From c02c47c7626e1a3f8442c24cb0722a766e26dc79 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 30 Sep 2024 22:08:45 +0200 Subject: [PATCH 01/39] chore: Adjust PR body --- .github/workflows/open_pull_request.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/open_pull_request.yml b/.github/workflows/open_pull_request.yml index 89207b5a3f..2afa0596cb 100644 --- a/.github/workflows/open_pull_request.yml +++ b/.github/workflows/open_pull_request.yml @@ -25,7 +25,8 @@ jobs: pr_body: | This pull request will ${{ env.MESSAGE }}. - ## Dependencies before merge + ## Before merging this PR - - [ ] https://github.com/revanced/revanced-integrations + - [ ] Remember about https://github.com/revanced/revanced-integrations + - [ ] Pull translations from Crowdin pr_draft: true From f5f2bad308a4ab9cacb055b2f02da87a0f2280f0 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 30 Sep 2024 22:34:23 +0200 Subject: [PATCH 02/39] ci: Adjust release commit message --- .releaserc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.releaserc b/.releaserc index 6193511b8e..ff81c99adf 100644 --- a/.releaserc +++ b/.releaserc @@ -21,11 +21,11 @@ "@semantic-release/git", { "assets": [ - "README.md", "CHANGELOG.md", "gradle.properties", "patches.json" - ] + ], + "message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" } ], [ From b81a551dc3e6e36fa3ca8b25b6115812f179ecc2 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 30 Sep 2024 23:21:43 +0200 Subject: [PATCH 03/39] build(Needs bump): Update dependencies --- package-lock.json | 321 ++++++++++++++++++++++++++-------------------- package.json | 4 +- 2 files changed, 182 insertions(+), 143 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a7023e559..c67622290d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,8 @@ "@saithodev/semantic-release-backmerge": "^4.0.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", - "gradle-semantic-release-plugin": "^1.9.2", - "semantic-release": "^24.0.0" + "gradle-semantic-release-plugin": "^1.10.1", + "semantic-release": "^24.1.2" } }, "node_modules/@babel/code-frame": { @@ -235,13 +235,13 @@ "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.3.tgz", - "integrity": "sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.5.tgz", + "integrity": "sha512-cgwIRtKrpwhLoBi0CUNuY83DPGRMaWVjqVI/bGKsLJ4PzyWZNaEmhHroI2xlrVXkk6nFv0IsZpOp+ZWSWUS2AQ==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/types": "^13.5.0" + "@octokit/types": "^13.6.0" }, "engines": { "node": ">= 18" @@ -251,9 +251,9 @@ } }, "node_modules/@octokit/plugin-retry": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.1.tgz", - "integrity": "sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.2.tgz", + "integrity": "sha512-XOWnPpH2kJ5VTwozsxGurw+svB2e61aWlmk5EVIYZPwFK5F9h4cyPyj9CIKRyMXMHSwpIsI3mPOdpMmrRhe7UQ==", "dev": true, "license": "MIT", "dependencies": { @@ -302,9 +302,9 @@ } }, "node_modules/@octokit/request-error": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.4.tgz", - "integrity": "sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.5.tgz", + "integrity": "sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -315,9 +315,9 @@ } }, "node_modules/@octokit/types": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz", - "integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==", + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.0.tgz", + "integrity": "sha512-CrooV/vKCXqwLa+osmHLIMUb87brpgUqlqkPGc6iE2wCkUvTrHiXFMhAKoDDaAAYJrtKtrFTgSQTg5nObBEaew==", "dev": true, "license": "MIT", "dependencies": { @@ -355,9 +355,9 @@ "license": "ISC" }, "node_modules/@pnpm/npm-conf": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", - "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", "dev": true, "license": "MIT", "dependencies": { @@ -977,6 +977,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/@saithodev/semantic-release-backmerge/node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -1372,9 +1385,9 @@ } }, "node_modules/@semantic-release/github": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.1.1.tgz", - "integrity": "sha512-sSmsBKGpAlTtXf9rUJf/si16p+FwPEsvsJRjl3KCwFP0WywaSpynvUhlYvE18n5rzkQNbGJnObAKIoo3xFMSjA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.0.tgz", + "integrity": "sha512-Uon6G6gJD8U1JNvPm7X0j46yxNRJ8Ui6SgK4Zw5Ktu8RgjEft3BGn+l/RX1TTzhhO3/uUcKuqM+/9/ETFxWS/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1399,7 +1412,7 @@ "node": ">=20.8.1" }, "peerDependencies": { - "semantic-release": ">=20.1.0" + "semantic-release": ">=24.1.0" } }, "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { @@ -1569,9 +1582,9 @@ } }, "node_modules/@semantic-release/npm/node_modules/execa": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.3.0.tgz", - "integrity": "sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.4.0.tgz", + "integrity": "sha512-yKHlle2YGxZE842MERVIplWwNH5VYmqqcPFgtnlU//K8gxuFFXu0pwd/CrfXTumFpeEiufsP7+opT/bPJa1yVw==", "dev": true, "license": "MIT", "dependencies": { @@ -1579,10 +1592,10 @@ "cross-spawn": "^7.0.3", "figures": "^6.1.0", "get-stream": "^9.0.0", - "human-signals": "^7.0.0", + "human-signals": "^8.0.0", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", - "npm-run-path": "^5.2.0", + "npm-run-path": "^6.0.0", "pretty-ms": "^9.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", @@ -1613,9 +1626,9 @@ } }, "node_modules/@semantic-release/npm/node_modules/human-signals": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-7.0.0.tgz", - "integrity": "sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", + "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1649,16 +1662,17 @@ } }, "node_modules/@semantic-release/npm/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^4.0.0" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1703,6 +1717,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@semantic-release/npm/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@semantic-release/release-notes-generator": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.1.tgz", @@ -2273,13 +2300,13 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2358,9 +2385,9 @@ "license": "MIT" }, "node_modules/env-ci": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.0.0.tgz", - "integrity": "sha512-apikxMgkipkgTvMdRT9MNqWx5VLOci79F4VBd7Op/7OPjjoanjdAvn6fglMCCEf/1bAh8eOiuEVCUs4V3qP3nQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.1.0.tgz", + "integrity": "sha512-Z8dnwSDbV1XYM9SBF2J0GcNVvmfmfh3a49qddGIROhBoVro6MZVTji15z/sJbQ2ko2ei8n988EU1wzoLU/tF+g==", "dev": true, "license": "MIT", "dependencies": { @@ -2549,9 +2576,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -2847,9 +2874,9 @@ "license": "ISC" }, "node_modules/gradle-semantic-release-plugin": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.9.2.tgz", - "integrity": "sha512-8qpf4GYFPQ+UMUymYBy/VchOOwLILAWzZMrZX1R0RR3JMgJBMN2R0tJn92R/3rXmxx4OAqwUFH6Np51eFoxr3w==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.10.1.tgz", + "integrity": "sha512-Q4dLAFICjPouUyRRHEKK8cXNB75nraXoioYZDZlVQOg4sYKudnTDZ3ohLmV3k4cPGiiMCh1ckXETkx9JnuyKmA==", "dev": true, "funding": [ { @@ -2925,16 +2952,16 @@ } }, "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.0.0.tgz", + "integrity": "sha512-4nw3vOVR+vHUOT8+U4giwe2tcGv+R3pwwRidUe67DoMBTjhrfr6rZYJVVwdkBE+Um050SG+X9tf0Jo4fOpn01w==", "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/http-proxy-agent": { @@ -2976,9 +3003,9 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -3191,9 +3218,9 @@ } }, "node_modules/is-unicode-supported": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", - "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { @@ -3497,9 +3524,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -3547,9 +3574,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -3610,6 +3637,19 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/normalize-url": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", @@ -3624,9 +3664,9 @@ } }, "node_modules/npm": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.2.tgz", - "integrity": "sha512-x/AIjFIKRllrhcb48dqUNAAZl0ig9+qMuN91RpZo3Cb2+zuibfh+KISl6+kVVyktDz230JKc208UkQwwMqyB+w==", + "version": "10.8.3", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.3.tgz", + "integrity": "sha512-0IQlyAYvVtQ7uOhDFYZCGK8kkut2nh8cpAdA9E6FvRSJaTgtZRZgNjlC5ZCct//L73ygrpY93CxXpRJDtNqPVg==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -3719,13 +3759,13 @@ "@sigstore/tuf": "^2.3.4", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^18.0.3", + "cacache": "^18.0.4", "chalk": "^5.3.0", "ci-info": "^4.0.0", "cli-columns": "^4.0.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.4.2", + "glob": "^10.4.5", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.2", "ini": "^4.1.3", @@ -3734,7 +3774,7 @@ "json-parse-even-better-errors": "^3.0.2", "libnpmaccess": "^8.0.6", "libnpmdiff": "^6.1.4", - "libnpmexec": "^8.1.3", + "libnpmexec": "^8.1.4", "libnpmfund": "^5.0.12", "libnpmhook": "^10.0.5", "libnpmorg": "^6.0.6", @@ -3748,12 +3788,12 @@ "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^10.1.0", + "node-gyp": "^10.2.0", "nopt": "^7.2.1", "normalize-package-data": "^6.0.2", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.3.0", - "npm-package-arg": "^11.0.2", + "npm-package-arg": "^11.0.3", "npm-pick-manifest": "^9.1.0", "npm-profile": "^10.0.0", "npm-registry-fetch": "^17.1.0", @@ -3764,7 +3804,7 @@ "proc-log": "^4.2.0", "qrcode-terminal": "^0.12.0", "read": "^3.0.1", - "semver": "^7.6.2", + "semver": "^7.6.3", "spdx-expression-parse": "^4.0.0", "ssri": "^10.0.6", "supports-color": "^9.4.0", @@ -4335,7 +4375,7 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "18.0.3", + "version": "18.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -4502,7 +4542,7 @@ } }, "node_modules/npm/node_modules/debug": { - "version": "4.3.5", + "version": "4.3.6", "dev": true, "inBundle": true, "license": "MIT", @@ -4586,7 +4626,7 @@ } }, "node_modules/npm/node_modules/foreground-child": { - "version": "3.2.1", + "version": "3.3.0", "dev": true, "inBundle": true, "license": "ISC", @@ -4614,7 +4654,7 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "10.4.2", + "version": "10.4.5", "dev": true, "inBundle": true, "license": "ISC", @@ -4629,9 +4669,6 @@ "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -4815,16 +4852,13 @@ "license": "ISC" }, "node_modules/npm/node_modules/jackspeak": { - "version": "3.4.0", + "version": "3.4.3", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -4910,7 +4944,7 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "8.1.3", + "version": "8.1.4", "dev": true, "inBundle": true, "license": "ISC", @@ -5044,13 +5078,10 @@ } }, "node_modules/npm/node_modules/lru-cache": { - "version": "10.2.2", + "version": "10.4.3", "dev": true, "inBundle": true, - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } + "license": "ISC" }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "13.0.1", @@ -5262,7 +5293,7 @@ } }, "node_modules/npm/node_modules/node-gyp": { - "version": "10.1.0", + "version": "10.2.0", "dev": true, "inBundle": true, "license": "MIT", @@ -5273,9 +5304,9 @@ "graceful-fs": "^4.2.6", "make-fetch-happen": "^13.0.0", "nopt": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.1.0", "semver": "^7.3.5", - "tar": "^6.1.2", + "tar": "^6.2.1", "which": "^4.0.0" }, "bin": { @@ -5285,15 +5316,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/proc-log": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm/node_modules/nopt": { "version": "7.2.1", "dev": true, @@ -5366,7 +5388,7 @@ } }, "node_modules/npm/node_modules/npm-package-arg": { - "version": "11.0.2", + "version": "11.0.3", "dev": true, "inBundle": true, "license": "ISC", @@ -5540,7 +5562,7 @@ } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.1.0", + "version": "6.1.2", "dev": true, "inBundle": true, "license": "MIT", @@ -5678,7 +5700,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.6.2", + "version": "7.6.3", "dev": true, "inBundle": true, "license": "ISC", @@ -6437,9 +6459,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true, "license": "ISC" }, @@ -6481,9 +6503,9 @@ } }, "node_modules/pretty-ms": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.0.0.tgz", - "integrity": "sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.1.0.tgz", + "integrity": "sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw==", "dev": true, "license": "MIT", "dependencies": { @@ -6738,15 +6760,15 @@ "license": "MIT" }, "node_modules/semantic-release": { - "version": "24.0.0", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.0.0.tgz", - "integrity": "sha512-v46CRPw+9eI3ZuYGF2oAjqPqsfbnfFTwLBgQsv/lch4goD09ytwOTESMN4QIrx/wPLxUGey60/NMx+ANQtWRsA==", + "version": "24.1.2", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.1.2.tgz", + "integrity": "sha512-hvEJ7yI97pzJuLsDZCYzJgmRxF8kiEJvNZhf0oiZQcexw+Ycjy4wbdsn/sVMURgNCu8rwbAXJdBRyIxM4pe32g==", "dev": true, "license": "MIT", "dependencies": { "@semantic-release/commit-analyzer": "^13.0.0-beta.1", "@semantic-release/error": "^4.0.0", - "@semantic-release/github": "^10.0.0", + "@semantic-release/github": "^11.0.0", "@semantic-release/npm": "^12.0.0", "@semantic-release/release-notes-generator": "^14.0.0-beta.1", "aggregate-error": "^5.0.0", @@ -6759,7 +6781,7 @@ "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^3.0.0", - "hosted-git-info": "^7.0.0", + "hosted-git-info": "^8.0.0", "import-from-esm": "^1.3.1", "lodash-es": "^4.17.21", "marked": "^12.0.0", @@ -6851,9 +6873,9 @@ } }, "node_modules/semantic-release/node_modules/execa": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.3.0.tgz", - "integrity": "sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.4.0.tgz", + "integrity": "sha512-yKHlle2YGxZE842MERVIplWwNH5VYmqqcPFgtnlU//K8gxuFFXu0pwd/CrfXTumFpeEiufsP7+opT/bPJa1yVw==", "dev": true, "license": "MIT", "dependencies": { @@ -6861,10 +6883,10 @@ "cross-spawn": "^7.0.3", "figures": "^6.1.0", "get-stream": "^9.0.0", - "human-signals": "^7.0.0", + "human-signals": "^8.0.0", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", - "npm-run-path": "^5.2.0", + "npm-run-path": "^6.0.0", "pretty-ms": "^9.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", @@ -6895,9 +6917,9 @@ } }, "node_modules/semantic-release/node_modules/human-signals": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-7.0.0.tgz", - "integrity": "sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", + "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -6931,16 +6953,17 @@ } }, "node_modules/semantic-release/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^4.0.0" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6998,6 +7021,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -7239,9 +7275,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", "dev": true, "license": "CC0-1.0" }, @@ -7365,9 +7401,9 @@ } }, "node_modules/supports-hyperlinks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", - "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz", + "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==", "dev": true, "license": "MIT", "dependencies": { @@ -7376,6 +7412,9 @@ }, "engines": { "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/temp-dir": { @@ -7530,9 +7569,9 @@ } }, "node_modules/type-fest": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.22.1.tgz", - "integrity": "sha512-9tHNEa0Ov81YOopiVkcCJVz5TM6AEQ+CHHjFIktqPnE3NV0AHIkx+gh9tiCl58m/66wWxkOC9eltpa75J4lQPA==", + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -7543,9 +7582,9 @@ } }, "node_modules/uglify-js": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.0.tgz", - "integrity": "sha512-wNKHUY2hYYkf6oSFfhwwiHo4WCHzHmzcXsqXYTN9ja3iApYIFbb2U6ics9hBcYLHcYGQoAlwnZlTrf3oF+BL/Q==", + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, "license": "BSD-2-Clause", "optional": true, diff --git a/package.json b/package.json index 5977269652..105a5ca879 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "@saithodev/semantic-release-backmerge": "^4.0.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", - "gradle-semantic-release-plugin": "^1.9.2", - "semantic-release": "^24.0.0" + "gradle-semantic-release-plugin": "^1.10.1", + "semantic-release": "^24.1.2" } } From 070388a42b2e7700a30cf07bc793664942642a17 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 30 Sep 2024 23:41:48 +0200 Subject: [PATCH 04/39] ci: Use permissions and regular GitHub token instead of PAT --- .github/workflows/pull_strings.yml | 4 +++- .github/workflows/push_strings.yml | 1 - .github/workflows/release.yml | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pull_strings.yml b/.github/workflows/pull_strings.yml index e1d931932d..dfed101ef3 100644 --- a/.github/workflows/pull_strings.yml +++ b/.github/workflows/pull_strings.yml @@ -8,6 +8,8 @@ on: jobs: pull: name: Pull strings + permissions: + contents: write runs-on: ubuntu-latest steps: - name: Checkout @@ -30,6 +32,6 @@ jobs: github_user_name: revanced-bot github_user_email: github@revanced.app env: - GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.github/workflows/push_strings.yml b/.github/workflows/push_strings.yml index 27c294cf70..a04af2499d 100644 --- a/.github/workflows/push_strings.yml +++ b/.github/workflows/push_strings.yml @@ -24,6 +24,5 @@ jobs: config: crowdin.yml upload_sources: true env: - GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8cf1d3a61e..b210aad5c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,9 @@ on: jobs: release: name: Release + permissions: + contents: write + packages: write runs-on: ubuntu-latest steps: - name: Checkout @@ -46,5 +49,5 @@ jobs: - name: Release env: - GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npm exec semantic-release From d56e2163b07c92d1304358557b19e92c420bbb8c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 1 Oct 2024 15:31:58 +0000 Subject: [PATCH 05/39] chore: Release v4.16.1-dev.1 [skip ci] ## [4.16.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.16.0...v4.16.1-dev.1) (2024-10-01) --- CHANGELOG.md | 2 ++ gradle.properties | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b182f5085..f1d64b0233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [4.16.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.16.0...v4.16.1-dev.1) (2024-10-01) + # [4.16.0](https://github.com/ReVanced/revanced-patches/compare/v4.15.0...v4.16.0) (2024-09-30) diff --git a/gradle.properties b/gradle.properties index a88d89983a..612cbab2a8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.16.0 +version = 4.16.1-dev.1 From 00a99dd13be6e5c44fa691d74c92b23ce6ba659d Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 2 Oct 2024 02:38:49 +0200 Subject: [PATCH 06/39] feat(YouTube - Hide Shorts components): Add option to hide like fountain (#3731) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> --- .../layout/hide/shorts/HideShortsComponentsResourcePatch.kt | 5 +++-- src/main/resources/addresources/values/strings.xml | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt index c3ce3a0ccb..9d3c8464ed 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt @@ -29,6 +29,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { // since this Setting menu currently uses the ordering used here. // Vertical row of buttons on right side of the screen. + SwitchPreference("revanced_hide_shorts_like_fountain"), SwitchPreference("revanced_hide_shorts_like_button"), SwitchPreference("revanced_hide_shorts_dislike_button"), SwitchPreference("revanced_hide_shorts_comments_button"), @@ -59,7 +60,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { context.xmlEditor["res/xml/main_shortcuts.xml"].use { editor -> val shortsItem = editor.file.childNodes.findElementByAttributeValueOrThrow( "android:shortcutId", - "shorts-shortcut" + "shorts-shortcut", ) shortsItem.parentNode.removeChild(shortsItem) @@ -70,7 +71,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { context.xmlEditor["res/layout/appwidget_two_rows.xml"].use { editor -> val shortsItem = editor.file.childNodes.findElementByAttributeValueOrThrow( "android:id", - "@id/button_shorts_container" + "@id/button_shorts_container", ) shortsItem.parentNode.removeChild(shortsItem) diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index f181a93d19..7ed20f9ee5 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -637,6 +637,9 @@ This is because Crowdin requires temporarily flattening this file and removing t Hide stickers Stickers are hidden Stickers are shown + Hide like fountain + Like button fountain animation is hidden + Like button fountain animation is shown Hide like button Like button is hidden Like button is shown From 8f3acbe8c2dbb1825e3724f6a9be8fcd256809cc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 2 Oct 2024 00:40:56 +0000 Subject: [PATCH 07/39] chore: Release v4.17.0-dev.1 [skip ci] # [4.17.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.16.1-dev.1...v4.17.0-dev.1) (2024-10-02) ### Features * **YouTube - Hide Shorts components:** Add option to hide like fountain ([#3731](https://github.com/ReVanced/revanced-patches/issues/3731)) ([00a99dd](https://github.com/ReVanced/revanced-patches/commit/00a99dd13be6e5c44fa691d74c92b23ce6ba659d)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1d64b0233..cc57541964 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.16.1-dev.1...v4.17.0-dev.1) (2024-10-02) + + +### Features + +* **YouTube - Hide Shorts components:** Add option to hide like fountain ([#3731](https://github.com/ReVanced/revanced-patches/issues/3731)) ([00a99dd](https://github.com/ReVanced/revanced-patches/commit/00a99dd13be6e5c44fa691d74c92b23ce6ba659d)) + ## [4.16.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.16.0...v4.16.1-dev.1) (2024-10-01) # [4.16.0](https://github.com/ReVanced/revanced-patches/compare/v4.15.0...v4.16.0) (2024-09-30) diff --git a/gradle.properties b/gradle.properties index 612cbab2a8..00d1621e1c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.16.1-dev.1 +version = 4.17.0-dev.1 From 1fe3a523e99ccfe556d88800686e34ac6ed77b2c Mon Sep 17 00:00:00 2001 From: 1fexd <58902674+1fexd@users.noreply.github.com> Date: Sun, 6 Oct 2024 01:19:39 +0200 Subject: [PATCH 08/39] feat(Willhaben): Add `Hide ads` patch (#3740) --- api/revanced-patches.api | 6 ++++ .../patches/willhaben/ads/HideAdsPatch.kt | 28 +++++++++++++++++++ .../ads/fingerprints/AdResolverFingerprint.kt | 17 +++++++++++ .../WHAdViewInjectorFingerprint.kt | 15 ++++++++++ 4 files changed, 66 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/AdResolverFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/WHAdViewInjectorFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index ad04ff075e..5ebfa2f71e 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1520,6 +1520,12 @@ public final class app/revanced/patches/warnwetter/misc/promocode/PromoCodeUnloc public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/willhaben/ads/HideAdsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/willhaben/ads/HideAdsPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/windyapp/misc/unlockpro/UnlockProPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/windyapp/misc/unlockpro/UnlockProPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V diff --git a/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt new file mode 100644 index 0000000000..2bf94f2c3e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.willhaben.ads + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.willhaben.ads.fingerprints.AdResolverFingerprint +import app.revanced.patches.willhaben.ads.fingerprints.WHAdViewInjectorFingerprint +import app.revanced.util.returnEarly + +@Patch( + name = "Hide ads", + description = "Hides all in-app ads.", + compatiblePackages = [CompatiblePackage("at.willhaben")] +) +@Suppress("unused") +object HideAdsPatch : BytecodePatch( + fingerprints = setOf( + AdResolverFingerprint, + WHAdViewInjectorFingerprint + ) +) { + override fun execute(context: BytecodeContext) { + arrayOf(AdResolverFingerprint, WHAdViewInjectorFingerprint).forEach { + it.returnEarly() + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/AdResolverFingerprint.kt b/src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/AdResolverFingerprint.kt new file mode 100644 index 0000000000..99b05db514 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/AdResolverFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.willhaben.ads.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object AdResolverFingerprint : MethodFingerprint( + "L", + parameters = listOf("L", "L"), + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + strings = listOf( + "Google Ad is invalid ", + "Google Native Ad is invalid ", + "Criteo Ad is invalid ", + "Amazon Ad is invalid " + ) +) diff --git a/src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/WHAdViewInjectorFingerprint.kt b/src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/WHAdViewInjectorFingerprint.kt new file mode 100644 index 0000000000..b3cb3e2345 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/willhaben/ads/fingerprints/WHAdViewInjectorFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.willhaben.ads.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object WHAdViewInjectorFingerprint : MethodFingerprint( + "V", + parameters = listOf("L", "L", "L", "Z"), + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + strings = listOf("successfulAdView"), + customFingerprint = { _, classDef -> + classDef.type == "Lat/willhaben/advertising/WHAdView;" + } +) From 4c5631e73ac211e15c6eb17a7459c9c8e8950226 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 5 Oct 2024 23:21:37 +0000 Subject: [PATCH 09/39] chore: Release v4.17.0-dev.2 [skip ci] # [4.17.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.1...v4.17.0-dev.2) (2024-10-05) ### Features * **Willhaben:** Add `Hide ads` patch ([#3740](https://github.com/ReVanced/revanced-patches/issues/3740)) ([1fe3a52](https://github.com/ReVanced/revanced-patches/commit/1fe3a523e99ccfe556d88800686e34ac6ed77b2c)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc57541964..4a1e8eace1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.1...v4.17.0-dev.2) (2024-10-05) + + +### Features + +* **Willhaben:** Add `Hide ads` patch ([#3740](https://github.com/ReVanced/revanced-patches/issues/3740)) ([1fe3a52](https://github.com/ReVanced/revanced-patches/commit/1fe3a523e99ccfe556d88800686e34ac6ed77b2c)) + # [4.17.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.16.1-dev.1...v4.17.0-dev.1) (2024-10-02) diff --git a/gradle.properties b/gradle.properties index 00d1621e1c..4be5ec5475 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.1 +version = 4.17.0-dev.2 From b8c89164cf3911ac3842df9b0d2ec42b52213505 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 5 Oct 2024 20:09:06 -0400 Subject: [PATCH 10/39] feat(YouTube - Hide layout components): Add option to hide Yoodles (YouTube Doodles) (#3743) Co-authored-by: oSumAtrIX --- api/revanced-patches.api | 1 + .../hide/general/HideLayoutComponentsPatch.kt | 36 ++++++++++++++++++- .../HideLayoutComponentsResourcePatch.kt | 7 ++++ .../YoodlesImageViewFingerprint.kt | 13 +++++++ .../kotlin/app/revanced/util/BytecodeUtils.kt | 13 +++++-- .../resources/addresources/values/strings.xml | 8 +++++ 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 5ebfa2f71e..d5a47720a9 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -2184,6 +2184,7 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List; + public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List; public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException; public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index a505497b13..4f2e832d8f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -18,13 +18,18 @@ import app.revanced.patches.youtube.layout.hide.general.fingerprints.HideShowMor import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverlayFingerprint import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint +import app.revanced.patches.youtube.layout.hide.general.fingerprints.YoodlesImageViewFingerprint import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.findOpcodeIndicesReversed +import app.revanced.util.getReference import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Hide layout components", @@ -70,7 +75,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction ) @Suppress("unused") object HideLayoutComponentsPatch : BytecodePatch( - setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint, HideShowMoreButtonFingerprint), + setOf( + ParseElementFromBufferFingerprint, + PlayerOverlayFingerprint, + HideShowMoreButtonFingerprint, + YoodlesImageViewFingerprint, + ), ) { private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;" @@ -128,6 +138,7 @@ object HideLayoutComponentsPatch : BytecodePatch( SwitchPreference("revanced_hide_search_result_recommendations"), SwitchPreference("revanced_hide_search_result_shelf_header"), SwitchPreference("revanced_hide_show_more_button"), + SwitchPreference("revanced_hide_yoodles"), PreferenceScreen( key = "revanced_hide_keyword_content_screen", sorting = Sorting.UNSORTED, @@ -226,5 +237,28 @@ object HideLayoutComponentsPatch : BytecodePatch( } // endregion + + // region 'Yoodles' + + YoodlesImageViewFingerprint.resultOrThrow().mutableMethod.apply { + findOpcodeIndicesReversed{ + opcode == Opcode.INVOKE_VIRTUAL + && getReference()?.name == "setImageDrawable" + }.forEach { insertIndex -> + val register = getInstruction(insertIndex).registerD + + addInstructionsWithLabels( + insertIndex, + """ + invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideYoodles(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable; + move-result-object v$register + if-eqz v$register, :hide + """, + ExternalLabel("hide", getInstruction(insertIndex + 1)), + ) + } + } + + // endregion } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt index c7b60d544e..24dcbb3f19 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt @@ -17,10 +17,17 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch internal object HideLayoutComponentsResourcePatch : ResourcePatch() { internal var expandButtonDownId: Long = -1 + var youTubeLogo = -1L + override fun execute(context: ResourceContext) { expandButtonDownId = ResourceMappingPatch[ "layout", "expand_button_down", ] + + youTubeLogo = ResourceMappingPatch[ + "id", + "youtube_logo" + ] } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt new file mode 100644 index 0000000000..092b5110b4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.layout.hide.general.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.youtube.layout.hide.general.HideLayoutComponentsResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object YoodlesImageViewFingerprint : LiteralValueFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L", "L"), + returnType = "Landroid/view/View;", + literalSupplier = { HideLayoutComponentsResourcePatch.youTubeLogo } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index d22bfbdbe0..98ec71428e 100644 --- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -224,18 +224,25 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instru /** * @return The list of indices of the opcode in reverse order. */ -fun Method.findOpcodeIndicesReversed(opcode: Opcode): List { +fun Method.findOpcodeIndicesReversed(opcode: Opcode): List = + findOpcodeIndicesReversed { this.opcode == opcode } + +/** + * @return The list of indices of the opcode in reverse order. + */ +fun Method.findOpcodeIndicesReversed(filter: Instruction.() -> Boolean): List { val indexes = implementation!!.instructions .withIndex() - .filter { (_, instruction) -> instruction.opcode == opcode } + .filter { (_, instruction) -> filter(instruction) } .map { (index, _) -> index } .reversed() - if (indexes.isEmpty()) throw PatchException("No ${opcode.name} instructions found in: $this") + if (indexes.isEmpty()) throw PatchException("No matching instructions found in: $this") return indexes } + /** * Return the resolved method early. */ diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 7ed20f9ee5..645f24cc34 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -231,6 +231,13 @@ This is because Crowdin requires temporarily flattening this file and removing t Transcript section is shown Video description Hide or show video description components + + + Hide Yoodles (YouTube Doodles) + Search bar Yoodles are hidden + Search bar Yoodles will be periodically shown + YouTube Yoodles show up a few days each year.\n\nIf a Yoodle is currently showing in your region and this hide setting is on, then the filter bar below the search bar will also be hidden. + Custom filter Hide components using custom filters Enable custom filter @@ -240,6 +247,7 @@ This is because Crowdin requires temporarily flattening this file and removing t List of component path builder strings to filter separated by new line Invalid custom filter: %s + Hide keyword content Hide search and feed videos using keyword filters Hide home videos by keywords From a20f8d5d8b9208412e4f6150e90de26ba1da7fa2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 6 Oct 2024 00:11:05 +0000 Subject: [PATCH 11/39] chore: Release v4.17.0-dev.3 [skip ci] # [4.17.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.2...v4.17.0-dev.3) (2024-10-06) ### Features * **YouTube - Hide layout components:** Add option to hide Yoodles (YouTube Doodles) ([#3743](https://github.com/ReVanced/revanced-patches/issues/3743)) ([b8c8916](https://github.com/ReVanced/revanced-patches/commit/b8c89164cf3911ac3842df9b0d2ec42b52213505)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a1e8eace1..24e477a985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.2...v4.17.0-dev.3) (2024-10-06) + + +### Features + +* **YouTube - Hide layout components:** Add option to hide Yoodles (YouTube Doodles) ([#3743](https://github.com/ReVanced/revanced-patches/issues/3743)) ([b8c8916](https://github.com/ReVanced/revanced-patches/commit/b8c89164cf3911ac3842df9b0d2ec42b52213505)) + # [4.17.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.1...v4.17.0-dev.2) (2024-10-05) diff --git a/gradle.properties b/gradle.properties index 4be5ec5475..8f77a0fa95 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.2 +version = 4.17.0-dev.3 From 13998bbf95ac3cde8bf24754d60258d0ff9bc4f4 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 6 Oct 2024 18:55:20 -0400 Subject: [PATCH 12/39] fix(YouTube - Hide layout components): Adjust settings text (#3745) --- .../layout/hide/general/HideLayoutComponentsPatch.kt | 2 +- src/main/resources/addresources/values/strings.xml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index 4f2e832d8f..9a99f3ef5c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -138,7 +138,7 @@ object HideLayoutComponentsPatch : BytecodePatch( SwitchPreference("revanced_hide_search_result_recommendations"), SwitchPreference("revanced_hide_search_result_shelf_header"), SwitchPreference("revanced_hide_show_more_button"), - SwitchPreference("revanced_hide_yoodles"), + SwitchPreference("revanced_hide_doodles"), PreferenceScreen( key = "revanced_hide_keyword_content_screen", sorting = Sorting.UNSORTED, diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 645f24cc34..ae7dd0af91 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -232,11 +232,11 @@ This is because Crowdin requires temporarily flattening this file and removing t Video description Hide or show video description components - - Hide Yoodles (YouTube Doodles) - Search bar Yoodles are hidden - Search bar Yoodles will be periodically shown - YouTube Yoodles show up a few days each year.\n\nIf a Yoodle is currently showing in your region and this hide setting is on, then the filter bar below the search bar will also be hidden. + + Hide YouTube Doodles + Search bar Doodles are hidden + Search bar Doodles are shown + YouTube Doodles show up a few days each year.\n\nIf a Doodle is currently showing in your region and this hide setting is on, then the filter bar below the search bar will also be hidden. Custom filter Hide components using custom filters From 1498ca0dd64df1019847688895ff2ddd1135681c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 6 Oct 2024 22:57:38 +0000 Subject: [PATCH 13/39] chore: Release v4.17.0-dev.4 [skip ci] # [4.17.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.3...v4.17.0-dev.4) (2024-10-06) ### Bug Fixes * **YouTube - Hide layout components:** Adjust settings text ([#3745](https://github.com/ReVanced/revanced-patches/issues/3745)) ([13998bb](https://github.com/ReVanced/revanced-patches/commit/13998bbf95ac3cde8bf24754d60258d0ff9bc4f4)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24e477a985..01b98ffdd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.3...v4.17.0-dev.4) (2024-10-06) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Adjust settings text ([#3745](https://github.com/ReVanced/revanced-patches/issues/3745)) ([13998bb](https://github.com/ReVanced/revanced-patches/commit/13998bbf95ac3cde8bf24754d60258d0ff9bc4f4)) + # [4.17.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.2...v4.17.0-dev.3) (2024-10-06) diff --git a/gradle.properties b/gradle.properties index 8f77a0fa95..5bd37b1807 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.3 +version = 4.17.0-dev.4 From a62b50691c49d1ce529a7c9c4e49da0d0dd46df2 Mon Sep 17 00:00:00 2001 From: KAZI MMT <82371061+kazimmt@users.noreply.github.com> Date: Tue, 8 Oct 2024 02:56:31 +0600 Subject: [PATCH 14/39] feat(Backdrops - Pro unlock): Support latest versions by removing version constraint --- .../app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt index d6351172f0..245ed0ee93 100644 --- a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt +++ b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt @@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Pro unlock", - compatiblePackages = [CompatiblePackage("com.backdrops.wallpapers", ["4.52"])] + compatiblePackages = [CompatiblePackage("com.backdrops.wallpapers")] ) @Suppress("unused") object ProUnlockPatch : BytecodePatch( @@ -34,4 +34,4 @@ object ProUnlockPatch : BytecodePatch( } ?: throw ProUnlockFingerprint.exception } -} \ No newline at end of file +} From 68beb7d39ac0af54494f41611de52ddf60ac648f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 7 Oct 2024 20:58:34 +0000 Subject: [PATCH 15/39] chore: Release v4.17.0-dev.5 [skip ci] # [4.17.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.4...v4.17.0-dev.5) (2024-10-07) ### Features * **Backdrops - Pro unlock:** Support latest versions by removing version constraint ([a62b506](https://github.com/ReVanced/revanced-patches/commit/a62b50691c49d1ce529a7c9c4e49da0d0dd46df2)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b98ffdd1..bf39889e4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.4...v4.17.0-dev.5) (2024-10-07) + + +### Features + +* **Backdrops - Pro unlock:** Support latest versions by removing version constraint ([a62b506](https://github.com/ReVanced/revanced-patches/commit/a62b50691c49d1ce529a7c9c4e49da0d0dd46df2)) + # [4.17.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.3...v4.17.0-dev.4) (2024-10-06) diff --git a/gradle.properties b/gradle.properties index 5bd37b1807..7a714c4d1e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.4 +version = 4.17.0-dev.5 From f71c4068bc646d02954b59fac4756f1419c55dbe Mon Sep 17 00:00:00 2001 From: MarcaD <152095496+MarcaDian@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:10:53 +0300 Subject: [PATCH 16/39] feat(YouTube - Hide Shorts components): Add option to hide `Use template`, `Upcoming`, `Green screen` buttons (#3752) --- .../shorts/HideShortsComponentsResourcePatch.kt | 3 +++ src/main/resources/addresources/values/strings.xml | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt index 9d3c8464ed..866d8fb19b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt @@ -42,6 +42,9 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { SwitchPreference("revanced_hide_shorts_subscribe_button"), SwitchPreference("revanced_hide_shorts_paused_overlay_buttons"), SwitchPreference("revanced_hide_shorts_save_sound_button"), + SwitchPreference("revanced_hide_shorts_use_template_button"), + SwitchPreference("revanced_hide_shorts_upcoming_button"), + SwitchPreference("revanced_hide_shorts_green_screen_button"), SwitchPreference("revanced_hide_shorts_shop_button"), SwitchPreference("revanced_hide_shorts_tagged_products"), SwitchPreference("revanced_hide_shorts_stickers"), diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index ae7dd0af91..c1625a4e26 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -637,8 +637,17 @@ This is because Crowdin requires temporarily flattening this file and removing t Location label is hidden Location label is shown Hide save music button - Save music is hidden - Save music is shown + Save music button is hidden + Save music button is shown + Hide use template button + Use template button is hidden + Use template button is shown + Hide upcoming button + Upcoming button is hidden + Upcoming button is shown + Hide green screen button + Green screen button is hidden + Green screen button is shown Hide search suggestions Search suggestions are hidden Search suggestions are shown From b4c3dac77ff6b256c806335848d346f1851dc54a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 14 Oct 2024 12:13:04 +0000 Subject: [PATCH 17/39] chore: Release v4.17.0-dev.6 [skip ci] # [4.17.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.5...v4.17.0-dev.6) (2024-10-14) ### Features * **YouTube - Hide Shorts components:** Add option to hide `Use template`, `Upcoming`, `Green screen` buttons ([#3752](https://github.com/ReVanced/revanced-patches/issues/3752)) ([f71c406](https://github.com/ReVanced/revanced-patches/commit/f71c4068bc646d02954b59fac4756f1419c55dbe)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf39889e4c..19c4379b48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.5...v4.17.0-dev.6) (2024-10-14) + + +### Features + +* **YouTube - Hide Shorts components:** Add option to hide `Use template`, `Upcoming`, `Green screen` buttons ([#3752](https://github.com/ReVanced/revanced-patches/issues/3752)) ([f71c406](https://github.com/ReVanced/revanced-patches/commit/f71c4068bc646d02954b59fac4756f1419c55dbe)) + # [4.17.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.4...v4.17.0-dev.5) (2024-10-07) diff --git a/gradle.properties b/gradle.properties index 7a714c4d1e..26525c40ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.5 +version = 4.17.0-dev.6 From 5150a15ad4ca73a747f0a89f933db7f2d686ec2d Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 17 Oct 2024 17:16:45 +0200 Subject: [PATCH 18/39] fix(YouTube - Spoof video streams): Fix playback for Android VR by removing invalid body as well (#3769) --- .../youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt index b378307622..ffb7aaf675 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt @@ -254,7 +254,9 @@ object SpoofVideoStreamsPatch : BytecodePatch( // endregion // region Remove /videoplayback request body to fix playback. - // This is needed when using iOS client as streaming data source. + // It is assumed, YouTube makes a request with a body tuned for Android. + // Requesting streams intended for other platforms with a body tuned for Android could be the cause of 400 errors. + // A proper fix may include modifying the request body to match the platforms expected body. BuildMediaDataSourceFingerprint.resultOrThrow().let { it.mutableMethod.apply { From 5189122006b0f72d5bfb50422021c3b0f3a9ae4a Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 17 Oct 2024 19:18:48 +0400 Subject: [PATCH 19/39] fix(Twitter - Unlock downloads): Make it work with latest versions (#3782) --- .../downloads/fingerprints/BuildMediaOptionsSheetFingerprint.kt | 2 +- .../ShowDownloadVideoUpsellBottomSheetFingerprint.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/BuildMediaOptionsSheetFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/BuildMediaOptionsSheetFingerprint.kt index 83d1732592..1e96c2bdae 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/BuildMediaOptionsSheetFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/BuildMediaOptionsSheetFingerprint.kt @@ -10,5 +10,5 @@ internal object BuildMediaOptionsSheetFingerprint : MethodFingerprint( Opcode.GOTO_16, Opcode.NEW_INSTANCE, ), - strings = listOf("resources.getString(R.string.post_video)"), + strings = listOf("mediaEntity", "media_options_sheet"), ) diff --git a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt index 1257d0f58e..257e043d15 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt @@ -5,6 +5,6 @@ import com.android.tools.smali.dexlib2.Opcode internal object ShowDownloadVideoUpsellBottomSheetFingerprint : MethodFingerprint( returnType = "Z", - strings = listOf("variantToDownload.url"), + strings = listOf("mediaEntity", "url"), opcodes = listOf(Opcode.IF_EQZ) ) From 979ad6f583820c5a79d4fc1094a8fe3b831a65cd Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 17 Oct 2024 15:21:25 +0000 Subject: [PATCH 20/39] chore: Release v4.17.0-dev.7 [skip ci] # [4.17.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.6...v4.17.0-dev.7) (2024-10-17) ### Bug Fixes * **Twitter - Unlock downloads:** Make it work with latest versions ([#3782](https://github.com/ReVanced/revanced-patches/issues/3782)) ([5189122](https://github.com/ReVanced/revanced-patches/commit/5189122006b0f72d5bfb50422021c3b0f3a9ae4a)) * **YouTube - Spoof video streams:** Fix playback for Android VR by removing invalid body as well ([#3769](https://github.com/ReVanced/revanced-patches/issues/3769)) ([5150a15](https://github.com/ReVanced/revanced-patches/commit/5150a15ad4ca73a747f0a89f933db7f2d686ec2d)) --- CHANGELOG.md | 8 ++++++++ gradle.properties | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19c4379b48..55611f5f02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [4.17.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.6...v4.17.0-dev.7) (2024-10-17) + + +### Bug Fixes + +* **Twitter - Unlock downloads:** Make it work with latest versions ([#3782](https://github.com/ReVanced/revanced-patches/issues/3782)) ([5189122](https://github.com/ReVanced/revanced-patches/commit/5189122006b0f72d5bfb50422021c3b0f3a9ae4a)) +* **YouTube - Spoof video streams:** Fix playback for Android VR by removing invalid body as well ([#3769](https://github.com/ReVanced/revanced-patches/issues/3769)) ([5150a15](https://github.com/ReVanced/revanced-patches/commit/5150a15ad4ca73a747f0a89f933db7f2d686ec2d)) + # [4.17.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.5...v4.17.0-dev.6) (2024-10-14) diff --git a/gradle.properties b/gradle.properties index 26525c40ff..2195458463 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.6 +version = 4.17.0-dev.7 From 9269a076b674ecdcf478bca842238f6e30869f44 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 17 Oct 2024 19:24:06 +0400 Subject: [PATCH 21/39] feat(Twitter): Add `Change link sharing domain` patch (#3753) Co-authored-by: oSumAtrIX --- api/revanced-patches.api | 6 ++ .../links/ChangeLinkSharingDomainPatch.kt | 93 +++++++++++++++++++ .../fingerprints/LinkBuilderFingerprint.kt | 8 ++ .../LinkResourceGetterFingerprint.kt | 12 +++ .../LinkSharingDomainFingerprint.kt | 7 ++ 5 files changed, 126 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkBuilderFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkResourceGetterFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkSharingDomainFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index d5a47720a9..74523ce8c9 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1490,6 +1490,12 @@ public final class app/revanced/patches/twitter/misc/hook/patch/recommendation/H public static final field INSTANCE Lapp/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch; } +public final class app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/twitter/misc/links/OpenLinksWithAppChooserPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/twitter/misc/links/OpenLinksWithAppChooserPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt new file mode 100644 index 0000000000..06597dd81d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt @@ -0,0 +1,93 @@ +package app.revanced.patches.twitter.misc.links + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption +import app.revanced.patches.twitter.misc.links.fingerprints.LinkBuilderFingerprint +import app.revanced.patches.twitter.misc.links.fingerprints.LinkResourceGetterFingerprint +import app.revanced.patches.twitter.misc.links.fingerprints.LinkSharingDomainFingerprint +import app.revanced.util.exception +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c +import com.android.tools.smali.dexlib2.iface.reference.StringReference + +@Patch( + name = "Change link sharing domain", + description = "Replaces the domain name of Twitter links when sharing them.", + compatiblePackages = [CompatiblePackage("com.twitter.android")], +) +@Suppress("unused") +object ChangeLinkSharingDomainPatch : BytecodePatch( + setOf( + LinkBuilderFingerprint, + LinkResourceGetterFingerprint, + LinkSharingDomainFingerprint, + ), +) { + private var domainName by stringPatchOption( + key = "domainName", + default = "fxtwitter.com", + title = "Domain name", + description = "The domain name to use when sharing links.", + required = true, + ) + + // This method is used to build the link that is shared when the "Share via..." button is pressed. + private const val FORMAT_METHOD_RESOURCE_REFERENCE = + "Lapp/revanced/integrations/twitter/patches/links/ChangeLinkSharingDomainPatch;->" + + "formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;" + + // This method is used to build the link that is shared when the "Copy link" button is pressed. + private const val FORMAT_METHOD_REFERENCE = + "Lapp/revanced/integrations/twitter/patches/links/ChangeLinkSharingDomainPatch;->" + + "formatLink(JLjava/lang/String;)Ljava/lang/String;" + + override fun execute(context: BytecodeContext) { + LinkSharingDomainFingerprint.result?.let { + val replacementIndex = it.scanResult.stringsScanResult!!.matches.first().index + val domainRegister = it.mutableMethod.getInstruction(replacementIndex).registerA + it.mutableMethod.replaceInstruction( + replacementIndex, + "const-string v$domainRegister, \"https://$domainName\"", + ) + } ?: throw LinkSharingDomainFingerprint.exception + + // Replace the domain name when copying a link with "Copy link" button. + LinkBuilderFingerprint.result?.let { + it.mutableMethod.apply { + addInstructions( + 0, + """ + invoke-static { p0, p1, p2 }, $FORMAT_METHOD_REFERENCE + move-result-object p0 + return-object p0 + """, + ) + } + } ?: throw LinkBuilderFingerprint.exception + + // Used in the Share via... dialog. + LinkResourceGetterFingerprint.result?.mutableMethod?.apply { + val constWithParameterName = indexOfFirstInstructionOrThrow { + getReference()?.string?.contains("id.toString()") == true + } + + // Format the link with the new domain name register (2 instructions above the const-string). + val formatLinkCallIndex = constWithParameterName - 2 + val formatLinkCall = getInstruction(formatLinkCallIndex) + + // Replace the original method call with the new method call. + replaceInstruction( + formatLinkCallIndex, + "invoke-static { v${formatLinkCall.registerE} }, $FORMAT_METHOD_RESOURCE_REFERENCE", + ) + } ?: throw LinkResourceGetterFingerprint.exception + } +} diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkBuilderFingerprint.kt new file mode 100644 index 0000000000..0df584cf2c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkBuilderFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.twitter.misc.links.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +// Returns a shareable link string based on a tweet ID and a username. +internal object LinkBuilderFingerprint : MethodFingerprint( + strings = listOf("/%1\$s/status/%2\$d"), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkResourceGetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkResourceGetterFingerprint.kt new file mode 100644 index 0000000000..a84181f62c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkResourceGetterFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.twitter.misc.links.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +// Gets Resource string for share link view available by pressing "Share via" button. +internal object LinkResourceGetterFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Landroid/content/res/Resources;"), + strings = listOf("res.getString(R.string.t…lUsername, id.toString())"), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkSharingDomainFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkSharingDomainFingerprint.kt new file mode 100644 index 0000000000..e4b1a7f300 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/links/fingerprints/LinkSharingDomainFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.twitter.misc.links.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object LinkSharingDomainFingerprint : MethodFingerprint( + strings = listOf("https://fxtwitter.com"), +) \ No newline at end of file From 085db408dfa183761989bd653aebfc8d4fff230a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 17 Oct 2024 15:26:18 +0000 Subject: [PATCH 22/39] chore: Release v4.17.0-dev.8 [skip ci] # [4.17.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.7...v4.17.0-dev.8) (2024-10-17) ### Features * **Twitter:** Add `Change link sharing domain` patch ([#3753](https://github.com/ReVanced/revanced-patches/issues/3753)) ([9269a07](https://github.com/ReVanced/revanced-patches/commit/9269a076b674ecdcf478bca842238f6e30869f44)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55611f5f02..c6a7714c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.7...v4.17.0-dev.8) (2024-10-17) + + +### Features + +* **Twitter:** Add `Change link sharing domain` patch ([#3753](https://github.com/ReVanced/revanced-patches/issues/3753)) ([9269a07](https://github.com/ReVanced/revanced-patches/commit/9269a076b674ecdcf478bca842238f6e30869f44)) + # [4.17.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.6...v4.17.0-dev.7) (2024-10-17) diff --git a/gradle.properties b/gradle.properties index 2195458463..2ff56b5d3c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.7 +version = 4.17.0-dev.8 From a47ee38b1cdd974a959008006ecaf58917addc60 Mon Sep 17 00:00:00 2001 From: 1fexd <58902674+1fexd@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:28:30 +0200 Subject: [PATCH 23/39] feat(Sync for Reddit): Add `Fix video downloads` patch (#3739) Co-authored-by: oSumAtrIX --- api/revanced-patches.api | 6 ++ .../fix/video/FixVideoDownloadsPatch.kt | 62 +++++++++++++++++++ ...seRedditVideoNetworkResponseFingerprint.kt | 16 +++++ 3 files changed, 84 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/fingerprints/ParseRedditVideoNetworkResponseFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 74523ce8c9..49822b6f92 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -840,6 +840,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/u public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch; } diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt new file mode 100644 index 0000000000..b228025c89 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt @@ -0,0 +1,62 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.fix.video + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.reddit.customclients.syncforreddit.fix.video.fingerprints.ParseRedditVideoNetworkResponseFingerprint +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c + +@Patch( + name = "Fix video downloads", + description = "Fixes a bug in Sync's MPD parser resulting in only the audio-track being saved.", + compatiblePackages = [ + CompatiblePackage("com.laurencedawson.reddit_sync"), + CompatiblePackage("com.laurencedawson.reddit_sync.pro"), + CompatiblePackage("com.laurencedawson.reddit_sync.dev"), + ], + requiresIntegrations = true, +) +@Suppress("unused") +object FixVideoDownloadsPatch : BytecodePatch( + fingerprints = setOf(ParseRedditVideoNetworkResponseFingerprint), +) { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/syncforreddit/FixRedditVideoDownloadPatch;" + private const val GET_LINKS_METHOD = "getLinks([B)[Ljava/lang/String;" + + override fun execute(context: BytecodeContext) { + ParseRedditVideoNetworkResponseFingerprint.resultOrThrow().let { + val scanResult = it.scanResult.patternScanResult!! + val newInstanceIndex = scanResult.startIndex + val invokeDirectIndex = scanResult.endIndex - 1 + + val buildResponseInstruction = it.mutableMethod.getInstruction(invokeDirectIndex) + + it.mutableMethod.addInstructions( + newInstanceIndex + 1, + """ + # Get byte array from response. + iget-object v2, p1, Lcom/android/volley/NetworkResponse;->data:[B + + # Parse the videoUrl and audioUrl from the byte array. + invoke-static { v2 }, $INTEGRATIONS_CLASS_DESCRIPTOR->$GET_LINKS_METHOD + move-result-object v2 + + # Get videoUrl (Index 0). + const/4 v5, 0x0 + aget-object v${buildResponseInstruction.registerE}, v2, v5 + + # Get audioUrl (Index 1). + const/4 v6, 0x1 + aget-object v${buildResponseInstruction.registerF}, v2, v6 + + # Register E and F are used to build the response. + """, + ) + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/fingerprints/ParseRedditVideoNetworkResponseFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/fingerprints/ParseRedditVideoNetworkResponseFingerprint.kt new file mode 100644 index 0000000000..1a06cd54d6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/fingerprints/ParseRedditVideoNetworkResponseFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.fix.video.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object ParseRedditVideoNetworkResponseFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.NEW_INSTANCE, + Opcode.IGET_OBJECT, + Opcode.INVOKE_DIRECT, + Opcode.CONST_WIDE_32 + ), + customFingerprint = { methodDef, classDef -> + classDef.sourceFile == "RedditVideoRequest.java" && methodDef.name == "parseNetworkResponse" + } +) From 26a04b36a11e806cb824cd7f244d401a31f48d79 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 17 Oct 2024 15:30:41 +0000 Subject: [PATCH 24/39] chore: Release v4.17.0-dev.9 [skip ci] # [4.17.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.8...v4.17.0-dev.9) (2024-10-17) ### Features * **Sync for Reddit:** Add `Fix video downloads` patch ([#3739](https://github.com/ReVanced/revanced-patches/issues/3739)) ([a47ee38](https://github.com/ReVanced/revanced-patches/commit/a47ee38b1cdd974a959008006ecaf58917addc60)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6a7714c9b..ff92f0c66e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.8...v4.17.0-dev.9) (2024-10-17) + + +### Features + +* **Sync for Reddit:** Add `Fix video downloads` patch ([#3739](https://github.com/ReVanced/revanced-patches/issues/3739)) ([a47ee38](https://github.com/ReVanced/revanced-patches/commit/a47ee38b1cdd974a959008006ecaf58917addc60)) + # [4.17.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.7...v4.17.0-dev.8) (2024-10-17) diff --git a/gradle.properties b/gradle.properties index 2ff56b5d3c..5a62a4b223 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.8 +version = 4.17.0-dev.9 From 214c72baeb7f87f21cd2ca34301ab11fa0ff1a4f Mon Sep 17 00:00:00 2001 From: PantlessCoding <101957999+PantlessCoding@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:36:35 -0400 Subject: [PATCH 25/39] feat(Facebook): Add `Hide sponsored stories` patch (#3627) Co-authored-by: oSumAtrIX --- api/revanced-patches.api | 6 ++ .../ads/mainfeed/HideSponsoredStoriesPatch.kt | 96 +++++++++++++++++++ .../BaseModelMapperFingerprint.kt | 21 ++++ ...etSponsoredDataModelTemplateFingerprint.kt | 23 +++++ .../GetStoryVisibilityFingerprint.kt | 23 +++++ 5 files changed, 169 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/BaseModelMapperFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetSponsoredDataModelTemplateFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetStoryVisibilityFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 49822b6f92..5ca19d08bf 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -263,6 +263,12 @@ public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatch : ap public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/facebook/ads/story/HideStoryAdsPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/facebook/ads/story/HideStoryAdsPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt new file mode 100644 index 0000000000..82b0bcd0a5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt @@ -0,0 +1,96 @@ +package app.revanced.patches.facebook.ads.mainfeed + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.facebook.ads.mainfeed.fingerprints.BaseModelMapperFingerprint +import app.revanced.patches.facebook.ads.mainfeed.fingerprints.GetSponsoredDataModelTemplateFingerprint +import app.revanced.patches.facebook.ads.mainfeed.fingerprints.GetStoryVisibilityFingerprint +import app.revanced.util.exception +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i +import com.android.tools.smali.dexlib2.immutable.ImmutableMethod +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter + +@Patch( + name = "Hide 'Sponsored Stories'", + compatiblePackages = [CompatiblePackage("com.facebook.katana")], +) +@Suppress("unused") +object HideSponsoredStoriesPatch : BytecodePatch( + setOf(GetStoryVisibilityFingerprint, GetSponsoredDataModelTemplateFingerprint, BaseModelMapperFingerprint), +) { + private const val GRAPHQL_STORY_TYPE = "Lcom/facebook/graphql/model/GraphQLStory;" + + override fun execute(context: BytecodeContext) { + GetStoryVisibilityFingerprint.result?.apply { + val sponsoredDataModelTemplateMethod = GetSponsoredDataModelTemplateFingerprint.resultOrThrow().method + val baseModelMapperMethod = BaseModelMapperFingerprint.resultOrThrow().method + val baseModelWithTreeType = baseModelMapperMethod.returnType + + // The "SponsoredDataModelTemplate" methods has the ids in its body to extract sponsored data + // from GraphQL models, but targets the wrong derived type of "BaseModelWithTree". Since those ids + // could change in future version, we need to extract them and call the base implementation directly. + val getSponsoredDataHelperMethod = ImmutableMethod( + classDef.type, + "getSponsoredData", + listOf(ImmutableMethodParameter(GRAPHQL_STORY_TYPE, null, null)), + baseModelWithTreeType, + AccessFlags.PRIVATE or AccessFlags.STATIC, + null, + null, + MutableMethodImplementation(4), + ).toMutable().apply { + // Extract the ids of the original method. These ids seem to correspond to model types for + // GraphQL data structure. They are then fed to a method of BaseModelWithTree that populate + // and cast the requested GraphQL subtype. The Ids are found in the two first "CONST" instructions. + val constInstructions = sponsoredDataModelTemplateMethod.implementation!!.instructions + .asSequence() + .filterIsInstance() + .take(2) + .toList() + + val storyTypeId = constInstructions[0].narrowLiteral + val sponsoredDataTypeId = constInstructions[1].narrowLiteral + + addInstructions( + """ + const-class v2, $baseModelWithTreeType + const v1, $storyTypeId + const v0, $sponsoredDataTypeId + invoke-virtual {p0, v2, v1, v0}, $baseModelMapperMethod + move-result-object v0 + check-cast v0, $baseModelWithTreeType + return-object v0 + """, + ) + } + + mutableClass.methods.add(getSponsoredDataHelperMethod) + + // Check if the parameter type is GraphQLStory and if sponsoredDataModelGetter returns a non-null value. + // If so, hide the story by setting the visibility to StoryVisibility.GONE. + mutableMethod.addInstructionsWithLabels( + scanResult.patternScanResult!!.startIndex, + """ + instance-of v0, p0, $GRAPHQL_STORY_TYPE + if-eqz v0, :resume_normal + invoke-static {p0}, $getSponsoredDataHelperMethod + move-result-object v0 + if-eqz v0, :resume_normal + const-string v0, "GONE" + return-object v0 + :resume_normal + nop + """, + ) + } ?: throw GetStoryVisibilityFingerprint.exception + } +} diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/BaseModelMapperFingerprint.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/BaseModelMapperFingerprint.kt new file mode 100644 index 0000000000..2d6d18a9e5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/BaseModelMapperFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.facebook.ads.mainfeed.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object BaseModelMapperFingerprint : MethodFingerprint( + + accessFlags = (AccessFlags.PUBLIC or AccessFlags.FINAL), + parameters = listOf("Ljava/lang/Class","I","I"), + returnType = "Lcom/facebook/graphql/modelutil/BaseModelWithTree;", + opcodes = listOf( + Opcode.SGET_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.IF_EQ + ) + +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetSponsoredDataModelTemplateFingerprint.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetSponsoredDataModelTemplateFingerprint.kt new file mode 100644 index 0000000000..9a7384be20 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetSponsoredDataModelTemplateFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.facebook.ads.mainfeed.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object GetSponsoredDataModelTemplateFingerprint : MethodFingerprint( + + accessFlags = (AccessFlags.PUBLIC or AccessFlags.FINAL), + parameters = listOf(), + returnType = "L", + opcodes = listOf( + Opcode.CONST, + Opcode.CONST, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT + ), + customFingerprint = { methodDef, classDef -> + classDef.type == "Lcom/facebook/graphql/model/GraphQLFBMultiAdsFeedUnit;" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetStoryVisibilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetStoryVisibilityFingerprint.kt new file mode 100644 index 0000000000..cf296c92e7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/fingerprints/GetStoryVisibilityFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.facebook.ads.mainfeed.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Annotation +import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue + +internal object GetStoryVisibilityFingerprint : MethodFingerprint( + returnType = "Ljava/lang/String;", + accessFlags = (AccessFlags.PUBLIC or AccessFlags.STATIC), + opcodes = listOf( + Opcode.INSTANCE_OF, + Opcode.IF_NEZ, + Opcode.INSTANCE_OF, + Opcode.IF_NEZ, + Opcode.INSTANCE_OF, + Opcode.IF_NEZ, + Opcode.CONST + ), + strings = listOf("This should not be called for base class object"), +) \ No newline at end of file From c9c7f01a2f196c7d75992be89f0313897699f493 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 17 Oct 2024 15:39:04 +0000 Subject: [PATCH 26/39] chore: Release v4.17.0-dev.10 [skip ci] # [4.17.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.9...v4.17.0-dev.10) (2024-10-17) ### Features * **Facebook:** Add `Hide sponsored stories` patch ([#3627](https://github.com/ReVanced/revanced-patches/issues/3627)) ([214c72b](https://github.com/ReVanced/revanced-patches/commit/214c72baeb7f87f21cd2ca34301ab11fa0ff1a4f)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff92f0c66e..ac0b0e0f3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.17.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.9...v4.17.0-dev.10) (2024-10-17) + + +### Features + +* **Facebook:** Add `Hide sponsored stories` patch ([#3627](https://github.com/ReVanced/revanced-patches/issues/3627)) ([214c72b](https://github.com/ReVanced/revanced-patches/commit/214c72baeb7f87f21cd2ca34301ab11fa0ff1a4f)) + # [4.17.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.8...v4.17.0-dev.9) (2024-10-17) diff --git a/gradle.properties b/gradle.properties index 5a62a4b223..e24f3e4f33 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.17.0-dev.9 +version = 4.17.0-dev.10 From 049e7f081358d2e1bf87d30e87b01c61b5eeafcc Mon Sep 17 00:00:00 2001 From: Zain Date: Sat, 19 Oct 2024 19:26:39 +0700 Subject: [PATCH 27/39] feat(YouTube): Support versions `19.25` and `19.34` (#3629) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Co-authored-by: oSumAtrIX --- api/revanced-patches.api | 19 +- .../cleardisplay/RememberClearDisplayPatch.kt | 6 +- .../youtube/ad/general/HideAdsPatch.kt | 23 +- .../ad/getpremium/HideGetPremiumPatch.kt | 23 +- .../patches/youtube/ad/video/VideoAdsPatch.kt | 23 +- .../copyvideourl/CopyVideoUrlBytecodePatch.kt | 19 +- .../RemoveViewerDiscretionDialogPatch.kt | 23 +- .../interaction/downloads/DownloadsPatch.kt | 19 +- .../DisablePreciseSeekingGesturePatch.kt | 23 +- .../seekbar/EnableSeekbarTappingPatch.kt | 22 +- .../seekbar/EnableSlideToSeekPatch.kt | 125 ++++-- .../DisableFastForwardGestureFingerprint.kt | 21 + ...=> DisableFastForwardLegacyFingerprint.kt} | 2 +- .../DisableFastForwardNoticeFingerprint.kt | 19 + .../fingerprints/SeekbarTappingFingerprint.kt | 13 +- .../fingerprints/SlideToSeekFingerprint.kt | 16 +- .../SwipingUpGestureParentFingerprint.kt | 3 - .../SwipeControlsBytecodePatch.kt | 23 +- .../layout/autocaptions/AutoCaptionsPatch.kt | 23 +- .../layout/buttons/action/HideButtonsPatch.kt | 23 +- .../autoplay/HideAutoplayButtonPatch.kt | 23 +- .../captions/HideCaptionsButtonPatch.kt | 23 +- .../navigation/NavigationButtonsPatch.kt | 23 +- .../player/hide/HidePlayerButtonsPatch.kt | 79 ++-- .../hide/HidePlayerButtonsResourcePatch.kt | 24 ++ ...rolsPreviousNextOverlayTouchFingerprint.kt | 20 + ...layerControlsVisibilityModelFingerprint.kt | 9 - .../layout/hide/albumcards/AlbumCardsPatch.kt | 23 +- .../layout/hide/comments/CommentsPatch.kt | 23 +- .../crowdfundingbox/CrowdfundingBoxPatch.kt | 23 +- .../endscreencards/HideEndscreenCardsPatch.kt | 23 +- .../hide/filterbar/HideFilterBarPatch.kt | 23 +- .../HideFloatingMicrophoneButtonPatch.kt | 23 +- .../DisableFullscreenAmbientModePatch.kt | 22 +- .../hide/general/HideLayoutComponentsPatch.kt | 31 +- .../hide/infocards/HideInfoCardsPatch.kt | 28 +- .../HidePlayerFlyoutMenuPatch.kt | 23 +- .../DisableRollingNumberAnimationPatch.kt | 22 +- .../layout/hide/seekbar/HideSeekbarPatch.kt | 31 +- .../hide/shorts/HideShortsComponentsPatch.kt | 172 ++++---- .../HideShortsComponentsResourcePatch.kt | 31 +- .../BottomNavigationBarFingerprint.kt | 24 -- ...derBottomNavigationBarParentFingerprint.kt | 15 + .../ReelConstructorFingerprint.kt | 12 +- .../RenderBottomNavigationBarFingerprint.kt | 2 + ...derBottomNavigationBarParentFingerprint.kt | 17 +- .../ShortsBottomBarContainerFingerprint.kt | 16 + .../DisableSuggestedVideoEndScreenPatch.kt | 22 +- .../layout/hide/time/HideTimestampPatch.kt | 22 +- .../layout/miniplayer/MiniplayerPatch.kt | 373 ++++++++++++------ .../miniplayer/MiniplayerResourcePatch.kt | 92 +++-- .../MiniplayerMinimumSizeFingerprint.kt | 16 + .../MiniplayerModernConstructorFingerprint.kt | 12 +- .../MiniplayerOverrideFingerprint.kt | 1 - .../panels/popup/PlayerPopupPanelsPatch.kt | 23 +- .../PlayerControlsBackgroundPatch.kt | 23 +- .../ReturnYouTubeDislikePatch.kt | 147 +++---- .../ConversionContextFingerprint.kt | 5 +- .../RollingNumberSetterFingerprint.kt | 3 +- .../RollingNumberTextViewFingerprint.kt | 3 +- .../fingerprints/ShortsTextViewFingerprint.kt | 14 +- .../TextComponentDataFingerprint.kt | 4 +- .../layout/searchbar/WideSearchbarPatch.kt | 22 +- .../SetWordmarkHeaderFingerprint.kt | 2 +- .../RestoreOldSeekbarThumbnailsPatch.kt | 32 +- .../seekbar/SeekbarColorBytecodePatch.kt | 59 ++- .../LithoLinearGradientFingerprint.kt | 10 + .../PlayerSeekbarGradientConfigFingerprint.kt | 15 + .../sponsorblock/SponsorBlockBytecodePatch.kt | 218 +++++----- .../spoofappversion/SpoofAppVersionPatch.kt | 23 +- .../layout/startpage/ChangeStartPagePatch.kt | 59 ++- .../fingerprints/BrowseIdFingerprint.kt | 15 + ...gerprint.kt => IntentActionFingerprint.kt} | 3 +- .../DisableResumingShortsOnStartupPatch.kt | 77 ++-- .../UserWasInShortsConfigFingerprint.kt | 35 ++ .../layout/tablet/EnableTabletLayoutPatch.kt | 25 +- .../layout/theme/ThemeBytecodePatch.kt | 22 +- .../layout/theme/ThemeResourcePatch.kt | 25 ++ .../thumbnails/AlternativeThumbnailsPatch.kt | 23 +- .../BypassImageRegionRestrictions.kt | 23 +- .../misc/autorepeat/AutoRepeatPatch.kt | 23 +- .../BackgroundPlaybackPatch.kt | 45 +-- ...oundPlaybackPolicyControllerFingerprint.kt | 8 +- .../spoof/SpoofDeviceDimensionsPatch.kt | 21 +- ...ckWatchHistoryDomainNameResolutionPatch.kt | 23 +- .../fix/cairo/DisableCairoSettingsPatch.kt | 56 +++ .../CarioFragmentConfigFingerprint.kt | 20 + .../fix/playback/SpoofVideoStreamsPatch.kt | 22 +- .../youtube/misc/gms/GmsCoreSupportPatch.kt | 26 +- .../misc/imageurlhook/CronetImageUrlHook.kt | 5 +- .../misc/integrations/IntegrationsPatch.kt | 8 +- .../APIPlayerServiceFingerprint.kt | 17 - ...mbeddedPlayerControlsOverlayFingerprint.kt | 22 -- .../fingerprints/EmbeddedPlayerFingerprint.kt | 20 - .../RemoteEmbedFragmentFingerprint.kt | 19 - .../RemoteEmbeddedPlayerFingerprint.kt | 19 - .../StandalonePlayerActivityFingerprint.kt | 23 -- .../misc/links/BypassURLRedirectsPatch.kt | 90 +++-- .../misc/links/OpenLinksExternallyPatch.kt | 23 +- .../fingerprints/ABUriParserFingerprint.kt | 31 +- .../ABUriParserLegacyFingerprint.kt | 33 ++ .../fingerprints/HTTPUriParserFingerprint.kt | 14 +- .../HTTPUriParserLegacyFingerprint.kt | 17 + .../misc/litho/filter/LithoFilterPatch.kt | 249 +++++++----- .../ComponentContextParserFingerprint.kt | 4 + .../EmptyComponentBuilderFingerprint.kt | 11 - .../fingerprints/EmptyComponentFingerprint.kt | 14 + .../ReadComponentIdentifierFingerprint.kt | 11 +- .../misc/navigation/NavigationBarHookPatch.kt | 12 +- .../ActionBarSearchResultsFingerprint.kt | 1 - .../InitializeButtonsFingerprint.kt | 1 - .../fingerprint/VideoStateFingerprint.kt | 5 +- .../misc/playservice/VersionCheckPatch.kt | 52 +++ .../RemoveTrackingQueryParameterPatch.kt | 22 +- .../hook/RecyclerViewTreeHookPatch.kt | 2 +- .../RecyclerViewTreeObserverFingerprint.kt | 5 +- .../youtube/misc/settings/SettingsPatch.kt | 2 + .../misc/settings/SettingsResourcePatch.kt | 79 ++-- .../fingerprints/HomeActivityFingerprint.kt | 9 - ...umberTextViewAnimationUpdateFingerprint.kt | 3 +- .../video/hdrbrightness/HDRBrightnessPatch.kt | 1 - .../information/VideoInformationPatch.kt | 27 +- .../MdxSeekRelativeFingerprint.kt | 5 +- .../fingerprints/SeekRelativeFingerprint.kt | 4 +- .../PlayerResponseMethodHookPatch.kt | 24 +- .../PlayerParameterBuilderFingerprint.kt | 7 +- ...PlayerParameterBuilderLegacyFingerprint.kt | 28 ++ .../quality/RememberVideoQualityPatch.kt | 19 +- .../youtube/video/speed/PlaybackSpeedPatch.kt | 19 +- .../speed/custom/CustomPlaybackSpeedPatch.kt | 172 ++++---- .../youtube/video/videoid/VideoIdPatch.kt | 56 ++- .../VideoIdBackgroundPlayFingerprint.kt | 32 ++ .../videoid/fingerprint/VideoIdFingerprint.kt | 10 +- .../VideoIdFingerprintBackgroundPlay.kt | 21 - .../fingerprint/VideoIdParentFingerprint.kt | 12 + .../RestoreOldVideoQualityMenuPatch.kt | 23 +- .../kotlin/app/revanced/util/BytecodeUtils.kt | 161 +++++++- .../util/patch/LiteralValueFingerprint.kt | 1 + .../resources/addresources/values/arrays.xml | 66 ++-- .../resources/addresources/values/strings.xml | 54 ++- .../resources/settings/host/values/styles.xml | 25 ++ 141 files changed, 2279 insertions(+), 2256 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardGestureFingerprint.kt rename src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/{DoubleSpeedSeekNoticeFingerprint.kt => DisableFastForwardLegacyFingerprint.kt} (79%) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardNoticeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsResourcePatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsPreviousNextOverlayTouchFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsVisibilityModelFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/BottomNavigationBarFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/LegacyRenderBottomNavigationBarParentFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ShortsBottomBarContainerFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerMinimumSizeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/LithoLinearGradientFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/PlayerSeekbarGradientConfigFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/BrowseIdFingerprint.kt rename src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/{StartActivityFingerprint.kt => IntentActionFingerprint.kt} (63%) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsConfigFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/DisableCairoSettingsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/fingerprints/CarioFragmentConfigFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserLegacyFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserLegacyFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderLegacyFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdBackgroundPlayFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdParentFingerprint.kt create mode 100644 src/main/resources/settings/host/values/styles.xml diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 5ca19d08bf..ed2f78f371 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1850,10 +1850,6 @@ public final class app/revanced/patches/youtube/layout/startpage/ChangeStartPage public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/youtube/layout/startpage/fingerprints/StartActivityFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { - public static final field INSTANCE Lapp/revanced/patches/youtube/layout/startpage/fingerprints/StartActivityFingerprint; -} - public final class app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V @@ -2203,12 +2199,27 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List; public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List; + public static final fun forEachLiteralValueInstruction (Lapp/revanced/patcher/data/BytecodeContext;JLkotlin/jvm/functions/Function2;)V public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException; + public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;)I public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I + public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I + public static synthetic fun indexOfFirstInstruction$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstruction$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I + public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;)I public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I + public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I + public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I + public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;)I + public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I + public static synthetic fun indexOfFirstInstructionReversed$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I + public static synthetic fun indexOfFirstInstructionReversed$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I + public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;)I + public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I + public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I + public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I public static final fun indexOfFirstWideLiteralInstructionValueOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I public static final fun indexOfFirstWideLiteralInstructionValueReversed (Lcom/android/tools/smali/dexlib2/iface/Method;J)I diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt index 60eb637c47..b1522e880c 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt @@ -13,7 +13,7 @@ import app.revanced.patches.tiktok.shared.fingerprints.OnRenderFirstFrameFingerp import app.revanced.util.exception import app.revanced.util.indexOfFirstInstructionOrThrow import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Remember clear display", @@ -34,8 +34,8 @@ object RememberClearDisplayPatch : BytecodePatch( OnClearDisplayEventFingerprint.result?.mutableMethod?.let { // region Hook the "Clear display" configuration save event to remember the state of clear display. - val isEnabledIndex = it.indexOfFirstInstructionOrThrow { opcode == Opcode.IGET_BOOLEAN } + 1 - val isEnabledRegister = it.getInstruction(isEnabledIndex - 1).registerA + val isEnabledIndex = it.indexOfFirstInstructionOrThrow(Opcode.IGET_BOOLEAN) + 1 + val isEnabledRegister = it.getInstruction(isEnabledIndex - 1).registerA it.addInstructions( isEnabledIndex, diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt index fd6ffde4b9..9cb064b597 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt @@ -26,30 +26,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt index a36063d3d3..4cb81e2fbd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt @@ -20,30 +20,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt index b2df5d82b1..aa3a7f71eb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt @@ -25,30 +25,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt index cea3988c28..ac5d7499b5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt @@ -19,24 +19,11 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch CompatiblePackage( "com.google.android.youtube", [ - "18.48.39", + "18.38.44", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt index 83b391cb8f..88df4beae6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt @@ -22,30 +22,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt index 6c8119fe93..7d2dd4a9ac 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt @@ -25,24 +25,11 @@ import app.revanced.util.resultOrThrow CompatiblePackage( "com.google.android.youtube", [ - "18.48.39", + "18.38.44", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt index dd3a07ae7f..04be050176 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt @@ -24,30 +24,11 @@ import app.revanced.util.alsoResolve CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt index eaae9af877..e37eb7f38c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt @@ -27,27 +27,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference CompatiblePackage( "com.google.android.youtube", [ - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", + // 18.38.44 patches but crashes on startup. "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt index e6ed839e4b..5b40947aac 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt @@ -4,46 +4,37 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.interaction.seekbar.fingerprints.DoubleSpeedSeekNoticeFingerprint +import app.revanced.patches.youtube.interaction.seekbar.fingerprints.DisableFastForwardLegacyFingerprint +import app.revanced.patches.youtube.interaction.seekbar.fingerprints.DisableFastForwardGestureFingerprint +import app.revanced.patches.youtube.interaction.seekbar.fingerprints.DisableFastForwardNoticeFingerprint import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SlideToSeekFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.util.exception +import app.revanced.util.getReference +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Enable slide to seek", - description = "Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.", + description = "Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with the video player overlay, such as missing buttons and ignored taps and double taps.", dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", + "18.38.44", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ], @@ -53,10 +44,13 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction object EnableSlideToSeekPatch : BytecodePatch( setOf( SlideToSeekFingerprint, - DoubleSpeedSeekNoticeFingerprint + DisableFastForwardLegacyFingerprint, + DisableFastForwardGestureFingerprint, + DisableFastForwardNoticeFingerprint ) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/SlideToSeekPatch;" + private const val INTEGRATIONS_METHOD_DESCRIPTOR = + "Lapp/revanced/integrations/youtube/patches/SlideToSeekPatch;->isSlideToSeekDisabled(Z)Z" override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) @@ -65,27 +59,74 @@ object EnableSlideToSeekPatch : BytecodePatch( SwitchPreference("revanced_slide_to_seek") ) - arrayOf( - // Restore the behaviour to slide to seek. - SlideToSeekFingerprint, - // Disable the double speed seek notice. - DoubleSpeedSeekNoticeFingerprint - ).map { - it.result ?: throw it.exception - }.forEach { - val insertIndex = it.scanResult.patternScanResult!!.endIndex + 1 + var modifiedMethods = false - it.mutableMethod.apply { - val isEnabledRegister = getInstruction(insertIndex).registerA + // Restore the behaviour to slide to seek. + SlideToSeekFingerprint.resultOrThrow().let { + val checkIndex = it.scanResult.patternScanResult!!.startIndex + val checkReference = it.mutableMethod + .getInstruction(checkIndex).getReference()!! - addInstructions( - insertIndex, - """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isSlideToSeekDisabled()Z - move-result v$isEnabledRegister - """ - ) + // A/B check method was only called on this class. + it.mutableClass.methods.forEach { method -> + method.implementation!!.instructions.forEachIndexed { index, instruction -> + if (instruction.opcode == Opcode.INVOKE_VIRTUAL && + instruction.getReference() == checkReference + ) { + method.apply { + val targetRegister = getInstruction(index + 1).registerA + + addInstructions( + index + 2, + """ + invoke-static { v$targetRegister }, $INTEGRATIONS_METHOD_DESCRIPTOR + move-result v$targetRegister + """ + ) + } + + modifiedMethods = true + } + } + } + } + + if (!modifiedMethods) throw PatchException("Could not find methods to modify") + + // Disable the double speed seek gesture. + if (!VersionCheckPatch.is_19_17_or_greater) { + DisableFastForwardLegacyFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val insertIndex = it.scanResult.patternScanResult!!.endIndex + 1 + val targetRegister = getInstruction(insertIndex).registerA + + addInstructions( + insertIndex, + """ + invoke-static { v$targetRegister }, $INTEGRATIONS_METHOD_DESCRIPTOR + move-result v$targetRegister + """ + ) + } } + } else { + arrayOf( + DisableFastForwardGestureFingerprint, + DisableFastForwardNoticeFingerprint + ).forEach { it.resultOrThrow().let { + it.mutableMethod.apply { + val targetIndex = it.scanResult.patternScanResult!!.endIndex + val targetRegister = getInstruction(targetIndex).registerA + + addInstructions( + targetIndex + 1, + """ + invoke-static { v$targetRegister }, $INTEGRATIONS_METHOD_DESCRIPTOR + move-result v$targetRegister + """ + ) + } + }} } } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardGestureFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardGestureFingerprint.kt new file mode 100644 index 0000000000..a1c5bf9870 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardGestureFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.interaction.seekbar.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object DisableFastForwardGestureFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "Z", + parameters = emptyList(), + opcodes = listOf( + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT + ), + customFingerprint = { methodDef, classDef -> + methodDef.implementation!!.instructions.count() > 30 && + classDef.type.endsWith("/NextGenWatchLayout;") + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DoubleSpeedSeekNoticeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardLegacyFingerprint.kt similarity index 79% rename from src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DoubleSpeedSeekNoticeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardLegacyFingerprint.kt index eee74fde59..1762c20431 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DoubleSpeedSeekNoticeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardLegacyFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.interaction.seekbar.fingerprints import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.Opcode -internal object DoubleSpeedSeekNoticeFingerprint : LiteralValueFingerprint( +internal object DisableFastForwardLegacyFingerprint : LiteralValueFingerprint( returnType = "Z", parameters = emptyList(), opcodes = listOf(Opcode.MOVE_RESULT), diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardNoticeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardNoticeFingerprint.kt new file mode 100644 index 0000000000..99be205e87 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DisableFastForwardNoticeFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.interaction.seekbar.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object DisableFastForwardNoticeFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "V", + parameters = emptyList(), + opcodes = listOf( + Opcode.CHECK_CAST, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT + ), + strings = listOf("Failed to easy seek haptics vibrate") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt index ddb8bf47d9..3989aa2d5c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt @@ -2,10 +2,9 @@ package app.revanced.patches.youtube.interaction.seekbar.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.util.containsWideLiteralInstructionValue import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction - internal object SeekbarTappingFingerprint : MethodFingerprint( returnType = "Z", @@ -21,14 +20,6 @@ internal object SeekbarTappingFingerprint : MethodFingerprint( customFingerprint = custom@{ methodDef, _ -> if (methodDef.name != "onTouchEvent") return@custom false - methodDef.implementation!!.instructions.any { instruction -> - if (instruction.opcode != Opcode.CONST) return@any false - - val literal = (instruction as NarrowLiteralInstruction).narrowLiteral - - // onTouchEvent method contains a CONST instruction - // with this literal making it unique with the rest of the properties of this fingerprint. - literal == Integer.MAX_VALUE - } + methodDef.containsWideLiteralInstructionValue(Integer.MAX_VALUE.toLong()) } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt index b618ea50f1..c3af701bfc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt @@ -1,11 +1,19 @@ package app.revanced.patches.youtube.interaction.seekbar.fingerprints +import app.revanced.patcher.extensions.or import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode internal object SlideToSeekFingerprint : LiteralValueFingerprint( - returnType = "Z", - parameters = emptyList(), - opcodes = listOf(Opcode.MOVE_RESULT), - literalSupplier = { 45411329 } + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + returnType = "V", + parameters = listOf("Landroid/view/View;", "F"), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.GOTO_16 + ), + literalSupplier = { 67108864 } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SwipingUpGestureParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SwipingUpGestureParentFingerprint.kt index cb33e72a23..98a03b3cbf 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SwipingUpGestureParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SwipingUpGestureParentFingerprint.kt @@ -1,11 +1,8 @@ package app.revanced.patches.youtube.interaction.seekbar.fingerprints -import app.revanced.patcher.extensions.or import app.revanced.util.patch.LiteralValueFingerprint -import com.android.tools.smali.dexlib2.AccessFlags internal object SwipingUpGestureParentFingerprint : LiteralValueFingerprint( - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, returnType = "Z", parameters = listOf(), literalSupplier = { 45379021 } diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt index 819ea52cad..63cffeb675 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt @@ -26,30 +26,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt index fabd8cc3ae..f5ea004743 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt @@ -24,30 +24,11 @@ import app.revanced.util.exception CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt index 1da88f35cb..f2994c824c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt @@ -23,30 +23,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt index 6446f32a43..161a3a2b3c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt @@ -34,30 +34,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt index e346945db4..bf41baa3be 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt @@ -24,30 +24,11 @@ import com.android.tools.smali.dexlib2.Opcode CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt index 10e8d36045..3ef0caba2a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt @@ -37,30 +37,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt index 2199b05d8e..9581f8f8ac 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt @@ -1,20 +1,23 @@ package app.revanced.patches.youtube.layout.buttons.player.hide import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.layout.buttons.player.hide.HidePlayerButtonsPatch.ParameterOffsets.HAS_NEXT -import app.revanced.patches.youtube.layout.buttons.player.hide.HidePlayerButtonsPatch.ParameterOffsets.HAS_PREVIOUS -import app.revanced.patches.youtube.layout.buttons.player.hide.fingerprints.PlayerControlsVisibilityModelFingerprint +import app.revanced.patches.youtube.layout.buttons.player.hide.fingerprints.PlayerControlsPreviousNextOverlayTouchFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.util.exception -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Hide player buttons", @@ -22,43 +25,25 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc dependencies = [ IntegrationsPatch::class, SettingsPatch::class, - AddResourcesPatch::class + AddResourcesPatch::class, + HidePlayerButtonsResourcePatch::class, ], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] ) @Suppress("unused") object HidePlayerButtonsPatch : BytecodePatch( - setOf(PlayerControlsVisibilityModelFingerprint) + setOf(PlayerControlsPreviousNextOverlayTouchFingerprint) ) { override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) @@ -67,29 +52,23 @@ object HidePlayerButtonsPatch : BytecodePatch( SwitchPreference("revanced_hide_player_buttons") ) - PlayerControlsVisibilityModelFingerprint.result?.apply { - val callIndex = scanResult.patternScanResult!!.endIndex - val callInstruction = mutableMethod.getInstruction(callIndex) + PlayerControlsPreviousNextOverlayTouchFingerprint.resultOrThrow().mutableMethod.apply { + val resourceIndex = indexOfFirstWideLiteralInstructionValueOrThrow( + HidePlayerButtonsResourcePatch.playerControlPreviousButtonTouchArea + ) - // overriding this parameter register hides the previous and next buttons - val hasNextParameterRegister = callInstruction.startRegister + HAS_NEXT - val hasPreviousParameterRegister = callInstruction.startRegister + HAS_PREVIOUS + val insertIndex = indexOfFirstInstructionOrThrow(resourceIndex) { + opcode == Opcode.INVOKE_STATIC + && getReference()?.parameterTypes?.firstOrNull() == "Landroid/view/View;" + } - mutableMethod.addInstructions( - callIndex, - """ - invoke-static { v$hasNextParameterRegister }, Lapp/revanced/integrations/youtube/patches/HidePlayerButtonsPatch;->previousOrNextButtonIsVisible(Z)Z - move-result v$hasNextParameterRegister - - invoke-static { v$hasPreviousParameterRegister }, Lapp/revanced/integrations/youtube/patches/HidePlayerButtonsPatch;->previousOrNextButtonIsVisible(Z)Z - move-result v$hasPreviousParameterRegister - """ - ) - } ?: throw PlayerControlsVisibilityModelFingerprint.exception - } + val viewRegister = getInstruction(insertIndex).registerC - private object ParameterOffsets { - const val HAS_NEXT = 5 - const val HAS_PREVIOUS = 6 + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, Lapp/revanced/integrations/youtube/patches/HidePlayerButtonsPatch;" + + "->hidePreviousNextButtons(Landroid/view/View;)V" + ) + } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsResourcePatch.kt new file mode 100644 index 0000000000..7bd23b17a1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsResourcePatch.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.youtube.layout.buttons.player.hide + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch + +@Patch(dependencies = [ResourceMappingPatch::class]) +internal object HidePlayerButtonsResourcePatch : ResourcePatch() { + var playerControlPreviousButtonTouchArea = -1L + var playerControlNextButtonTouchArea = -1L + + override fun execute(context: ResourceContext) { + playerControlPreviousButtonTouchArea = ResourceMappingPatch[ + "id", + "player_control_previous_button_touch_area" + ] + + playerControlNextButtonTouchArea = ResourceMappingPatch[ + "id", + "player_control_next_button_touch_area" + ] + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsPreviousNextOverlayTouchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsPreviousNextOverlayTouchFingerprint.kt new file mode 100644 index 0000000000..131bf47130 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsPreviousNextOverlayTouchFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.layout.buttons.player.hide.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.youtube.layout.buttons.player.hide.HidePlayerButtonsResourcePatch +import app.revanced.util.containsWideLiteralInstructionValue +import com.android.tools.smali.dexlib2.AccessFlags + +internal object PlayerControlsPreviousNextOverlayTouchFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "V", + strings = listOf("1.0x"), + customFingerprint = { methodDef, _ -> + methodDef.containsWideLiteralInstructionValue( + HidePlayerButtonsResourcePatch.playerControlPreviousButtonTouchArea + ) && methodDef.containsWideLiteralInstructionValue( + HidePlayerButtonsResourcePatch.playerControlNextButtonTouchArea + ) + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsVisibilityModelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsVisibilityModelFingerprint.kt deleted file mode 100644 index 4aae5c27ed..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/fingerprints/PlayerControlsVisibilityModelFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.buttons.player.hide.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.Opcode - -internal object PlayerControlsVisibilityModelFingerprint : MethodFingerprint( - opcodes = listOf(Opcode.INVOKE_DIRECT_RANGE), - strings = listOf("Missing required properties:", "hasNext", "hasPrevious") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt index 782999c106..937f2b509d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt @@ -22,30 +22,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt index 51280ac183..9c595da663 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt @@ -22,30 +22,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt index 938d91eb70..e186babd7b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt @@ -22,30 +22,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt index 396e9a8c35..3585f800d5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt @@ -25,30 +25,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt index 37915f48d0..7e4ad51230 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt @@ -22,30 +22,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt index 697b081fc7..07b8425727 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt @@ -18,30 +18,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt index 0d7ccb956c..1e596071bd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt @@ -19,29 +19,11 @@ import app.revanced.util.exception compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index 9a99f3ef5c..3930d17716 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -24,6 +24,7 @@ import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.util.findOpcodeIndicesReversed import app.revanced.util.getReference +import app.revanced.util.alsoResolve import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -45,30 +46,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], @@ -202,9 +184,10 @@ object HideLayoutComponentsPatch : BytecodePatch( // region Watermark (legacy code for old versions of YouTube) - ShowWatermarkFingerprint.also { - it.resolve(context, PlayerOverlayFingerprint.resultOrThrow().classDef) - }.resultOrThrow().mutableMethod.apply { + ShowWatermarkFingerprint.alsoResolve( + context, + PlayerOverlayFingerprint + ).mutableMethod.apply { val index = implementation!!.instructions.size - 5 removeInstruction(index) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt index 92b2d5a4f8..cd162823eb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt @@ -13,6 +13,7 @@ import app.revanced.patches.youtube.layout.hide.infocards.fingerprints.Infocards import app.revanced.patches.youtube.layout.hide.infocards.fingerprints.InfocardsMethodCallFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch +import app.revanced.util.alsoResolve import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -29,30 +30,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] @@ -68,9 +50,7 @@ object HideInfoCardsPatch : BytecodePatch( "Lapp/revanced/integrations/youtube/patches/components/HideInfoCardsFilterPatch;" override fun execute(context: BytecodeContext) { - InfocardsIncognitoFingerprint.also { - it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef) - }.result!!.mutableMethod.apply { + InfocardsIncognitoFingerprint.alsoResolve(context, InfocardsIncognitoParentFingerprint).mutableMethod.apply { val invokeInstructionIndex = implementation!!.instructions.indexOfFirst { it.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal && ((it as ReferenceInstruction).reference.toString() == "Landroid/view/View;->setVisibility(I)V") diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt index 6bf5c58eb7..76ac414085 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt @@ -23,30 +23,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt index 0e7b98850f..a2fe2ad1c4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt @@ -23,27 +23,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", + // 18.43 is the earliest target this patch works. "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt index 6f369184a4..0f4473523b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt @@ -12,6 +12,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.shared.fingerprints.SeekbarFingerprint import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint +import app.revanced.util.alsoResolve @Patch( name = "Hide seekbar", @@ -25,30 +26,11 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] @@ -65,9 +47,10 @@ object HideSeekbarPatch : BytecodePatch( SwitchPreference("revanced_hide_seekbar_thumbnail") ) - SeekbarFingerprint.result!!.let { - SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) } - }.result!!.mutableMethod.addInstructionsWithLabels( + SeekbarOnDrawFingerprint.alsoResolve( + context, + SeekbarFingerprint + ).mutableMethod.addInstructionsWithLabels( 0, """ const/4 v0, 0x0 diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt index e1ba723910..87986185de 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt @@ -2,6 +2,7 @@ package app.revanced.patches.youtube.layout.hide.shorts import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage @@ -13,10 +14,15 @@ import app.revanced.patches.youtube.layout.hide.shorts.fingerprints.* import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch -import app.revanced.util.exception +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch +import app.revanced.util.forEachLiteralValueInstruction +import app.revanced.util.alsoResolve import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstWideLiteralInstructionValue import app.revanced.util.indexOfIdResourceOrThrow import app.revanced.util.injectHideViewCall +import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -32,35 +38,17 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference HideShortsComponentsResourcePatch::class, ResourceMappingPatch::class, NavigationBarHookPatch::class, + VersionCheckPatch::class ], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], @@ -70,7 +58,8 @@ object HideShortsComponentsPatch : BytecodePatch( setOf( CreateShortsButtonsFingerprint, ReelConstructorFingerprint, - BottomNavigationBarFingerprint, + ShortsBottomBarContainerFingerprint, + LegacyRenderBottomNavigationBarParentFingerprint, RenderBottomNavigationBarParentFingerprint, SetPivotBarVisibilityParentFingerprint, ), @@ -95,29 +84,30 @@ object HideShortsComponentsPatch : BytecodePatch( // region Hide the Shorts shelf. // This patch point is not present in 19.03.x and greater. - // If 19.02.x and lower is dropped, then this section of code and the fingerprint should be removed. - ReelConstructorFingerprint.result?.let { - it.mutableMethod.apply { - val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 - val viewRegister = getInstruction(insertIndex).registerA - - injectHideViewCall( - insertIndex, - viewRegister, - FILTER_CLASS_DESCRIPTOR, - "hideShortsShelf", - ) + if (!VersionCheckPatch.is_19_03_or_greater) { + ReelConstructorFingerprint.result?.let { + it.mutableMethod.apply { + val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 + val viewRegister = getInstruction(insertIndex).registerA + + injectHideViewCall( + insertIndex, + viewRegister, + FILTER_CLASS_DESCRIPTOR, + "hideShortsShelf", + ) + } } - } // Do not throw an exception if not resolved. + } // endregion // region Hide the Shorts buttons in older versions of YouTube. // Some Shorts buttons are views, hide them by setting their visibility to GONE. - CreateShortsButtonsFingerprint.result?.let { + CreateShortsButtonsFingerprint.resultOrThrow().let { ShortsButtons.entries.forEach { button -> button.injectHideCall(it.mutableMethod) } - } ?: throw CreateShortsButtonsFingerprint.exception + } // endregion @@ -125,54 +115,68 @@ object HideShortsComponentsPatch : BytecodePatch( LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) - // endregion + context.forEachLiteralValueInstruction( + HideShortsComponentsResourcePatch.reelPlayerRightPivotV2Size + ) { literalInstructionIndex -> + val targetIndex = indexOfFirstInstructionOrThrow(literalInstructionIndex) { + getReference()?.name == "getDimensionPixelSize" + } + 1 - // region Hide the navigation bar. + val sizeRegister = getInstruction(targetIndex).registerA - // Hook to get the pivotBar view. - SetPivotBarVisibilityParentFingerprint.result?.let { - if (!SetPivotBarVisibilityFingerprint.resolve(context, it.classDef)) { - throw SetPivotBarVisibilityFingerprint.exception - } + addInstructions(targetIndex + 1, """ + invoke-static { v$sizeRegister }, $FILTER_CLASS_DESCRIPTOR->getSoundButtonSize(I)I + move-result v$sizeRegister + """ + ) + } - SetPivotBarVisibilityFingerprint.result!!.let { result -> - result.mutableMethod.apply { - val insertIndex = result.scanResult.patternScanResult!!.endIndex - val viewRegister = getInstruction(insertIndex - 1).registerA - addInstruction( - insertIndex, - "sput-object v$viewRegister, $FILTER_CLASS_DESCRIPTOR->pivotBar:" + - "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;", - ) - } - } - } ?: throw SetPivotBarVisibilityParentFingerprint.exception + // endregion - // Hook to hide the navigation bar when Shorts are being played. - RenderBottomNavigationBarParentFingerprint.result?.let { - if (!RenderBottomNavigationBarFingerprint.resolve(context, it.classDef)) { - throw RenderBottomNavigationBarFingerprint.exception - } + // region Hide the navigation bar. - RenderBottomNavigationBarFingerprint.result!!.mutableMethod.apply { - addInstruction(0, "invoke-static { }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar()V") - } - } ?: throw RenderBottomNavigationBarParentFingerprint.exception - - // Required to prevent a black bar from appearing at the bottom of the screen. - BottomNavigationBarFingerprint.result?.let { - it.mutableMethod.apply { - val moveResultIndex = it.scanResult.patternScanResult!!.startIndex + 2 - val viewRegister = getInstruction(moveResultIndex).registerA - val insertIndex = moveResultIndex + 1 - - addInstruction( - insertIndex, - "invoke-static { v$viewRegister }, $FILTER_CLASS_DESCRIPTOR->" + - "hideNavigationBar(Landroid/view/View;)Landroid/view/View;", + // Hook to get the pivotBar view. + SetPivotBarVisibilityFingerprint.alsoResolve( + context, + SetPivotBarVisibilityParentFingerprint + ).let { result-> + result.mutableMethod.apply { + val insertIndex = result.scanResult.patternScanResult!!.endIndex + val viewRegister = getInstruction(insertIndex - 1).registerA + addInstruction(insertIndex, "invoke-static {v$viewRegister}," + + " $FILTER_CLASS_DESCRIPTOR->setNavigationBar(Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;)V" ) } - } ?: throw BottomNavigationBarFingerprint.exception + } + + // Hook to hide the shared navigation bar when the Shorts player is opened. + RenderBottomNavigationBarFingerprint.alsoResolve( + context, + if (VersionCheckPatch.is_19_41_or_greater) + RenderBottomNavigationBarParentFingerprint + else + LegacyRenderBottomNavigationBarParentFingerprint + ).mutableMethod.addInstruction( + 0, + "invoke-static { p1 }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar(Ljava/lang/String;)V" + ) + + // Hide the bottom bar container of the Shorts player. + ShortsBottomBarContainerFingerprint.resultOrThrow().mutableMethod.apply { + val resourceIndex = indexOfFirstWideLiteralInstructionValue(HideShortsComponentsResourcePatch.bottomBarContainer) + + val targetIndex = indexOfFirstInstructionOrThrow(resourceIndex) { + getReference()?.name == "getHeight" + } + 1 + + val heightRegister = getInstruction(targetIndex).registerA + + addInstructions(targetIndex + 1, """ + invoke-static { v$heightRegister }, $FILTER_CLASS_DESCRIPTOR->getNavigationBarHeight(I)I + move-result v$heightRegister + """ + ) + } // endregion } @@ -187,14 +191,12 @@ object HideShortsComponentsPatch : BytecodePatch( fun injectHideCall(method: MutableMethod) { val referencedIndex = method.indexOfIdResourceOrThrow(resourceName) - val instruction = method.implementation!!.instructions - .subList(referencedIndex, referencedIndex + 20) - .first { - it.opcode == Opcode.INVOKE_VIRTUAL && it.getReference()?.name == "setId" - } + val setIdIndex = method.indexOfFirstInstructionOrThrow(referencedIndex) { + opcode == Opcode.INVOKE_VIRTUAL && getReference()?.name == "setId" + } - val setIdIndex = instruction.location.index val viewRegister = method.getInstruction(setIdIndex).registerC + method.injectHideViewCall(setIdIndex + 1, viewRegister, FILTER_CLASS_DESCRIPTOR, methodName) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt index 866d8fb19b..38a7e99eba 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt @@ -8,13 +8,23 @@ import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.hide.shorts.HideShortsComponentsPatch.hideShortsAppShortcut import app.revanced.patches.youtube.layout.hide.shorts.HideShortsComponentsPatch.hideShortsWidget +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.util.findElementByAttributeValueOrThrow -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class]) +@Patch( + dependencies = [ + SettingsPatch::class, + ResourceMappingPatch::class, + AddResourcesPatch::class, + VersionCheckPatch::class + ] +) object HideShortsComponentsResourcePatch : ResourcePatch() { internal var reelMultipleItemShelfId = -1L internal var reelPlayerRightCellButtonHeight = -1L + internal var bottomBarContainer = -1L + internal var reelPlayerRightPivotV2Size = -1L override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) @@ -86,14 +96,21 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { "reel_player_right_cell_button_height", ] - // Resource not present in new versions of the app. - try { - ResourceMappingPatch[ + bottomBarContainer = ResourceMappingPatch[ + "id", + "bottom_bar_container" + ] + + reelPlayerRightPivotV2Size = ResourceMappingPatch[ + "dimen", + "reel_player_right_pivot_v2_size" + ] + + if (!VersionCheckPatch.is_19_03_or_greater) { + reelMultipleItemShelfId = ResourceMappingPatch[ "dimen", "reel_player_right_cell_button_height", ] - } catch (e: NoSuchElementException) { - return - }.also { reelPlayerRightCellButtonHeight = it } + } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/BottomNavigationBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/BottomNavigationBarFingerprint.kt deleted file mode 100644 index 12ca03fb13..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/BottomNavigationBarFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.shorts.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -internal object BottomNavigationBarFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Landroid/view/View;", "Landroid/os/Bundle;"), - opcodes = listOf( - Opcode.CONST, // R.id.app_engagement_panel_wrapper - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - ), - strings = listOf( - "ReelWatchPaneFragmentViewModelKey" - ), -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/LegacyRenderBottomNavigationBarParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/LegacyRenderBottomNavigationBarParentFingerprint.kt new file mode 100644 index 0000000000..de25cf8706 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/LegacyRenderBottomNavigationBarParentFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.hide.shorts.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object LegacyRenderBottomNavigationBarParentFingerprint : MethodFingerprint( + parameters = listOf( + "I", + "I", + "L", + "L", + "J", + "L", + ), + strings = listOf("aa") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt index dece9b3718..912aa9704c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt @@ -1,19 +1,13 @@ package app.revanced.patches.youtube.layout.hide.shorts.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patches.youtube.layout.hide.shorts.HideShortsComponentsResourcePatch -import app.revanced.util.containsWideLiteralInstructionValue +import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal object ReelConstructorFingerprint : MethodFingerprint( +internal object ReelConstructorFingerprint : LiteralValueFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, opcodes = listOf(Opcode.INVOKE_VIRTUAL), - customFingerprint = { methodDef, _ -> - // Cannot use LiteralValueFingerprint, because the resource id may not be present. - val reelMultipleItemShelfId = HideShortsComponentsResourcePatch.reelMultipleItemShelfId - reelMultipleItemShelfId != -1L - && methodDef.containsWideLiteralInstructionValue(reelMultipleItemShelfId) - } + literalSupplier = { HideShortsComponentsResourcePatch.reelMultipleItemShelfId } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarFingerprint.kt index d6d74b1e83..89a0ef942b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarFingerprint.kt @@ -4,6 +4,8 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.Opcode internal object RenderBottomNavigationBarFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("Ljava/lang/String;"), opcodes = listOf( Opcode.IGET_OBJECT, Opcode.MONITOR_ENTER, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarParentFingerprint.kt index cb606d5c31..00ee226b3d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/RenderBottomNavigationBarParentFingerprint.kt @@ -1,8 +1,23 @@ package app.revanced.patches.youtube.layout.hide.shorts.fingerprints +import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +/** + * Identical to [LegacyRenderBottomNavigationBarParentFingerprint] + * except this has an extra parameter. + */ internal object RenderBottomNavigationBarParentFingerprint : MethodFingerprint( - parameters = listOf("I", "I", "L", "L", "J", "L"), + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf( + "I", + "I", + "L", // ReelWatchEndpointOuterClass + "L", + "J", + "Ljava/lang/String;", + "L" + ), strings = listOf("aa") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ShortsBottomBarContainerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ShortsBottomBarContainerFingerprint.kt new file mode 100644 index 0000000000..ca9fadf590 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ShortsBottomBarContainerFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.layout.hide.shorts.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.youtube.layout.hide.shorts.HideShortsComponentsResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object ShortsBottomBarContainerFingerprint : LiteralValueFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Landroid/view/View;", "Landroid/os/Bundle;"), + strings = listOf( + "r_pfvc" + ), + literalSupplier = { HideShortsComponentsResourcePatch.bottomBarContainer } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt index aee5ad2884..ec2802ed21 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt @@ -18,29 +18,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt index 1fee6435e9..47b89e353c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt @@ -19,29 +19,11 @@ import app.revanced.util.exception compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt index 4d7c52a48f..58f80a72d2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt @@ -1,17 +1,20 @@ +@file:Suppress("SpellCheckingInspection") + package app.revanced.patches.youtube.layout.miniplayer import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.BasePreference import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen @@ -26,6 +29,7 @@ import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.sc import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24 import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlineXWhite24 import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerDimensionsCalculatorParentFingerprint +import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerMinimumSizeFingerprint import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernAddViewListenerFingerprint import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernCloseButtonFingerprint import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint @@ -42,30 +46,32 @@ import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayer import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.addInstructionsAtControlFlowLabel +import app.revanced.util.alsoResolve import app.revanced.util.findOpcodeIndicesReversed import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow -import app.revanced.util.patch.LiteralValueFingerprint import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.TypeReference import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter -// YT uses "Miniplayer" without a space between 'mini' and 'player: https://support.google.com/youtube/answer/9162927. +// YT uses "Miniplayer" without a space between 'mini' and 'player': https://support.google.com/youtube/answer/9162927. @Patch( name = "Miniplayer", - description = "Adds options to change the in app minimized player, " + - "and if patching target 19.16+ adds options to use modern miniplayers.", + description = "Adds options to change the in app minimized player. " + + "Patching target 19.16+ adds modern miniplayers.", dependencies = [ IntegrationsPatch::class, SettingsPatch::class, @@ -75,32 +81,28 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - // 19.14 is left out, as it has incomplete miniplayer code and missing some UI resources. - // It's simpler to not bother with supporting this single old version. - // 19.15 has a different code for handling sub title texts, - // and also probably not worth making changes just to support this single old version. - "19.16.39" // Earliest supported version with modern miniplayers. + // 19.14.43 // Incomplete code for modern miniplayers. + // 19.15.36 // Different code for handling subtitle texts and not worth supporting. + "19.16.39", // First with modern miniplayers. + // 19.17.41 // Works without issues, but no reason to recommend over 19.16. + // 19.18.41 // Works without issues, but no reason to recommend over 19.16. + // 19.19.39 // Last bug free version with smaller Modern 1 miniplayer, but no reason to recommend over 19.16. + // 19.20.35 // Cannot swipe to expand. + // 19.21.40 // Cannot swipe to expand. + // 19.22.43 // Cannot swipe to expand. + // 19.23.40 // First with Modern 1 drag and drop, Cannot swipe to expand. + // 19.24.45 // First with larger Modern 1, Cannot swipe to expand. + "19.25.37", // First with double tap, last with skip forward/back buttons, last with swipe to expand/close, and last before double tap to expand seems to be required. + // 19.26.42 // Modern 1 Pause/play button are always hidden. Unusable. + // 19.28.42 // First with custom miniplayer size, screen flickers when swiping to maximize Modern 1. Swipe to close miniplayer is broken. + // 19.29.42 // All modern players are broken and ignore tapping the miniplayer video. + // 19.30.39 // Modern 3 is less broken when double tap expand is enabled, but cannot swipe to expand when double tap is off. + // 19.31.36 // All Modern 1 buttons are missing. Unusable. + // 19.32.36 // 19.32+ and beyond all work without issues. + // 19.33.35 + "19.34.42", ] ) ] @@ -113,6 +115,7 @@ object MiniplayerPatch : BytecodePatch( MiniplayerOverrideFingerprint, MiniplayerModernConstructorFingerprint, MiniplayerModernViewParentFingerprint, + MiniplayerMinimumSizeFingerprint, YouTubePlayerOverlaysLayoutFingerprint ) ) { @@ -121,48 +124,71 @@ object MiniplayerPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - // Modern mini player is only present and functional in 19.15+. - // Resource is not present in older versions. Using it to determine, if patching an old version. - val isPatchingOldVersion = ytOutlinePictureInPictureWhite24 < 0 + val preferences = mutableSetOf() + + if (!VersionCheckPatch.is_19_16_or_greater) { + preferences += ListPreference( + "revanced_miniplayer_type", + summaryKey = null, + entriesKey = "revanced_miniplayer_type_legacy_entries", + entryValuesKey = "revanced_miniplayer_type_legacy_entry_values" + ) + } else { + preferences += ListPreference( + "revanced_miniplayer_type", + summaryKey = null, + ) + + if (VersionCheckPatch.is_19_25_or_greater) { + if (!VersionCheckPatch.is_19_29_or_greater) { + preferences += SwitchPreference("revanced_miniplayer_double_tap_action") + } + preferences += SwitchPreference("revanced_miniplayer_drag_and_drop") + } + + if (VersionCheckPatch.is_19_36_or_greater) { + preferences += SwitchPreference("revanced_miniplayer_rounded_corners") + } + + preferences += SwitchPreference("revanced_miniplayer_hide_subtext") + + preferences += + if (VersionCheckPatch.is_19_26_or_greater) { + SwitchPreference("revanced_miniplayer_hide_expand_close") + } else { + SwitchPreference( + key = "revanced_miniplayer_hide_expand_close", + titleKey = "revanced_miniplayer_hide_expand_close_legacy_title", + summaryOnKey = "revanced_miniplayer_hide_expand_close_legacy_summary_on", + summaryOffKey = "revanced_miniplayer_hide_expand_close_legacy_summary_off", + ) + } + + if (!VersionCheckPatch.is_19_26_or_greater) { + preferences += SwitchPreference("revanced_miniplayer_hide_rewind_forward") + } + + if (VersionCheckPatch.is_19_26_or_greater) { + preferences += TextPreference("revanced_miniplayer_width_dip", inputType = InputType.NUMBER) + } + + preferences += TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER) + } SettingsPatch.PreferenceScreen.PLAYER.addPreferences( PreferenceScreen( key = "revanced_miniplayer_screen", sorting = Sorting.UNSORTED, - preferences = - if (isPatchingOldVersion) { - setOf( - ListPreference( - "revanced_miniplayer_type", - summaryKey = null, - entriesKey = "revanced_miniplayer_type_legacy_entries", - entryValuesKey = "revanced_miniplayer_type_legacy_entry_values" - ) - ) - } else { - setOf( - ListPreference( - "revanced_miniplayer_type", - summaryKey = null, - entriesKey = "revanced_miniplayer_type_19_15_entries", - entryValuesKey = "revanced_miniplayer_type_19_15_entry_values" - ), - SwitchPreference("revanced_miniplayer_hide_expand_close"), - SwitchPreference("revanced_miniplayer_hide_subtext"), - SwitchPreference("revanced_miniplayer_hide_rewind_forward"), - TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER) - ) - } + preferences = preferences ) ) // region Enable tablet miniplayer. - MiniplayerOverrideNoContextFingerprint.resolve( + MiniplayerOverrideNoContextFingerprint.alsoResolve( context, - MiniplayerDimensionsCalculatorParentFingerprint.resultOrThrow().classDef - ) - MiniplayerOverrideNoContextFingerprint.resultOrThrow().mutableMethod.apply { + MiniplayerDimensionsCalculatorParentFingerprint + ).mutableMethod.apply { findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) } } @@ -188,8 +214,8 @@ object MiniplayerPatch : BytecodePatch( it.mutableMethod.insertLegacyTabletMiniplayerOverride(it.scanResult.patternScanResult!!.endIndex) } - if (isPatchingOldVersion) { - // Return here, as patch below is only intended for new versions of the app. + if (!VersionCheckPatch.is_19_16_or_greater) { + // Return here, as patch below is only for the current versions of the app. return } @@ -212,59 +238,150 @@ object MiniplayerPatch : BytecodePatch( } } + if (VersionCheckPatch.is_19_23_or_greater) { + MiniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( + MiniplayerModernConstructorFingerprint.DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL, + "enableMiniplayerDragAndDrop" + ) + } + + if (VersionCheckPatch.is_19_25_or_greater) { + MiniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( + MiniplayerModernConstructorFingerprint.MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY, + "getModernMiniplayerOverride" + ) + + MiniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( + MiniplayerModernConstructorFingerprint.MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL, + "getModernFeatureFlagsActiveOverride" + ) + + MiniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( + MiniplayerModernConstructorFingerprint.DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL, + "enableMiniplayerDoubleTapAction" + ) + } + + if (VersionCheckPatch.is_19_26_or_greater) { + MiniplayerModernConstructorFingerprint.resultOrThrow().mutableMethod.apply { + val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow( + MiniplayerModernConstructorFingerprint.INITIAL_SIZE_FEATURE_KEY_LITERAL + ) + val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT) + + val register = getInstruction(targetIndex).registerA + + addInstructions( + targetIndex + 1, + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->setMiniplayerDefaultSize(I)I + move-result v$register + """ + ) + } + + // Override a mininimum miniplayer size constant. + MiniplayerMinimumSizeFingerprint.resultOrThrow().mutableMethod.apply { + val index = indexOfFirstInstructionOrThrow { + opcode == Opcode.CONST_16 && (this as NarrowLiteralInstruction).narrowLiteral == 192 + } + val register = getInstruction(index).registerA + + // Smaller sizes can be used, but the miniplayer will always start in size 170 if set any smaller. + // The 170 initial limit probably could be patched to allow even smaller initial sizes, + // but 170 is already half the horizontal space and smaller does not seem useful. + replaceInstruction(index, "const/16 v$register, 170") + } + } + + if (VersionCheckPatch.is_19_32_or_greater) { + // Feature is not exposed in the settings, and currently only for debugging. + + MiniplayerModernConstructorFingerprint.insertLiteralValueFloatOverride( + MiniplayerModernConstructorFingerprint.ANIMATION_INTERPOLATION_FEATURE_KEY, + "setMovementBoundFactor" + ) + } + + if (VersionCheckPatch.is_19_36_or_greater) { + MiniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( + MiniplayerModernConstructorFingerprint.DROP_SHADOW_FEATURE_KEY, + "setDropShadow" + ) + + MiniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( + MiniplayerModernConstructorFingerprint.ROUNDED_CORNERS_FEATURE_KEY, + "setRoundedCorners" + ) + } + // endregion // region Fix 19.16 using mixed up drawables for tablet modern. // YT fixed this mistake in 19.17. // Fix this, by swapping the drawable resource values with each other. - - MiniplayerModernExpandCloseDrawablesFingerprint.apply { - resolve( + if (ytOutlinePictureInPictureWhite24 >= 0) { + MiniplayerModernExpandCloseDrawablesFingerprint.alsoResolve( context, - MiniplayerModernViewParentFingerprint.resultOrThrow().classDef - ) - }.resultOrThrow().mutableMethod.apply { - listOf( - ytOutlinePictureInPictureWhite24 to ytOutlineXWhite24, - ytOutlineXWhite24 to ytOutlinePictureInPictureWhite24, - ).forEach { (originalResource, replacementResource) -> - val imageResourceIndex = indexOfFirstWideLiteralInstructionValueOrThrow(originalResource) - val register = getInstruction(imageResourceIndex).registerA - - replaceInstruction(imageResourceIndex, "const v$register, $replacementResource") + MiniplayerModernViewParentFingerprint + ).mutableMethod.apply { + listOf( + ytOutlinePictureInPictureWhite24 to ytOutlineXWhite24, + ytOutlineXWhite24 to ytOutlinePictureInPictureWhite24, + ).forEach { (originalResource, replacementResource) -> + val imageResourceIndex = indexOfFirstWideLiteralInstructionValueOrThrow(originalResource) + val register = getInstruction(imageResourceIndex).registerA + + replaceInstruction(imageResourceIndex, "const v$register, $replacementResource") + } } } // endregion - - // region Add hooks to hide tablet modern miniplayer buttons. + // region Add hooks to hide modern miniplayer buttons. listOf( - Triple(MiniplayerModernExpandButtonFingerprint, modernMiniplayerExpand,"hideMiniplayerExpandClose"), - Triple(MiniplayerModernCloseButtonFingerprint, modernMiniplayerClose, "hideMiniplayerExpandClose"), - Triple(MiniplayerModernRewindButtonFingerprint, modernMiniplayerRewindButton, "hideMiniplayerRewindForward"), - Triple(MiniplayerModernForwardButtonFingerprint, modernMiniplayerForwardButton, "hideMiniplayerRewindForward"), - Triple(MiniplayerModernOverlayViewFingerprint, scrimOverlay, "adjustMiniplayerOpacity") + Triple( + MiniplayerModernExpandButtonFingerprint, + modernMiniplayerExpand, + "hideMiniplayerExpandClose" + ), + Triple( + MiniplayerModernCloseButtonFingerprint, + modernMiniplayerClose, + "hideMiniplayerExpandClose" + ), + Triple( + MiniplayerModernRewindButtonFingerprint, + modernMiniplayerRewindButton, + "hideMiniplayerRewindForward" + ), + Triple( + MiniplayerModernForwardButtonFingerprint, + modernMiniplayerForwardButton, + "hideMiniplayerRewindForward" + ), + Triple( + MiniplayerModernOverlayViewFingerprint, + scrimOverlay, + "adjustMiniplayerOpacity" + ) ).forEach { (fingerprint, literalValue, methodName) -> - fingerprint.resolve( + fingerprint.alsoResolve( context, - MiniplayerModernViewParentFingerprint.resultOrThrow().classDef - ) - - fingerprint.hookInflatedView( + MiniplayerModernViewParentFingerprint + ).mutableMethod.hookInflatedView( literalValue, "Landroid/widget/ImageView;", "$INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V" ) } - MiniplayerModernAddViewListenerFingerprint.apply { - resolve( - context, - MiniplayerModernViewParentFingerprint.resultOrThrow().classDef - ) - }.resultOrThrow().mutableMethod.addInstruction( + MiniplayerModernAddViewListenerFingerprint.alsoResolve( + context, + MiniplayerModernViewParentFingerprint + ).mutableMethod.addInstruction( 0, "invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->" + "hideMiniplayerSubTexts(Landroid/view/View;)V" @@ -275,6 +392,9 @@ object MiniplayerPatch : BytecodePatch( // Modern 2 uses the same overlay controls as the regular video player, // and the overlay views are added at runtime. // Add a hook to the overlay class, and pass the added views to integrations. + // + // NOTE: Modern 2 uses the same video UI as the regular player except resized to smaller. + // This patch code could be used to hide other player overlays that do not use Litho. YouTubePlayerOverlaysLayoutFingerprint.resultOrThrow().mutableClass.methods.add( ImmutableMethod( YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME, @@ -319,6 +439,37 @@ object MiniplayerPatch : BytecodePatch( insertBooleanOverride(index, "getModernMiniplayerOverride") } + private fun MethodFingerprint.insertLiteralValueBooleanOverride( + literal: Long, + integrationsMethod: String + ) { + resultOrThrow().mutableMethod.apply { + val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow(literal) + val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT) + + insertBooleanOverride(targetIndex + 1, integrationsMethod) + } + } + + private fun MethodFingerprint.insertLiteralValueFloatOverride( + literal: Long, + integrationsMethod: String + ) { + resultOrThrow().mutableMethod.apply { + val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow(literal) + val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.DOUBLE_TO_FLOAT) + val register = getInstruction(targetIndex).registerA + + addInstructions( + targetIndex + 1, + """ + invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->$integrationsMethod(F)F + move-result v$register + """ + ) + } + } + private fun MutableMethod.insertBooleanOverride(index: Int, methodName: String) { val register = getInstruction(index).registerA addInstructions( @@ -335,36 +486,30 @@ object MiniplayerPatch : BytecodePatch( */ private fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) { val targetInstruction = getInstruction(iPutIndex) - val targetReference = (targetInstruction as ReferenceInstruction).reference - addInstructions( - iPutIndex + 1, """ + addInstructionsAtControlFlowLabel( + iPutIndex, """ invoke-static { v${targetInstruction.registerA} }, $INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I move-result v${targetInstruction.registerA} - # Original instruction - iput v${targetInstruction.registerA}, v${targetInstruction.registerB}, $targetReference """ ) - removeInstruction(iPutIndex) } - private fun LiteralValueFingerprint.hookInflatedView( + private fun MutableMethod.hookInflatedView( literalValue: Long, hookedClassType: String, integrationsMethodName: String, ) { - resultOrThrow().mutableMethod.apply { - val imageViewIndex = indexOfFirstInstructionOrThrow( - indexOfFirstWideLiteralInstructionValueOrThrow(literalValue) - ) { - opcode == Opcode.CHECK_CAST && getReference()?.type == hookedClassType - } - - val register = getInstruction(imageViewIndex).registerA - addInstruction( - imageViewIndex + 1, - "invoke-static { v$register }, $integrationsMethodName" - ) + val imageViewIndex = indexOfFirstInstructionOrThrow( + indexOfFirstWideLiteralInstructionValueOrThrow(literalValue) + ) { + opcode == Opcode.CHECK_CAST && getReference()?.type == hookedClassType } + + val register = getInstruction(imageViewIndex).registerA + addInstruction( + imageViewIndex + 1, + "invoke-static { v$register }, $integrationsMethodName" + ) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt index 3870f06544..1c8649c097 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt @@ -1,12 +1,12 @@ package app.revanced.patches.youtube.layout.miniplayer import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch -@Patch(dependencies = [ResourceMappingPatch::class]) +@Patch(dependencies = [ResourceMappingPatch::class, VersionCheckPatch::class]) internal object MiniplayerResourcePatch : ResourcePatch() { var floatyBarButtonTopMargin = -1L @@ -19,6 +19,7 @@ internal object MiniplayerResourcePatch : ResourcePatch() { var modernMiniplayerRewindButton = -1L var modernMiniplayerForwardButton = -1L var playerOverlays = -1L + var miniplayerMaxSize = -1L override fun execute(context: ResourceContext) { floatyBarButtonTopMargin = ResourceMappingPatch[ @@ -26,56 +27,63 @@ internal object MiniplayerResourcePatch : ResourcePatch() { "floaty_bar_button_top_margin" ] - try { - ytOutlinePictureInPictureWhite24 = ResourceMappingPatch[ - "drawable", - "yt_outline_picture_in_picture_white_24" - ] - } catch (exception: PatchException) { - // Ignore, and assume the app is 19.14 or earlier. - return - } - - ytOutlineXWhite24 = ResourceMappingPatch[ - "drawable", - "yt_outline_x_white_24" - ] - scrimOverlay = ResourceMappingPatch[ "id", "scrim_overlay" ] - modernMiniplayerClose = ResourceMappingPatch[ - "id", - "modern_miniplayer_close" + playerOverlays = ResourceMappingPatch[ + "layout", + "player_overlays" ] - modernMiniplayerExpand = ResourceMappingPatch[ - "id", - "modern_miniplayer_expand" - ] + if (VersionCheckPatch.is_19_16_or_greater) { + modernMiniplayerClose = ResourceMappingPatch[ + "id", + "modern_miniplayer_close" + ] - modernMiniplayerRewindButton = ResourceMappingPatch[ - "id", - "modern_miniplayer_rewind_button" - ] + modernMiniplayerExpand = ResourceMappingPatch[ + "id", + "modern_miniplayer_expand" + ] - modernMiniplayerForwardButton = ResourceMappingPatch[ - "id", - "modern_miniplayer_forward_button" - ] + modernMiniplayerRewindButton = ResourceMappingPatch[ + "id", + "modern_miniplayer_rewind_button" + ] - playerOverlays = ResourceMappingPatch[ - "layout", - "player_overlays" - ] + modernMiniplayerForwardButton = ResourceMappingPatch[ + "id", + "modern_miniplayer_forward_button" + ] - // Resource id is not used during patching, but is used by integrations. - // Verify the resource is present while patching. - ResourceMappingPatch[ - "id", - "modern_miniplayer_subtitle_text" - ] + // Resource id is not used during patching, but is used by integrations. + // Verify the resource is present while patching. + ResourceMappingPatch[ + "id", + "modern_miniplayer_subtitle_text" + ] + + // Only required for exactly 19.16 + if (!VersionCheckPatch.is_19_17_or_greater) { + ytOutlinePictureInPictureWhite24 = ResourceMappingPatch[ + "drawable", + "yt_outline_picture_in_picture_white_24" + ] + + ytOutlineXWhite24 = ResourceMappingPatch[ + "drawable", + "yt_outline_x_white_24" + ] + } + + if (VersionCheckPatch.is_19_26_or_greater) { + miniplayerMaxSize = ResourceMappingPatch[ + "dimen", + "miniplayer_max_size" + ] + } + } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerMinimumSizeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerMinimumSizeFingerprint.kt new file mode 100644 index 0000000000..134eaed429 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerMinimumSizeFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.layout.miniplayer.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch +import app.revanced.util.containsWideLiteralInstructionValue +import com.android.tools.smali.dexlib2.AccessFlags + +internal object MiniplayerMinimumSizeFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + customFingerprint = { methodDef, _ -> + methodDef.containsWideLiteralInstructionValue(192) + && methodDef.containsWideLiteralInstructionValue(128) + && methodDef.containsWideLiteralInstructionValue(MiniplayerResourcePatch.miniplayerMaxSize) + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt index 0afb5e5264..1b0c7096e2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt @@ -8,4 +8,14 @@ internal object MiniplayerModernConstructorFingerprint : LiteralValueFingerprint accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, parameters = listOf("L"), literalSupplier = { 45623000L } // Magic number found in the constructor. -) \ No newline at end of file +) { + const val MODERN_FEATURE_FLAGS_ENABLED_KEY_LITERAL = 45622882L + // In later targets this feature flag does nothing and is dead code. + const val MODERN_MINIPLAYER_ENABLED_OLD_TARGETS_FEATURE_KEY = 45630429L + const val DOUBLE_TAP_ENABLED_FEATURE_KEY_LITERAL = 45628823L + const val DRAG_DROP_ENABLED_FEATURE_KEY_LITERAL = 45628752L + const val INITIAL_SIZE_FEATURE_KEY_LITERAL = 45640023L + const val ANIMATION_INTERPOLATION_FEATURE_KEY = 45647018L + const val DROP_SHADOW_FEATURE_KEY = 45652223L + const val ROUNDED_CORNERS_FEATURE_KEY = 45652224L +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt index 9d9bf5e153..3a1fbfb43b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt @@ -7,6 +7,5 @@ import com.android.tools.smali.dexlib2.AccessFlags internal object MiniplayerOverrideFingerprint : MethodFingerprint( returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("L"), strings = listOf("appName") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt index c93d718f5b..5675204b13 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt @@ -19,30 +19,11 @@ import app.revanced.util.exception compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt index eec03ff01f..f67bdc9f98 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt @@ -14,30 +14,11 @@ import org.w3c.dom.Element CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt index 8e4556a008..9485bc3d24 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException @@ -27,11 +28,14 @@ import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.Tex import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint import app.revanced.patches.youtube.video.videoid.VideoIdPatch +import app.revanced.util.alsoResolve import app.revanced.util.exception import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.addInstructionsAtControlFlowLabel import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -51,27 +55,15 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference VideoIdPatch::class, ReturnYouTubeDislikeResourcePatch::class, PlayerTypeHookPatch::class, + VersionCheckPatch::class ], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] @@ -117,7 +109,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( DislikeFingerprint.toPatch(Vote.DISLIKE), RemoveLikeFingerprint.toPatch(Vote.REMOVE_LIKE) ).forEach { (fingerprint, vote) -> - fingerprint.result?.mutableMethod?.apply { + fingerprint.resultOrThrow().mutableMethod.apply { addInstructions( 0, """ @@ -125,7 +117,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->sendVote(I)V """ ) - } ?: throw fingerprint.exception + } } // endregion @@ -136,7 +128,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // And it works in all situations except it fails to update the Span when the user dislikes, // since the underlying (likes only) text did not change. // This hook handles all situations, as it's where the created Spans are stored and later reused. - TextComponentConstructorFingerprint.result?.let { textConstructorResult -> + TextComponentConstructorFingerprint.resultOrThrow().let { textConstructorResult -> // Find the field name of the conversion context. val conversionContextClassType = ConversionContextFingerprint.resultOrThrow().classDef.type val conversionContextField = textConstructorResult.classDef.fields.find { @@ -147,55 +139,80 @@ object ReturnYouTubeDislikePatch : BytecodePatch( TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply { // Find the instruction for creating the text data object. val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type - val insertIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.NEW_INSTANCE && - getReference()?.type == textDataClassType + + val insertIndex : Int + val tempRegister : Int + val charSequenceRegister : Int + + if (VersionCheckPatch.is_19_33_or_greater) { + insertIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_STATIC_RANGE && + getReference()?.returnType == textDataClassType + } + + tempRegister = getInstruction(insertIndex + 1).registerA + + // Find the instruction that sets the span to an instance field. + // The instruction is only a few lines after the creation of the instance. + charSequenceRegister = getInstruction( + indexOfFirstInstructionOrThrow(insertIndex) { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.parameterTypes?.firstOrNull() == "Ljava/lang/CharSequence;" + } + ).registerD + } else { + insertIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.NEW_INSTANCE && + getReference()?.type == textDataClassType + } + + tempRegister = getInstruction(insertIndex).registerA + + charSequenceRegister = getInstruction( + indexOfFirstInstructionOrThrow(insertIndex) { + opcode == Opcode.IPUT_OBJECT && + getReference()?.type == "Ljava/lang/CharSequence;" + } + ).registerA } - val tempRegister = getInstruction(insertIndex).registerA - - // Find the instruction that sets the span to an instance field. - // The instruction is only a few lines after the creation of the instance. - // The method has multiple iput-object instructions using a CharSequence, - // so verify the found instruction is in the expected location. - val putFieldInstruction = implementation!!.instructions - .subList(insertIndex, insertIndex + 20) - .find { - it.opcode == Opcode.IPUT_OBJECT && - it.getReference()?.type == "Ljava/lang/CharSequence;" - } ?: throw PatchException("Could not find put object instruction") - val charSequenceRegister = (putFieldInstruction as TwoRegisterInstruction).registerA - addInstructions( - insertIndex, + addInstructionsAtControlFlowLabel(insertIndex, + """ + # Copy conversion context + move-object/from16 v$tempRegister, p0 + iget-object v$tempRegister, v$tempRegister, $conversionContextField + invoke-static { v$tempRegister, v$charSequenceRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + move-result-object v$charSequenceRegister """ - # Copy conversion context - move-object/from16 v$tempRegister, p0 - iget-object v$tempRegister, v$tempRegister, $conversionContextField - invoke-static {v$tempRegister, v$charSequenceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; - move-result-object v$charSequenceRegister - """ ) } - } ?: throw TextComponentConstructorFingerprint.exception + } // endregion // region Hook for non-litho Short videos. - ShortsTextViewFingerprint.result?.let { + ShortsTextViewFingerprint.resultOrThrow().let { it.mutableMethod.apply { - val patternResult = it.scanResult.patternScanResult!! + val insertIndex = it.scanResult.patternScanResult!!.endIndex + 1 // If the field is true, the TextView is for a dislike button. - val isDisLikesBooleanReference = getInstruction(patternResult.endIndex).reference + val isDisLikesBooleanInstruction = getInstructions().first { instruction -> + instruction.opcode == Opcode.IGET_BOOLEAN + } as ReferenceInstruction + + val isDisLikesBooleanReference = isDisLikesBooleanInstruction.reference - val textViewFieldReference = // Like/Dislike button TextView field - getInstruction(patternResult.endIndex - 1).reference + // Like/Dislike button TextView field. + val textViewFieldInstruction = getInstructions().first { instruction -> + instruction.opcode == Opcode.IGET_OBJECT + } as ReferenceInstruction + + val textViewFieldReference = textViewFieldInstruction.reference // Check if the hooked TextView object is that of the dislike button. // If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted. // Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward. - val insertIndex = patternResult.startIndex + 6 addInstructionsWithLabels( insertIndex, """ @@ -216,7 +233,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( """ ) } - } ?: throw ShortsTextViewFingerprint.exception + } // endregion @@ -251,20 +268,14 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // region Hook rolling numbers. - // Do this last to allow patching old unsupported versions (if the user really wants), - // On older unsupported version this will fail to resolve and throw an exception, - // but everything will still work correctly anyways. - - RollingNumberSetterFingerprint.result?.let { + RollingNumberSetterFingerprint.resultOrThrow().let { val dislikesIndex = it.scanResult.patternScanResult!!.endIndex it.mutableMethod.apply { val insertIndex = 1 - val charSequenceInstanceRegister = - getInstruction(0).registerA - val charSequenceFieldReference = - getInstruction(dislikesIndex).reference + val charSequenceInstanceRegister = getInstruction(0).registerA + val charSequenceFieldReference = getInstruction(dislikesIndex).reference val registerCount = implementation!!.registerCount @@ -282,7 +293,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( """ ) } - } ?: throw RollingNumberSetterFingerprint.exception + } // Rolling Number text views use the measured width of the raw string for layout. // Modify the measure text calculation to include the left drawable separator if needed. @@ -306,9 +317,12 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // Additional text measurement method. Used if YouTube decides not to animate the likes count // and sometimes used for initial video load. - RollingNumberMeasureStaticLabelFingerprint.resolve(context, RollingNumberMeasureStaticLabelParentFingerprint.resultOrThrow().classDef) - RollingNumberMeasureStaticLabelFingerprint.result?.also { + RollingNumberMeasureStaticLabelFingerprint.alsoResolve( + context, + RollingNumberMeasureStaticLabelParentFingerprint + ).let { val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1 + it.mutableMethod.apply { val freeRegister = getInstruction(0).registerA @@ -320,19 +334,18 @@ object ReturnYouTubeDislikePatch : BytecodePatch( """ ) } - } ?: throw RollingNumberMeasureStaticLabelFingerprint.exception + } // The rolling number Span is missing styling since it's initially set as a String. // Modify the UI text view and use the styled like/dislike Span. - RollingNumberTextViewFingerprint.result?.let { + RollingNumberTextViewFingerprint.resultOrThrow().let { // Initial TextView is set in this method. val initiallyCreatedTextViewMethod = it.mutableMethod // Videos less than 24 hours after uploaded, like counts will be updated in real time. // Whenever like counts are updated, TextView is set in this method. val realTimeUpdateTextViewMethod = - RollingNumberTextViewAnimationUpdateFingerprint.result?.mutableMethod - ?: throw RollingNumberTextViewAnimationUpdateFingerprint.exception + RollingNumberTextViewAnimationUpdateFingerprint.resultOrThrow().mutableMethod arrayOf( initiallyCreatedTextViewMethod, @@ -357,7 +370,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( ) } } - } ?: throw RollingNumberTextViewFingerprint.exception + } // endregion diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt index 75b6eb55cc..92ff788295 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt @@ -10,9 +10,6 @@ internal object ConversionContextFingerprint : MethodFingerprint( ", heightConstraint=", ", templateLoggerFactory=", ", rootDisposableContainer=", - // 18.37.36 and after this String is: ConversionContext{containerInternal= - // and before it is: ConversionContext{container= - // Use a partial string to match both. - "ConversionContext{container" + "ConversionContext{containerInternal=" ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt index e79cf27292..57569b2709 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt @@ -8,5 +8,6 @@ internal object RollingNumberSetterFingerprint : MethodFingerprint( Opcode.INVOKE_DIRECT, Opcode.IGET_OBJECT ), - strings = listOf("RollingNumberType required properties missing! Need updateCount, fontName, color and fontSize.") + // Partial string match. + strings = listOf("RollingNumberType required properties missing! Need") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt index 54fe00865f..ba109ac54a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt @@ -18,6 +18,7 @@ internal object RollingNumberTextViewFingerprint : MethodFingerprint( Opcode.RETURN_VOID ), customFingerprint = { _, classDef -> - classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" + classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" || + classDef.superclass == "Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt index a326a6ced8..75ec556068 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt @@ -15,18 +15,6 @@ internal object ShortsTextViewFingerprint : MethodFingerprint( null, Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.SGET_OBJECT, // insertion point, must be after constructor call to parent class - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.CONST_4, - Opcode.IF_EQZ, - Opcode.CONST_4, - Opcode.IF_EQ, - Opcode.CONST_4, - Opcode.IF_EQ, - Opcode.RETURN_VOID, - Opcode.IGET_OBJECT, // TextView field - Opcode.IGET_BOOLEAN, // boolean field + Opcode.CHECK_CAST ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt index 2d70664030..6126fda655 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt @@ -9,8 +9,6 @@ internal object TextComponentDataFingerprint : MethodFingerprint( parameters = listOf("L", "L"), strings = listOf("text"), customFingerprint = { _, classDef -> - val fields = classDef.fields - fields.find { it.type == "Ljava/util/BitSet;" } != null && - fields.find { it.type == "[Ljava/lang/String;" } != null + classDef.fields.find { it.type == "Ljava/util/BitSet;" } != null } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt index c8a75eb11c..cc029b92c0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt @@ -24,29 +24,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt index bc5f29ff8e..0d4fa777e0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt @@ -18,6 +18,6 @@ internal object SetWordmarkHeaderFingerprint : MethodFingerprint( Opcode.IF_EQZ, Opcode.IGET_OBJECT, Opcode.CONST, - Opcode.INVOKE_STATIC, + null // invoke-static or invoke-virtual ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt index 3aecd97f07..c28aa2564b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt @@ -4,45 +4,28 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.seekbar.fingerprints.FullscreenSeekbarThumbnailsFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.util.exception @Patch( name = "Restore old seekbar thumbnails", description = "Adds an option to restore the old seekbar thumbnails that appear above the seekbar while seeking instead of fullscreen thumbnails.", - dependencies = [IntegrationsPatch::class, AddResourcesPatch::class], + dependencies = [IntegrationsPatch::class, AddResourcesPatch::class, VersionCheckPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", - "19.16.39", + "19.16.39" + // 19.17+ is not supported. ] ) ] @@ -55,6 +38,11 @@ object RestoreOldSeekbarThumbnailsPatch : BytecodePatch( "Lapp/revanced/integrations/youtube/patches/RestoreOldSeekbarThumbnailsPatch;" override fun execute(context: BytecodeContext) { + if (VersionCheckPatch.is_19_17_or_greater) { + // Give a more informative error, if the user has turned off version checks. + throw PatchException("'Restore old seekbar thumbnails' cannot be patched to any version after 19.16.39") + } + AddResourcesPatch(this::class) SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt index 08d3fa0274..8d3050c29f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt @@ -1,20 +1,26 @@ package app.revanced.patches.youtube.layout.seekbar import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.layout.seekbar.fingerprints.LithoLinearGradientFingerprint import app.revanced.patches.youtube.layout.seekbar.fingerprints.PlayerSeekbarColorFingerprint +import app.revanced.patches.youtube.layout.seekbar.fingerprints.PlayerSeekbarGradientConfigFingerprint import app.revanced.patches.youtube.layout.seekbar.fingerprints.SetSeekbarClickedColorFingerprint import app.revanced.patches.youtube.layout.seekbar.fingerprints.ShortsSeekbarColorFingerprint import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch.lithoColorOverrideHook import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch -import app.revanced.util.exception +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch +import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @@ -24,7 +30,13 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction compatiblePackages = [CompatiblePackage("com.google.android.youtube")] ) internal object SeekbarColorBytecodePatch : BytecodePatch( - setOf(PlayerSeekbarColorFingerprint, ShortsSeekbarColorFingerprint, SetSeekbarClickedColorFingerprint) + setOf( + PlayerSeekbarColorFingerprint, + ShortsSeekbarColorFingerprint, + SetSeekbarClickedColorFingerprint, + PlayerSeekbarGradientConfigFingerprint, + LithoLinearGradientFingerprint + ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/theme/SeekbarColorPatch;" @@ -32,25 +44,26 @@ internal object SeekbarColorBytecodePatch : BytecodePatch( fun MutableMethod.addColorChangeInstructions(resourceId: Long) { val registerIndex = indexOfFirstWideLiteralInstructionValueOrThrow(resourceId) + 2 val colorRegister = getInstruction(registerIndex).registerA + addInstructions( registerIndex + 1, """ - invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I - move-result v$colorRegister - """ + invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I + move-result v$colorRegister + """ ) } - PlayerSeekbarColorFingerprint.result?.mutableMethod?.apply { + PlayerSeekbarColorFingerprint.resultOrThrow().mutableMethod.apply { addColorChangeInstructions(SeekbarColorResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId) addColorChangeInstructions(SeekbarColorResourcePatch.inlineTimeBarPlayedNotHighlightedColorId) - } ?: throw PlayerSeekbarColorFingerprint.exception + } - ShortsSeekbarColorFingerprint.result?.mutableMethod?.apply { + ShortsSeekbarColorFingerprint.resultOrThrow().mutableMethod.apply { addColorChangeInstructions(SeekbarColorResourcePatch.reelTimeBarPlayedColorId) - } ?: throw ShortsSeekbarColorFingerprint.exception + } - SetSeekbarClickedColorFingerprint.result?.let { result -> + SetSeekbarClickedColorFingerprint.resultOrThrow().let { result -> result.mutableMethod.let { val setColorMethodIndex = result.scanResult.patternScanResult!!.startIndex + 1 val method = context @@ -69,7 +82,31 @@ internal object SeekbarColorBytecodePatch : BytecodePatch( ) } } - } ?: throw SetSeekbarClickedColorFingerprint.exception + } + + if (VersionCheckPatch.is_19_23_or_greater) { + PlayerSeekbarGradientConfigFingerprint.resultOrThrow().mutableMethod.apply { + val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow( + PlayerSeekbarGradientConfigFingerprint.PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG + ) + val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT) + val register = getInstruction(resultIndex).registerA + + addInstructions( + resultIndex + 1, + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z + move-result v$register + """ + ) + } + + LithoLinearGradientFingerprint.resultOrThrow().mutableMethod.apply { + addInstruction(0, "invoke-static/range { p4 .. p5 }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->setLinearGradient([I[F)V" + ) + } + } lithoColorOverrideHook(INTEGRATIONS_CLASS_DESCRIPTOR, "getLithoColor") } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/LithoLinearGradientFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/LithoLinearGradientFingerprint.kt new file mode 100644 index 0000000000..6185420bf2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/LithoLinearGradientFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.youtube.layout.seekbar.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object LithoLinearGradientFingerprint : MethodFingerprint( + accessFlags = AccessFlags.STATIC.value, + returnType = "Landroid/graphics/LinearGradient;", + parameters = listOf("F", "F", "F", "F", "[I", "[F"), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/PlayerSeekbarGradientConfigFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/PlayerSeekbarGradientConfigFingerprint.kt new file mode 100644 index 0000000000..2d7730fb52 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/PlayerSeekbarGradientConfigFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.seekbar.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.youtube.layout.seekbar.fingerprints.PlayerSeekbarGradientConfigFingerprint.PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object PlayerSeekbarGradientConfigFingerprint : LiteralValueFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "Z", + parameters = listOf(), + literalSupplier = { PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG }, +) { + const val PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG = 45617850L +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt index 85aad5fd01..ea99e000ee 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt @@ -23,13 +23,16 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarFingerprint import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch -import app.revanced.util.exception +import app.revanced.util.alsoResolve +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.StringReference @@ -41,24 +44,11 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference CompatiblePackage( "com.google.android.youtube", [ - "18.48.39", + "18.38.44", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], @@ -92,12 +82,6 @@ object SponsorBlockBytecodePatch : BytecodePatch( "Lapp/revanced/integrations/youtube/sponsorblock/ui/SponsorBlockViewController;" override fun execute(context: BytecodeContext) { - LayoutConstructorFingerprint.result?.let { - if (!ControlsOverlayFingerprint.resolve(context, it.classDef)) { - throw ControlsOverlayFingerprint.exception - } - } ?: throw LayoutConstructorFingerprint.exception - /* * Hook the video time methods */ @@ -108,67 +92,46 @@ object SponsorBlockBytecodePatch : BytecodePatch( ) } - /* - * Set current video id. - */ - VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") - - /* - * Seekbar drawing - */ - val seekbarSignatureResult = SeekbarFingerprint.result!!.let { - SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) } - }.result!! - val seekbarMethod = seekbarSignatureResult.mutableMethod - val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions - - /* - * Get left and right of seekbar rectangle - */ - val moveRectangleToRegisterIndex = seekbarMethodInstructions.indexOfFirst { - it.opcode == Opcode.MOVE_OBJECT_FROM16 - } - - seekbarMethod.addInstruction( - moveRectangleToRegisterIndex + 1, - "invoke-static/range {p0 .. p0}, " + - "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V", - ) - - for ((index, instruction) in seekbarMethodInstructions.withIndex()) { - if (instruction.opcode != Opcode.INVOKE_STATIC) continue + VideoIdPatch.hookBackgroundPlayVideoId( + "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") - val invokeInstruction = instruction as Instruction35c - if ((invokeInstruction.reference as MethodReference).name != "round") continue - val insertIndex = index + 2 + // Seekbar drawing + SeekbarOnDrawFingerprint.alsoResolve(context, SeekbarFingerprint).mutableMethod.apply { + // Get left and right of seekbar rectangle. + val moveRectangleToRegisterIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_OBJECT_FROM16) - // set the thickness of the segment - seekbarMethod.addInstruction( - insertIndex, - "invoke-static {v${invokeInstruction.registerC}}, " + - "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V", + addInstruction( + moveRectangleToRegisterIndex + 1, + "invoke-static/range { p0 .. p0 }, " + + "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V", ) - break - } - /* - * Draw segment - */ - // Find the drawCircle call and draw the segment before it - for (i in seekbarMethodInstructions.size - 1 downTo 0) { - val invokeInstruction = seekbarMethodInstructions[i] as? ReferenceInstruction ?: continue - if ((invokeInstruction.reference as MethodReference).name != "drawCircle") continue - - val (canvasInstance, centerY) = (invokeInstruction as FiveRegisterInstruction).let { - it.registerC to it.registerE + // Set the thickness of the segment. + val thicknessIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_STATIC && getReference()?.name == "round" } - seekbarMethod.addInstruction( - i, - "invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V", + val thicknessRegister = getInstruction(thicknessIndex).registerC + addInstruction( + thicknessIndex + 2, + "invoke-static { v$thicknessRegister }, " + + "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V", ) - break + // Find the drawCircle call and draw the segment before it. + val drawCircleIndex = indexOfFirstInstructionReversedOrThrow { + getReference()?.name == "drawCircle" + } + val drawCircleInstruction = getInstruction(drawCircleIndex) + val canvasInstanceRegister = drawCircleInstruction.registerC + val centerYRegister = drawCircleInstruction.registerE + + addInstruction( + drawCircleIndex, + "invoke-static { v$canvasInstanceRegister, v$centerYRegister }, " + + "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->" + + "drawSponsorTimeBars(Landroid/graphics/Canvas;F)V", + ) } // Change visibility of the buttons. @@ -179,24 +142,26 @@ object SponsorBlockBytecodePatch : BytecodePatch( PlayerControlsBytecodePatch.injectVisibilityCheckCall(INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR) // Append the new time to the player layout. - val appendTimeFingerprintResult = AppendTimeFingerprint.result!! - val appendTimePatternScanStartIndex = appendTimeFingerprintResult.scanResult.patternScanResult!!.startIndex - val targetRegister = - (appendTimeFingerprintResult.method.implementation!!.instructions.elementAt(appendTimePatternScanStartIndex + 1) as OneRegisterInstruction).registerA - - appendTimeFingerprintResult.mutableMethod.addInstructions( - appendTimePatternScanStartIndex + 2, - """ - invoke-static {v$targetRegister}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$targetRegister - """, - ) + AppendTimeFingerprint.resultOrThrow().let { + val appendTimePatternScanStartIndex = it.scanResult.patternScanResult!!.startIndex + it.mutableMethod.apply { + val register = getInstruction(appendTimePatternScanStartIndex + 1).registerA + + addInstructions( + appendTimePatternScanStartIndex + 2, + """ + invoke-static { v$register }, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$register + """ + ) + } + } - // initialize the player controller + // Initialize the player controller. VideoInformationPatch.onCreateHook(INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR, "initialize") - // initialize the sponsorblock view - ControlsOverlayFingerprint.result?.let { + // Initialize the SponsorBlock view. + ControlsOverlayFingerprint.alsoResolve(context, LayoutConstructorFingerprint).let { val startIndex = it.scanResult.patternScanResult!!.startIndex it.mutableMethod.apply { val frameLayoutRegister = (getInstruction(startIndex + 2) as OneRegisterInstruction).registerA @@ -205,53 +170,50 @@ object SponsorBlockBytecodePatch : BytecodePatch( "invoke-static {v$frameLayoutRegister}, $INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/ViewGroup;)V", ) } - } ?: throw ControlsOverlayFingerprint.exception - - // get rectangle field name - RectangleFieldInvalidatorFingerprint.resolve(context, seekbarSignatureResult.classDef) - val rectangleFieldInvalidatorInstructions = - RectangleFieldInvalidatorFingerprint.result!!.method.implementation!!.instructions - val rectangleFieldName = - ((rectangleFieldInvalidatorInstructions.elementAt(rectangleFieldInvalidatorInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name + } - // replace the "replaceMeWith*" strings - context - .proxy(context.classes.first { it.type.endsWith("SegmentPlaybackController;") }) - .mutableClass - .methods - .find { it.name == "setSponsorBarRect" } - ?.let { method -> - fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { - val register = (instruction as OneRegisterInstruction).registerA - this.replaceInstruction( - index, - "const-string v$register, \"$with\"", - ) - } - for ((index, it) in method.implementation!!.instructions.withIndex()) { - if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue - when (((it as ReferenceInstruction).reference as StringReference).string) { - "replaceMeWithsetSponsorBarRect" -> method.replaceStringInstruction( + // Set seekbar draw rectangle. + RectangleFieldInvalidatorFingerprint.alsoResolve(context, SeekbarOnDrawFingerprint).mutableMethod.apply { + val fieldIndex = implementation!!.instructions.count() - 3 + val fieldReference = getInstruction(fieldIndex).reference as FieldReference + + // replace the "replaceMeWith*" strings + context + .proxy(context.classes.first { it.type.endsWith("SegmentPlaybackController;") }) + .mutableClass + .methods + .find { it.name == "setSponsorBarRect" } + ?.let { method -> + fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { + val register = (instruction as OneRegisterInstruction).registerA + this.replaceInstruction( index, - it, - rectangleFieldName, + "const-string v$register, \"$with\"", ) } - } - } ?: throw PatchException("Could not find the method which contains the replaceMeWith* strings") + for ((index, it) in method.implementation!!.instructions.withIndex()) { + if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue + + when (((it as ReferenceInstruction).reference as StringReference).string) { + "replaceMeWithsetSponsorBarRect" -> method.replaceStringInstruction( + index, + it, + fieldReference.name, + ) + } + } + } ?: throw PatchException("Could not find the method which contains the replaceMeWith* strings") + } // The vote and create segment buttons automatically change their visibility when appropriate, // but if buttons are showing when the end of the video is reached then they will not automatically hide. // Add a hook to forcefully hide when the end of the video is reached. - AutoRepeatParentFingerprint.result ?: throw AutoRepeatParentFingerprint.exception - AutoRepeatFingerprint.also { - it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef) - }.result?.mutableMethod?.addInstruction( + AutoRepeatFingerprint.alsoResolve(context, AutoRepeatParentFingerprint).mutableMethod.addInstruction( 0, "invoke-static {}, $INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->endOfVideoReached()V", - ) ?: throw AutoRepeatFingerprint.exception + ) - // TODO: isSBChannelWhitelisting implementation + // TODO: isSBChannelWhitelisting implementation? } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt index a4aa0f38de..df2fcf9c64 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt @@ -22,30 +22,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt index e4f42397e4..d58e772f18 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt @@ -2,30 +2,47 @@ package app.revanced.patches.youtube.layout.startpage import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.ListPreference -import app.revanced.patches.youtube.layout.startpage.fingerprints.StartActivityFingerprint +import app.revanced.patches.youtube.layout.startpage.fingerprints.BrowseIdFingerprint +import app.revanced.patches.youtube.layout.startpage.fingerprints.IntentActionFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.patches.youtube.shared.fingerprints.HomeActivityFingerprint -import app.revanced.util.exception +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.StringReference @Patch( name = "Change start page", description = "Adds an option to set which page the app opens in instead of the homepage.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], + dependencies = [ + IntegrationsPatch::class, + SettingsPatch::class, + AddResourcesPatch::class + ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube" + "com.google.android.youtube", + [ + "18.38.44", + "18.49.37", + "19.16.39", + "19.25.37", + "19.34.42", + ] ) ] ) @Suppress("unused") object ChangeStartPagePatch : BytecodePatch( - setOf(HomeActivityFingerprint) + setOf(BrowseIdFingerprint, IntentActionFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/ChangeStartPagePatch;" @@ -35,19 +52,31 @@ object ChangeStartPagePatch : BytecodePatch( SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( ListPreference( - key = "revanced_start_page", + key = "revanced_change_start_page", summaryKey = null, ) ) - StartActivityFingerprint.resolve( - context, - HomeActivityFingerprint.result?.classDef ?: throw HomeActivityFingerprint.exception - ) + // Hook browseId. + BrowseIdFingerprint.resultOrThrow().mutableMethod.apply { + val browseIdIndex = indexOfFirstInstructionOrThrow { + getReference()?.string == "FEwhat_to_watch" + } + val browseIdRegister = getInstruction(browseIdIndex).registerA + + addInstructions( + browseIdIndex + 1, """ + invoke-static { v$browseIdRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideBrowseId(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$browseIdRegister + """ + ) + } - StartActivityFingerprint.result?.mutableMethod?.addInstruction( + // There is no browserId assigned to Shorts and Search. + // Just hook the Intent action. + IntentActionFingerprint.resultOrThrow().mutableMethod.addInstruction( 0, - "invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->changeIntent(Landroid/content/Intent;)V" - ) ?: throw StartActivityFingerprint.exception + "invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideIntentAction(Landroid/content/Intent;)V" + ) } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/BrowseIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/BrowseIdFingerprint.kt new file mode 100644 index 0000000000..f3fc189f3e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/BrowseIdFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.startpage.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object BrowseIdFingerprint : MethodFingerprint( + returnType = "Lcom/google/android/apps/youtube/app/common/ui/navigation/PaneDescriptor;", + parameters = listOf(), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT, + ), + strings = listOf("FEwhat_to_watch") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/StartActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/IntentActionFingerprint.kt similarity index 63% rename from src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/StartActivityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/IntentActionFingerprint.kt index 7461872181..86c227c29e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/StartActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/fingerprints/IntentActionFingerprint.kt @@ -2,6 +2,7 @@ package app.revanced.patches.youtube.layout.startpage.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint -object StartActivityFingerprint : MethodFingerprint( +internal object IntentActionFingerprint : MethodFingerprint( parameters = listOf("Landroid/content/Intent;"), + strings = listOf("has_handled_intent"), ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt index 3030214399..389c2a1cb9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt @@ -3,20 +3,22 @@ package app.revanced.patches.youtube.layout.startupshortsreset import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.youtube.layout.startupshortsreset.fingerprints.UserWasInShortsConfigFingerprint +import app.revanced.patches.youtube.layout.startupshortsreset.fingerprints.UserWasInShortsConfigFingerprint.indexOfOptionalInstruction import app.revanced.patches.youtube.layout.startupshortsreset.fingerprints.UserWasInShortsFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.util.exception +import app.revanced.util.addInstructionsAtControlFlowLabel import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference @@ -27,37 +29,18 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] ) @Suppress("unused") object DisableResumingShortsOnStartupPatch : BytecodePatch( - setOf(UserWasInShortsFingerprint) + setOf(UserWasInShortsConfigFingerprint, UserWasInShortsFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = @@ -70,30 +53,54 @@ object DisableResumingShortsOnStartupPatch : BytecodePatch( SwitchPreference("revanced_disable_resuming_shorts_player") ) - UserWasInShortsFingerprint.result?.mutableMethod?.apply { + UserWasInShortsConfigFingerprint.resultOrThrow().mutableMethod.apply { + val startIndex = indexOfOptionalInstruction(this) + val walkerIndex = indexOfFirstInstructionOrThrow(startIndex) { + val reference = getReference() + opcode == Opcode.INVOKE_VIRTUAL + && reference?.returnType == "Z" + && reference.definingClass != "Lj${'$'}/util/Optional;" + && reference.parameterTypes.size == 0 + } + + val walkerMethod = context.toMethodWalker(this) + .nextMethod(walkerIndex, true) + .getMethod() as MutableMethod + + // Presumably a method that processes the ProtoDataStore value (boolean) for the 'user_was_in_shorts' key. + walkerMethod.addInstructionsWithLabels( + 0, + """ + invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z + move-result v0 + if-eqz v0, :show + const/4 v0, 0x0 + return v0 + :show + nop + """ + ) + } + + UserWasInShortsFingerprint.resultOrThrow().mutableMethod.apply { val listenableInstructionIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_INTERFACE && getReference()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && getReference()?.name == "isDone" } - val originalInstructionRegister = getInstruction(listenableInstructionIndex).registerC val freeRegister = getInstruction(listenableInstructionIndex + 1).registerA - // Replace original instruction to preserve control flow label. - replaceInstruction( + addInstructionsAtControlFlowLabel( listenableInstructionIndex, - "invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z" - ) - addInstructionsWithLabels( - listenableInstructionIndex + 1, """ + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z move-result v$freeRegister if-eqz v$freeRegister, :show_startup_shorts_player return-void :show_startup_shorts_player - invoke-interface {v$originalInstructionRegister}, Lcom/google/common/util/concurrent/ListenableFuture;->isDone()Z + nop """ ) - } ?: throw UserWasInShortsFingerprint.exception + } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsConfigFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsConfigFingerprint.kt new file mode 100644 index 0000000000..21bf07c246 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsConfigFingerprint.kt @@ -0,0 +1,35 @@ +package app.revanced.patches.youtube.layout.startupshortsreset.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.youtube.layout.startupshortsreset.fingerprints.UserWasInShortsConfigFingerprint.indexOfOptionalInstruction +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference +import com.android.tools.smali.dexlib2.util.MethodUtil + +/** + * 18.15.40+ + */ +internal object UserWasInShortsConfigFingerprint : MethodFingerprint( + returnType = "V", + strings = listOf("Failed to get offline response: "), + customFingerprint = { methodDef, _ -> + indexOfOptionalInstruction(methodDef) >= 0 + } +) { + private val optionalOfMethodReference = ImmutableMethodReference( + "Lj${'$'}/util/Optional;", + "of", + listOf("Ljava/lang/Object;"), + "Lj${'$'}/util/Optional;", + ) + + fun indexOfOptionalInstruction(methodDef: Method) = + methodDef.indexOfFirstInstruction { + val reference = getReference() ?: return@indexOfFirstInstruction false + + MethodUtil.methodSignaturesMatch(reference, optionalOfMethodReference) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt index 8b41fc5dfc..d5c3aed445 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt @@ -26,30 +26,11 @@ import app.revanced.util.resultOrThrow compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", arrayOf( - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", - "19.16.39" + "19.16.39", + "19.25.37", + "19.34.42", ) ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt index 23d7a62fdd..eb476cf337 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt @@ -35,29 +35,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt index 80cff8a722..98606ab8c5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt @@ -11,6 +11,7 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.layout.theme.ThemeBytecodePatch.darkThemeBackgroundColor import app.revanced.patches.youtube.layout.theme.ThemeBytecodePatch.lightThemeBackgroundColor +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import org.w3c.dom.Element @@ -19,6 +20,7 @@ import org.w3c.dom.Element SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class, + VersionCheckPatch::class, ], ) internal object ThemeResourcePatch : ResourcePatch() { @@ -89,12 +91,35 @@ internal object ThemeResourcePatch : ResourcePatch() { return@editSplashScreen } } + throw PatchException("Failed to modify launch screen") } } + + // Fix the splash screen dark mode background color. + // In earlier versions of the app this is white and makes no sense for dark mode. + // This is only required for 19.32 and greater, but is applied to all targets. + // Only dark mode needs this fix as light mode correctly uses the custom color. + context.xmlEditor["res/values-night/styles.xml"].use { editor -> + val document = editor.file + + // Create a night mode specific override for the splash screen background. + val style = document.createElement("style") + style.setAttribute("name", "Theme.YouTube.Home") + style.setAttribute("parent", "@style/Base.V23.Theme.YouTube.Home") + + val windowItem = document.createElement("item") + windowItem.setAttribute("name", "android:windowBackground") + windowItem.textContent = "@color/$SPLASH_BACKGROUND_COLOR" + style.appendChild(windowItem) + + val resourcesNode = document.getElementsByTagName("resources").item(0) as Element + resourcesNode.appendChild(style) + } } } + @Suppress("SameParameterValue") private fun addColorResource( context: ResourceContext, resourceFile: String, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt index 095d567c72..f4088bbcae 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt @@ -28,30 +28,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/BypassImageRegionRestrictions.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/BypassImageRegionRestrictions.kt index d1d9dd39e1..8ca354b88f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/BypassImageRegionRestrictions.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/BypassImageRegionRestrictions.kt @@ -24,30 +24,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt index 1db64983dc..a9521378fd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt @@ -23,30 +23,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt index 97fc73d662..c639abb5e8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.youtube.misc.backgroundplayback import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch @@ -14,7 +15,11 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.video.information.VideoInformationPatch +import app.revanced.util.addInstructionsAtControlFlowLabel +import app.revanced.util.findOpcodeIndicesReversed import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference @@ -32,24 +37,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference CompatiblePackage( "com.google.android.youtube", [ - "18.48.39", + "18.38.44", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] @@ -66,14 +58,19 @@ object BackgroundPlaybackPatch : BytecodePatch( "Lapp/revanced/integrations/youtube/patches/BackgroundPlaybackPatch;" override fun execute(context: BytecodeContext) { - BackgroundPlaybackManagerFingerprint.resultOrThrow().mutableMethod.addInstructions( - 0, - """ - invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackIsNotShort()Z - move-result v0 - return v0 - """ - ) + BackgroundPlaybackManagerFingerprint.resultOrThrow().mutableMethod.apply { + findOpcodeIndicesReversed(Opcode.RETURN).forEach{ index -> + val register = getInstruction(index).registerA + + addInstructionsAtControlFlowLabel( + index, + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->allowBackgroundPlayback(Z)Z + move-result v$register + """ + ) + } + } // Enable background playback option in YouTube settings BackgroundPlaybackSettingsFingerprint.resultOrThrow().mutableMethod.apply { diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt index 7f33326c5f..11040d5e18 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt @@ -17,13 +17,7 @@ internal object KidsBackgroundPlaybackPolicyControllerFingerprint : LiteralValue Opcode.IGET, Opcode.CONST_4, Opcode.IF_NE, - Opcode.IGET_OBJECT, - Opcode.SGET_OBJECT, - Opcode.IF_EQ, - Opcode.GOTO, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID + Opcode.IGET_OBJECT ), literalSupplier = { 5 }, ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt index 70e1978e76..3c3e2c45ab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt @@ -21,27 +21,10 @@ import app.revanced.util.exception "com.google.android.youtube", [ "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt index 7d24b10862..d816f24a68 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt @@ -18,30 +18,11 @@ import app.revanced.util.resultOrThrow CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", "18.38.44", - "18.43.45", - "18.44.41", - "18.45.43", - "18.48.39", "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", "19.16.39", + "19.25.37", + "19.34.42", ], ), ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/DisableCairoSettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/DisableCairoSettingsPatch.kt new file mode 100644 index 0000000000..b936d7bf91 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/DisableCairoSettingsPatch.kt @@ -0,0 +1,56 @@ +package app.revanced.patches.youtube.misc.fix.cairo + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackPatch +import app.revanced.patches.youtube.misc.fix.cairo.fingerprints.CarioFragmentConfigFingerprint +import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction + +@Patch( + description = "Disables Cairo Fragment from being used.", + dependencies = [ + VersionCheckPatch::class + ] +) +internal object DisableCairoSettingsPatch : BytecodePatch( + setOf(CarioFragmentConfigFingerprint) +) { + override fun execute(context: BytecodeContext) { + if (!VersionCheckPatch.is_19_04_or_greater) { + return + } + + /** + *
+         * Cairo Fragment was added since YouTube v19.04.38.
+         *
+         * Disable this for the following reasons:
+         * 1. [BackgroundPlaybackPatch] does not activate the Minimized playback setting of Cairo Fragment.
+         * 2. Some patches do not yet support Cairo Fragments (ie: custom Seekbar color).
+         * 3. Settings preferences added by ReVanced are missing.
+         *
+         * Screenshots of the Cairo Fragment:
+         * uYouPlus#1468.
+         */
+        CarioFragmentConfigFingerprint.resultOrThrow().mutableMethod.apply {
+            val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow(
+                CarioFragmentConfigFingerprint.CAIRO_CONFIG_LITERAL_VALUE
+            )
+            val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
+            val register = getInstruction(resultIndex).registerA
+
+            addInstruction(
+                resultIndex + 1,
+                "const/16 v$register, 0x0"
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/fingerprints/CarioFragmentConfigFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/fingerprints/CarioFragmentConfigFingerprint.kt
new file mode 100644
index 0000000000..fc24be05c2
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/cairo/fingerprints/CarioFragmentConfigFingerprint.kt
@@ -0,0 +1,20 @@
+package app.revanced.patches.youtube.misc.fix.cairo.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.misc.fix.cairo.fingerprints.CarioFragmentConfigFingerprint.CAIRO_CONFIG_LITERAL_VALUE
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Added in YouTube v19.04.38
+ *
+ * When this value is TRUE, Cairo Fragment is used.
+ * In this case, some of patches may be broken, so set this value to FALSE.
+ */
+internal object CarioFragmentConfigFingerprint : LiteralValueFingerprint(
+    returnType = "Z",
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    literalSupplier = { CAIRO_CONFIG_LITERAL_VALUE }
+) {
+  const val CAIRO_CONFIG_LITERAL_VALUE = 45532100L
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt
index ffb7aaf675..f97553fc87 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt
@@ -49,29 +49,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
         CompatiblePackage(
             "com.google.android.youtube",
             [
-                "18.37.36",
                 "18.38.44",
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ],
         ),
     ],
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt
index e74a3d11eb..e66efc9c60 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.gms
 import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint
 import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
 import app.revanced.patches.youtube.layout.buttons.cast.HideCastButtonPatch
-import app.revanced.patches.youtube.misc.fix.playback.SpoofClientPatch
+import app.revanced.patches.youtube.misc.fix.playback.SpoofVideoStreamsPatch
 import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME
 import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
 import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
@@ -25,36 +25,18 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
     integrationsPatchDependency = IntegrationsPatch::class,
     dependencies = setOf(
         HideCastButtonPatch::class,
-        SpoofClientPatch::class,
+        SpoofVideoStreamsPatch::class,
     ),
     gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
     compatiblePackages = setOf(
         CompatiblePackage(
             "com.google.android.youtube",
             setOf(
-                "18.37.36",
                 "18.38.44",
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ),
         ),
     ),
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook.kt
index d85b5f6a1b..84e1c061c2 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook.kt
@@ -97,9 +97,8 @@ object CronetImageUrlHook : BytecodePatch(
         // The URL is required for the failure callback hook, but the URL field is obfuscated.
         // Add a helper get method that returns the URL field.
         RequestFingerprint.resultOrThrow().apply {
-            // The url is the only string field that is set inside the constructor.
-            val urlFieldInstruction = mutableMethod.getInstructions().single {
-                if (it.opcode != Opcode.IPUT_OBJECT) return@single false
+            val urlFieldInstruction = mutableMethod.getInstructions().first {
+                if (it.opcode != Opcode.IPUT_OBJECT) return@first false
 
                 val reference = (it as ReferenceInstruction).reference as FieldReference
                 reference.type == "Ljava/lang/String;"
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt
index ed161b2540..1c426f6cd1 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt
@@ -2,17 +2,11 @@ package app.revanced.patches.youtube.misc.integrations
 
 import app.revanced.patcher.patch.annotation.Patch
 import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
-import app.revanced.patches.youtube.misc.integrations.fingerprints.*
+import app.revanced.patches.youtube.misc.integrations.fingerprints.ApplicationInitFingerprint
 
 @Patch(requiresIntegrations = true)
 object IntegrationsPatch : BaseIntegrationsPatch(
     setOf(
         ApplicationInitFingerprint,
-        StandalonePlayerActivityFingerprint,
-        RemoteEmbeddedPlayerFingerprint,
-        RemoteEmbedFragmentFingerprint,
-        EmbeddedPlayerControlsOverlayFingerprint,
-        EmbeddedPlayerFingerprint,
-        APIPlayerServiceFingerprint,
     ),
 )
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt
deleted file mode 100644
index ca4ad846e6..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package app.revanced.patches.youtube.misc.integrations.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-
-/**
- * For embedded playback.
- * It appears this hook may no longer be needed as one of the constructor parameters is the already hooked
- * [EmbeddedPlayerControlsOverlayFingerprint]
- */
-internal object APIPlayerServiceFingerprint : IntegrationsFingerprint(
-    accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
-    customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/google/android/apps/youtube/embeddedplayer/service/service/jar/ApiPlayerService;" },
-    // Integrations context is the first method parameter.
-    contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt
deleted file mode 100644
index 1b57540675..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package app.revanced.patches.youtube.misc.integrations.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-
-/**
- * For embedded playback inside Google Play store (and probably other situations as well).
- *
- * Note: this fingerprint may no longer be needed, as it appears
- * [RemoteEmbedFragmentFingerprint] may be set before this hook is called.
- */
-internal object EmbeddedPlayerControlsOverlayFingerprint : IntegrationsFingerprint(
-    accessFlags = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR,
-    returnType = "V",
-    parameters = listOf("Landroid/content/Context;", "L", "L"),
-    customFingerprint = { methodDef, _ ->
-        methodDef.definingClass.startsWith("Lcom/google/android/apps/youtube/embeddedplayer/service/ui/overlays/controlsoverlay/remoteloaded/")
-    },
-    // Integrations context is the first method parameter.
-    contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt
deleted file mode 100644
index fbc2ab0dbf..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package app.revanced.patches.youtube.misc.integrations.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-
-/**
- * For embedded playback inside the Google app (such as the in app 'discover' tab).
- *
- * Note: this fingerprint may or may not be needed, as
- * [RemoteEmbedFragmentFingerprint] might be set before this is called.
- */
-internal object EmbeddedPlayerFingerprint : IntegrationsFingerprint(
-    accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
-    returnType = "L",
-    parameters = listOf("L", "L", "Landroid/content/Context;"),
-    strings = listOf("android.hardware.type.television"), // String is also found in other classes
-    // Integrations context is the third method parameter.
-    contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size + 2 }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt
deleted file mode 100644
index 77eeec32dc..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package app.revanced.patches.youtube.misc.integrations.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-
-/**
- * For embedded playback.  Likely covers Google Play store and other Google products.
- */
-internal object RemoteEmbedFragmentFingerprint : IntegrationsFingerprint(
-    accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
-    returnType = "V",
-    parameters = listOf("Landroid/content/Context;", "L", "L"),
-    customFingerprint = { methodDef, _ ->
-        methodDef.definingClass == "Lcom/google/android/apps/youtube/embeddedplayer/service/jar/client/RemoteEmbedFragment;"
-    },
-    // Integrations context is the first method parameter.
-    contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt
deleted file mode 100644
index 196994f49b..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package app.revanced.patches.youtube.misc.integrations.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-
-/**
- * For embedded playback inside 3rd party android app (such as 3rd party Reddit apps).
- */
-internal object RemoteEmbeddedPlayerFingerprint : IntegrationsFingerprint(
-    accessFlags = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR,
-    returnType = "V",
-    parameters = listOf("Landroid/content/Context;", "L", "L", "Z"),
-    customFingerprint = { methodDef, _ ->
-        methodDef.definingClass == "Lcom/google/android/youtube/api/jar/client/RemoteEmbeddedPlayer;"
-    },
-    // Integrations context is the first method parameter.
-    contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt
deleted file mode 100644
index 9148f5fdb5..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package app.revanced.patches.youtube.misc.integrations.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-
-/**
- * Old API activity to embed YouTube into 3rd party Android apps.
- *
- * In 2023 supported was ended and is no longer available,
- * but this may still be used by older apps:
- * https://developers.google.com/youtube/android/player
- */
-internal object StandalonePlayerActivityFingerprint : IntegrationsFingerprint(
-    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
-    returnType = "V",
-    parameters = listOf("L"),
-    customFingerprint = { methodDef, _ ->
-        methodDef.definingClass == "Lcom/google/android/youtube/api/StandalonePlayerActivity;"
-                && methodDef.name == "onCreate"
-    },
-    // Integrations context is the Activity itself.
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt
index 451f7742e7..71052a3f3c 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt
@@ -10,47 +10,48 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch
 import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.misc.links.fingerprints.ABUriParserFingerprint
+import app.revanced.patches.youtube.misc.links.fingerprints.ABUriParserLegacyFingerprint
 import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint
+import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserLegacyFingerprint
+import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch
 import app.revanced.patches.youtube.misc.settings.SettingsPatch
+import app.revanced.util.getReference
+import app.revanced.util.indexOfFirstInstruction
 import app.revanced.util.resultOrThrow
+import com.android.tools.smali.dexlib2.iface.Method
 import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
+import com.android.tools.smali.dexlib2.iface.reference.MethodReference
 
 @Patch(
     name = "Bypass URL redirects",
     description = "Adds an option to bypass URL redirects and open the original URL directly.",
-    dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
+    dependencies = [
+        IntegrationsPatch::class,
+        SettingsPatch::class,
+        AddResourcesPatch::class,
+        VersionCheckPatch::class
+   ],
     compatiblePackages = [
         CompatiblePackage(
             "com.google.android.youtube",
             [
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
+                "18.38.44",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ],
         ),
     ],
 )
 @Suppress("unused")
 object BypassURLRedirectsPatch : BytecodePatch(
-    setOf(ABUriParserFingerprint, HTTPUriParserFingerprint),
+    setOf(
+        ABUriParserFingerprint,
+        ABUriParserLegacyFingerprint,
+        HTTPUriParserFingerprint,
+        HTTPUriParserLegacyFingerprint,
+    ),
 ) {
     override fun execute(context: BytecodeContext) {
         AddResourcesPatch(this::class)
@@ -59,24 +60,39 @@ object BypassURLRedirectsPatch : BytecodePatch(
             SwitchPreference("revanced_bypass_url_redirects"),
         )
 
-        mapOf(
-            ABUriParserFingerprint to 7, // Offset to Uri.parse.
-            HTTPUriParserFingerprint to 0, // Offset to Uri.parse.
-        ).map { (fingerprint, offset) ->
-            fingerprint.resultOrThrow() to offset
-        }.forEach { (result, offset) ->
-            result.mutableMethod.apply {
-                val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset
-                val uriStringRegister = getInstruction(insertIndex).registerC
-
-                replaceInstruction(
-                    insertIndex,
-                    "invoke-static {v$uriStringRegister}," +
-                        "Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" +
-                        "->" +
-                        "parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;",
+        val fingerprints =
+            if (VersionCheckPatch.is_19_33_or_greater)
+                arrayOf(
+                    ABUriParserFingerprint,
+                    HTTPUriParserFingerprint
                 )
+            else arrayOf(
+                ABUriParserLegacyFingerprint,
+                HTTPUriParserLegacyFingerprint
+            )
+
+        fingerprints.forEach { fingerprint ->
+            fingerprint.resultOrThrow().let {
+                it.mutableMethod.apply {
+                    val insertIndex = findUriParseIndex()
+
+                    val uriStringRegister = getInstruction(insertIndex).registerC
+
+                    replaceInstruction(
+                        insertIndex,
+                        "invoke-static {v$uriStringRegister}," +
+                                "Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" +
+                                "->" +
+                                "parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;",
+                    )
+                }
             }
         }
     }
+
+    internal fun Method.findUriParseIndex(): Int = indexOfFirstInstruction {
+        val reference = getReference()
+        reference?.returnType == "Landroid/net/Uri;" &&
+                reference.name == "parse"
+    }
 }
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt
index 97367d6c1b..a19ff03cec 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt
@@ -24,30 +24,11 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
         CompatiblePackage(
             "com.google.android.youtube",
             [
-                "18.32.39",
-                "18.37.36",
                 "18.38.44",
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ]
         )
     ]
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt
index c2b3aa1d66..f5766ae30f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt
@@ -2,32 +2,21 @@ package app.revanced.patches.youtube.misc.links.fingerprints
 
 import app.revanced.patcher.extensions.or
 import app.revanced.patcher.fingerprint.MethodFingerprint
+import app.revanced.patches.youtube.misc.links.BypassURLRedirectsPatch.findUriParseIndex
 import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.Opcode
 
+/**
+ * Target 19.33+
+ */
 internal object ABUriParserFingerprint : MethodFingerprint(
     returnType = "Ljava/lang/Object",
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     parameters = listOf("Ljava/lang/Object"),
-    opcodes = listOf(
-        Opcode.RETURN_OBJECT,
-        Opcode.CHECK_CAST,
-        Opcode.INVOKE_VIRTUAL,
-        Opcode.MOVE_RESULT_OBJECT,
-        Opcode.CHECK_CAST,
-        Opcode.RETURN_OBJECT,
-        Opcode.CHECK_CAST,
-        Opcode.INVOKE_STATIC,
-        Opcode.MOVE_RESULT_OBJECT,
-        Opcode.RETURN_OBJECT,
-        Opcode.CHECK_CAST,
+    strings = listOf(
+        "Found entityKey=`",
+        "` that does not contain a PlaylistVideoEntityId message as it's identifier."
     ),
-    customFingerprint = custom@{ methodDef, classDef ->
-        // This method is always called "a" because this kind of class always has a single (non synthetic) method.
-
-        if (methodDef.name != "a") return@custom false
-
-        val count = classDef.methods.count()
-        count == 2 || count == 3
-    },
+    customFingerprint = { methodDef, _ ->
+        methodDef.findUriParseIndex() >= 0
+    }
 )
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserLegacyFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserLegacyFingerprint.kt
new file mode 100644
index 0000000000..b05818e4b7
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserLegacyFingerprint.kt
@@ -0,0 +1,33 @@
+package app.revanced.patches.youtube.misc.links.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+import com.android.tools.smali.dexlib2.Opcode
+
+internal object ABUriParserLegacyFingerprint : MethodFingerprint(
+    returnType = "Ljava/lang/Object",
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    parameters = listOf("Ljava/lang/Object"),
+    opcodes = listOf(
+        Opcode.RETURN_OBJECT,
+        Opcode.CHECK_CAST,
+        Opcode.INVOKE_VIRTUAL,
+        Opcode.MOVE_RESULT_OBJECT,
+        Opcode.CHECK_CAST,
+        Opcode.RETURN_OBJECT,
+        Opcode.CHECK_CAST,
+        Opcode.INVOKE_STATIC,
+        Opcode.MOVE_RESULT_OBJECT,
+        Opcode.RETURN_OBJECT,
+        Opcode.CHECK_CAST,
+    ),
+    customFingerprint = custom@{ methodDef, classDef ->
+        // This method is always called "a" because this kind of class always has a single (non synthetic) method.
+
+        if (methodDef.name != "a") return@custom false
+
+        val count = classDef.methods.count()
+        count == 2 || count == 3
+    }
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt
index 66fcccaac4..f27f23949b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt
@@ -2,16 +2,18 @@ package app.revanced.patches.youtube.misc.links.fingerprints
 
 import app.revanced.patcher.extensions.or
 import app.revanced.patcher.fingerprint.MethodFingerprint
+import app.revanced.patches.youtube.misc.links.BypassURLRedirectsPatch.findUriParseIndex
 import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.Opcode
 
+/**
+ * Target 19.33+
+ */
 internal object HTTPUriParserFingerprint : MethodFingerprint(
     returnType = "Landroid/net/Uri",
     accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
     parameters = listOf("Ljava/lang/String"),
-    opcodes = listOf(
-        Opcode.INVOKE_STATIC,
-        Opcode.MOVE_RESULT_OBJECT
-    ),
-    strings = listOf("://")
+    strings = listOf("https", "https:", "://"),
+    customFingerprint = { methodDef, _ ->
+        methodDef.findUriParseIndex() >= 0
+    }
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserLegacyFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserLegacyFingerprint.kt
new file mode 100644
index 0000000000..e6bfc4cf8e
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserLegacyFingerprint.kt
@@ -0,0 +1,17 @@
+package app.revanced.patches.youtube.misc.links.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+import com.android.tools.smali.dexlib2.Opcode
+
+internal object HTTPUriParserLegacyFingerprint : MethodFingerprint(
+    returnType = "Landroid/net/Uri",
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
+    parameters = listOf("Ljava/lang/String"),
+    opcodes = listOf(
+        Opcode.INVOKE_STATIC,
+        Opcode.MOVE_RESULT_OBJECT
+    ),
+    strings = listOf("://")
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt
index 4b9620a2a4..08c73e9b82 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt
@@ -1,6 +1,5 @@
 package app.revanced.patches.youtube.misc.litho.filter
 
-import app.revanced.util.exception
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
@@ -8,36 +7,47 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
 import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
 import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
-import app.revanced.patcher.fingerprint.MethodFingerprint
 import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchException
 import app.revanced.patcher.patch.annotation.Patch
 import app.revanced.patcher.util.smali.ExternalLabel
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
-import app.revanced.patches.youtube.misc.litho.filter.fingerprints.*
+import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ComponentContextParserFingerprint
+import app.revanced.patches.youtube.misc.litho.filter.fingerprints.EmptyComponentFingerprint
+import app.revanced.patches.youtube.misc.litho.filter.fingerprints.LithoFilterFingerprint
+import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ProtobufBufferReferenceFingerprint
+import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ReadComponentIdentifierFingerprint
+import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch
 import app.revanced.util.getReference
 import app.revanced.util.indexOfFirstInstructionOrThrow
+import app.revanced.util.indexOfFirstInstructionReversedOrThrow
+import app.revanced.util.resultOrThrow
+import com.android.tools.smali.dexlib2.AccessFlags
 import com.android.tools.smali.dexlib2.Opcode
-import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
+import com.android.tools.smali.dexlib2.iface.Field
+import com.android.tools.smali.dexlib2.iface.Method
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction
 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
 import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
+import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
 import com.android.tools.smali.dexlib2.iface.reference.FieldReference
+import com.android.tools.smali.dexlib2.iface.reference.MethodReference
 import java.io.Closeable
 
 @Patch(
     description = "Hooks the method which parses the bytes into a ComponentContext to filter components.",
-    dependencies = [IntegrationsPatch::class]
+    dependencies = [IntegrationsPatch::class, VersionCheckPatch::class]
 )
 @Suppress("unused")
 object LithoFilterPatch : BytecodePatch(
-    setOf(ComponentContextParserFingerprint, LithoFilterFingerprint, ProtobufBufferReferenceFingerprint)
+    setOf(
+        ComponentContextParserFingerprint,
+        LithoFilterFingerprint,
+        ProtobufBufferReferenceFingerprint,
+        ReadComponentIdentifierFingerprint,
+        EmptyComponentFingerprint
+    )
 ), Closeable {
-    private val MethodFingerprint.patternScanResult
-        get() = result!!.scanResult.patternScanResult!!
-
-    private val MethodFingerprint.patternScanEndIndex
-        get() = patternScanResult.endIndex
-
     private val Instruction.descriptor
         get() = (this as ReferenceInstruction).reference.toString()
 
@@ -70,118 +80,181 @@ object LithoFilterPatch : BytecodePatch(
      *   }
      * }
      *
+     * When patching 19.17 and earlier:
+     *
      * class ComponentContextParser {
+     *    public ComponentContext ReadComponentIdentifierFingerprint(...) {
+     *        ...
+     *        if (IntegrationsClass.filter(identifier, pathBuilder)); // Inserted by this patch.
+     *            return emptyComponent;
+     *        ...
+     *    }
+     * }
+     *
+     * When patching 19.18 and later:
      *
+     * class ComponentContextParser {
      *    public ComponentContext parseBytesToComponentContext(...) {
      *        ...
-     *        if (IntegrationsClass.filter(identifier, pathBuilder)); // Inserted by this patch.
+     *        if (ReadComponentIdentifierFingerprint() == null); // Inserted by this patch.
      *            return emptyComponent;
      *        ...
      *    }
+     *
+     *    public ComponentIdentifierObj readComponentIdentifier(...) {
+     *        ...
+     *        if (IntegrationsClass.filter(identifier, pathBuilder)); // Inserted by this patch.
+     *            return null;
+     *        ...
+     *    }
      * }
      */
     override fun execute(context: BytecodeContext) {
-        ComponentContextParserFingerprint.result?.also {
-            arrayOf(
-                EmptyComponentBuilderFingerprint,
-                ReadComponentIdentifierFingerprint
-            ).forEach { fingerprint ->
-                if (fingerprint.resolve(context, it.mutableMethod, it.mutableClass)) return@forEach
-                throw fingerprint.exception
+
+        // Remove dummy filter from Integrations static field
+        // and add the filters included during patching.
+        LithoFilterFingerprint.resultOrThrow().mutableMethod.apply {
+            removeInstructions(2, 4) // Remove dummy filter.
+
+            addFilter = { classDescriptor ->
+                addInstructions(
+                    2,
+                    """
+                        new-instance v1, $classDescriptor
+                        invoke-direct {v1}, $classDescriptor->()V
+                        const/16 v2, ${filterCount++}
+                        aput-object v1, v0, v2
+                    """
+                )
             }
-        }?.let { bytesToComponentContextMethod ->
+        }
 
-            // region Pass the buffer into Integrations.
+        // region Pass the buffer into Integrations.
 
-            ProtobufBufferReferenceFingerprint.result
-                ?.mutableMethod?.addInstruction(0,
-                    " invoke-static { p2 }, $INTEGRATIONS_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V")
-                ?: throw ProtobufBufferReferenceFingerprint.exception
+        ProtobufBufferReferenceFingerprint.resultOrThrow().mutableMethod.addInstruction(
+            0,
+            " invoke-static { p2 }, $INTEGRATIONS_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V"
+        )
 
-            // endregion
+        // endregion
 
-            // region Hook the method that parses bytes into a ComponentContext.
+        // region Hook the method that parses bytes into a ComponentContext.
 
-            val builderMethodIndex = EmptyComponentBuilderFingerprint.patternScanEndIndex
-            val emptyComponentFieldIndex = builderMethodIndex + 2
+        var readComponentMethod : Method
+        var builderMethodDescriptor : Method
+        val emptyComponentField : Field
 
-            bytesToComponentContextMethod.mutableMethod.apply {
-                val insertHookIndex = indexOfFirstInstructionOrThrow {
-                    opcode == Opcode.IPUT_OBJECT &&
-                            getReference()?.type == "Ljava/lang/StringBuilder;"
-                } + 1
+        ComponentContextParserFingerprint.resultOrThrow().let {
+            it.mutableMethod.apply {
+                // Get the only static method in the class.
+                builderMethodDescriptor = EmptyComponentFingerprint.resultOrThrow().classDef
+                    .methods.first { method -> AccessFlags.STATIC.isSet(method.accessFlags) }
+                // Only one field.
+                emptyComponentField = context.findClass(builderMethodDescriptor.returnType)!!
+                    .immutableClass.fields.single()
+                readComponentMethod = ReadComponentIdentifierFingerprint.resultOrThrow().method
 
-                // region Get free registers that this patch uses.
-                // Registers are overwritten right after they are used in this patch, therefore free to clobber.
+                // 19.18 and later require patching 2 methods instead of one.
+                // Otherwise the patched code is the same.
+                if (VersionCheckPatch.is_19_18_or_greater) {
+                    // Get the method name of the ReadComponentIdentifierFingerprint call.
+                    val readComponentMethodCallIndex = indexOfFirstInstructionOrThrow {
+                        val reference = getReference()
+                        reference?.definingClass == readComponentMethod.definingClass
+                                && reference.name == readComponentMethod.name
+                    }
 
-                val freeRegistersInstruction = getInstruction(insertHookIndex - 2)
+                    // Result of read component, and also a free register.
+                    val register = getInstruction(
+                        readComponentMethodCallIndex + 1
+                    ).registerA
 
-                // Later used to store the protobuf buffer object.
-                val free1 = getInstruction(insertHookIndex).registerA
-                // Later used to store the identifier of the component.
-                // This register currently holds a reference to the StringBuilder object
-                // that is required before clobbering.
-                val free2 = freeRegistersInstruction.registerC
+                    // Insert after 'move-result-object'
+                    val insertHookIndex = readComponentMethodCallIndex + 2
 
-                @Suppress("UnnecessaryVariable")
-                val stringBuilderRegister = free2
+                    // Return an EmptyComponent instead of the original component if the filterState method returns true.
+                    addInstructionsWithLabels(
+                        insertHookIndex,
+                        """
+                            if-nez v$register, :unfiltered
+    
+                            # Component was filtered in ReadComponentIdentifierFingerprint hook
+                            move-object/from16 v$register, p1
+                            invoke-static { v$register }, $builderMethodDescriptor
+                            move-result-object v$register
+                            iget-object v$register, v$register, $emptyComponentField
+                            return-object v$register
+                        """,
+                        ExternalLabel("unfiltered", getInstruction(insertHookIndex))
+                    )
+                }
+            }
+        }
+
+        // endregion
 
-                // endregion
+        // region Read component then store the result.
 
-                // region Get references that this patch needs.
+        ReadComponentIdentifierFingerprint.resultOrThrow().let {
+            it.mutableMethod.apply {
+                val insertHookIndex = indexOfFirstInstructionOrThrow {
+                    opcode == Opcode.IPUT_OBJECT &&
+                            getReference()?.type == "Ljava/lang/StringBuilder;"
+                }
+                val stringBuilderRegister = getInstruction(insertHookIndex).registerA
 
-                val builderMethodDescriptor = getInstruction(builderMethodIndex).descriptor
-                val emptyComponentFieldDescriptor = getInstruction(emptyComponentFieldIndex).descriptor
+                // Identifier is saved to a field just before the string builder.
+                val identifierRegister = getInstruction(
+                    indexOfFirstInstructionReversedOrThrow(insertHookIndex) {
+                        opcode == Opcode.IPUT_OBJECT
+                                && getReference()?.type == "Ljava/lang/String;"
+                    }
+                ).registerA
 
-                val identifierRegister =
-                    getInstruction(ReadComponentIdentifierFingerprint.patternScanEndIndex).registerA
+                // Find a free temporary register.
+                val register = getInstruction(
+                    // Immediately before is a StringBuilder append constant character.
+                    indexOfFirstInstructionReversedOrThrow(insertHookIndex, Opcode.CONST_16)
+                ).registerA
 
-                // endregion
+                // Verify the temp register will not clobber the method result register.
+                if (stringBuilderRegister == register) {
+                    throw PatchException("Free register will clobber StringBuilder register")
+                }
 
-                // region Patch the method.
+                val commonInstructions = """
+                    invoke-static { v$identifierRegister, v$stringBuilderRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->filter(Ljava/lang/String;Ljava/lang/StringBuilder;)Z
+                    move-result v$register
+                    if-eqz v$register, :unfiltered
+                """
 
-                // Insert the instructions that are responsible
-                // to return an EmptyComponent instead of the original component if the filter method returns true.
                 addInstructionsWithLabels(
                     insertHookIndex,
+                    if (VersionCheckPatch.is_19_18_or_greater) """
+                        $commonInstructions
+                        
+                        # Return null, and the ComponentContextParserFingerprint hook 
+                        # handles returning an empty component.
+                        const/4 v$register, 0x0
+                        return-object v$register
                     """
-                        # Invoke the filter method.
-                      
-                        invoke-static { v$identifierRegister, v$stringBuilderRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->filter(Ljava/lang/String;Ljava/lang/StringBuilder;)Z
-                        move-result v$free1
-                       
-                        if-eqz v$free1, :unfiltered
-
-                        move-object/from16 v$free2, p1
-                        invoke-static {v$free2}, $builderMethodDescriptor
-                        move-result-object v$free2
-                        iget-object v$free2, v$free2, $emptyComponentFieldDescriptor
-                        return-object v$free2
+                    else """
+                        $commonInstructions
+                        
+                        # Exact same code as ComponentContextParserFingerprint hook,
+                        # but with the free register of this method.
+                        move-object/from16 v$register, p1
+                        invoke-static { v$register }, $builderMethodDescriptor
+                        move-result-object v$register
+                        iget-object v$register, v$register, $emptyComponentField
+                        return-object v$register
                     """,
-                    // Used to jump over the instruction which block the component from being created.
                     ExternalLabel("unfiltered", getInstruction(insertHookIndex))
                 )
-                // endregion
             }
+        }
 
-            // endregion
-        } ?: throw ComponentContextParserFingerprint.exception
-
-        LithoFilterFingerprint.result?.mutableMethod?.apply {
-            removeInstructions(2, 4) // Remove dummy filter.
-
-            addFilter = { classDescriptor ->
-                addInstructions(
-                    2,
-                    """
-                        new-instance v1, $classDescriptor
-                        invoke-direct {v1}, $classDescriptor->()V
-                        const/16 v2, ${filterCount++}
-                        aput-object v1, v0, v2
-                    """
-                )
-            }
-        } ?: throw LithoFilterFingerprint.exception
+        // endregion
     }
 
     override fun close() = LithoFilterFingerprint.result!!
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt
index 419e0f91c8..1249e674c8 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt
@@ -2,6 +2,10 @@ package app.revanced.patches.youtube.misc.litho.filter.fingerprints
 
 import app.revanced.patcher.fingerprint.MethodFingerprint
 
+/**
+ * In 19.17 and earlier, this resolves to the same method as [ReadComponentIdentifierFingerprint].
+ * In 19.18+ this resolves to a different method.
+ */
 internal object ComponentContextParserFingerprint : MethodFingerprint(
     strings = listOf("Component was not found %s because it was removed due to duplicate converter bindings.")
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt
deleted file mode 100644
index ec6a1f0c6f..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package app.revanced.patches.youtube.misc.litho.filter.fingerprints
-
-import app.revanced.patcher.fingerprint.MethodFingerprint
-import com.android.tools.smali.dexlib2.Opcode
-
-internal object EmptyComponentBuilderFingerprint : MethodFingerprint(
-    opcodes = listOf(
-        Opcode.INVOKE_INTERFACE,
-        Opcode.INVOKE_STATIC_RANGE
-    ),
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentFingerprint.kt
new file mode 100644
index 0000000000..f5dc38971a
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentFingerprint.kt
@@ -0,0 +1,14 @@
+package app.revanced.patches.youtube.misc.litho.filter.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+internal object EmptyComponentFingerprint : MethodFingerprint(
+    accessFlags = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR,
+    parameters = listOf(),
+    strings = listOf("EmptyComponent"),
+    customFingerprint = { _, classDef ->
+        classDef.methods.filter { AccessFlags.STATIC.isSet(it.accessFlags) }.size == 1
+    }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt
index 0a6adfda3d..7a86b86ca5 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt
@@ -1,12 +1,11 @@
 package app.revanced.patches.youtube.misc.litho.filter.fingerprints
 
 import app.revanced.patcher.fingerprint.MethodFingerprint
-import com.android.tools.smali.dexlib2.Opcode
 
+/**
+ * In 19.17 and earlier, this resolves to the same method as [ComponentContextParserFingerprint].
+ * In 19.18+ this resolves to a different method.
+ */
 internal object ReadComponentIdentifierFingerprint : MethodFingerprint(
-    opcodes = listOf(
-        Opcode.IF_NEZ,
-        null,
-        Opcode.MOVE_RESULT_OBJECT // Register stores the component identifier string
-    )
+    strings = listOf("Number of bits must be positive")
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt
index ae648899d5..03d19d6cb3 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt
@@ -11,8 +11,10 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.misc.navigation.fingerprints.*
 import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
+import app.revanced.util.alsoResolve
 import app.revanced.util.getReference
 import app.revanced.util.indexOfFirstInstructionOrThrow
+import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
 import app.revanced.util.resultOrThrow
 import com.android.tools.smali.dexlib2.Opcode
 import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@@ -64,9 +66,7 @@ object NavigationBarHookPatch : BytecodePatch(
             }
         }
 
-        InitializeButtonsFingerprint.apply {
-            resolve(context, PivotBarConstructorFingerprint.resultOrThrow().classDef)
-        }.resultOrThrow().mutableMethod.apply {
+        InitializeButtonsFingerprint.alsoResolve(context, PivotBarConstructorFingerprint).mutableMethod.apply {
             // Hook the current navigation bar enum value. Note, the 'You' tab does not have an enum value.
             val navigationEnumClassName = NavigationEnumFingerprint.resultOrThrow().mutableClass.type
             addHook(Hook.SET_LAST_APP_NAVIGATION_ENUM) {
@@ -121,7 +121,11 @@ object NavigationBarHookPatch : BytecodePatch(
         // Insert before the first ViewGroup method call after inflating,
         // so this works regardless which layout is used.
         ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply {
-            val instructionIndex = indexOfFirstInstructionOrThrow {
+            val searchBarResourceId = indexOfFirstWideLiteralInstructionValueOrThrow(
+                NavigationBarHookResourcePatch.actionBarSearchResultsViewMicId
+            )
+
+            val instructionIndex = indexOfFirstInstructionOrThrow(searchBarResourceId) {
                 opcode == Opcode.INVOKE_VIRTUAL && getReference()?.name == "setLayoutDirection"
             }
 
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/ActionBarSearchResultsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/ActionBarSearchResultsFingerprint.kt
index 2ba8106f99..921047d50e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/ActionBarSearchResultsFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/ActionBarSearchResultsFingerprint.kt
@@ -8,6 +8,5 @@ import com.android.tools.smali.dexlib2.AccessFlags
 internal object ActionBarSearchResultsFingerprint : LiteralValueFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     returnType = "Landroid/view/View;",
-    parameters = listOf("Landroid/view/LayoutInflater;"),
     literalSupplier = { NavigationBarHookResourcePatch.actionBarSearchResultsViewMicId }
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/InitializeButtonsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/InitializeButtonsFingerprint.kt
index f91d1b36f3..eeeb060ffb 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/InitializeButtonsFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/fingerprints/InitializeButtonsFingerprint.kt
@@ -11,6 +11,5 @@ import com.android.tools.smali.dexlib2.AccessFlags
 internal object InitializeButtonsFingerprint : LiteralValueFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     returnType = "V",
-    parameters = listOf(),
     literalSupplier = { NavigationBarHookResourcePatch.imageOnlyTabResourceId }
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt
index 7df451a4a3..1f58ddd871 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt
@@ -8,11 +8,8 @@ import com.android.tools.smali.dexlib2.Opcode
 internal object VideoStateFingerprint : MethodFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     returnType = "V",
-    parameters = listOf("L"),
+    parameters = listOf("Lcom/google/android/libraries/youtube/player/features/overlay/controls/ControlsState;"),
     opcodes = listOf(
-        Opcode.IGET_OBJECT,
-        Opcode.INVOKE_VIRTUAL,
-        Opcode.IGET_OBJECT,
         Opcode.CONST_4,
         Opcode.IF_EQZ,
         Opcode.IF_EQZ,
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt
new file mode 100644
index 0000000000..5ef04463c6
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt
@@ -0,0 +1,52 @@
+package app.revanced.patches.youtube.misc.playservice
+
+import app.revanced.patcher.data.ResourceContext
+import app.revanced.patcher.patch.ResourcePatch
+import app.revanced.patcher.patch.annotation.Patch
+import app.revanced.util.findElementByAttributeValueOrThrow
+import kotlin.properties.Delegates
+
+@Patch(description = "Uses the Play Store service version to find the major/minor version of the YouTube target app.")
+internal object VersionCheckPatch : ResourcePatch() {
+
+    var is_19_03_or_greater by Delegates.notNull()
+    var is_19_04_or_greater by Delegates.notNull()
+    var is_19_16_or_greater by Delegates.notNull()
+    var is_19_17_or_greater by Delegates.notNull()
+    var is_19_18_or_greater by Delegates.notNull()
+    var is_19_23_or_greater by Delegates.notNull()
+    var is_19_25_or_greater by Delegates.notNull()
+    var is_19_26_or_greater by Delegates.notNull()
+    var is_19_29_or_greater by Delegates.notNull()
+    var is_19_32_or_greater by Delegates.notNull()
+    var is_19_33_or_greater by Delegates.notNull()
+    var is_19_36_or_greater by Delegates.notNull()
+    var is_19_41_or_greater by Delegates.notNull()
+
+    override fun execute(context: ResourceContext) {
+
+        // The app version is missing from the decompiled manifest,
+        // so instead use the Google Play services version and compare against specific releases.
+        val playStoreServicesVersion = context.document["res/values/integers.xml"].use { document ->
+            document.documentElement.childNodes.findElementByAttributeValueOrThrow(
+                "name",
+                "google_play_services_version"
+            ).textContent.toInt()
+        }
+
+        // All bug fix releases always seem to use the same play store version as the minor version.
+        is_19_03_or_greater = 240402000 <= playStoreServicesVersion
+        is_19_04_or_greater = 240502000 <= playStoreServicesVersion
+        is_19_16_or_greater = 241702000 <= playStoreServicesVersion
+        is_19_17_or_greater = 241802000 <= playStoreServicesVersion
+        is_19_18_or_greater = 241902000 <= playStoreServicesVersion
+        is_19_23_or_greater = 242402000 <= playStoreServicesVersion
+        is_19_25_or_greater = 242599000 <= playStoreServicesVersion
+        is_19_26_or_greater = 242705000 <= playStoreServicesVersion
+        is_19_29_or_greater = 243005000 <= playStoreServicesVersion
+        is_19_32_or_greater = 243199000 <= playStoreServicesVersion
+        is_19_33_or_greater = 243405000 <= playStoreServicesVersion
+        is_19_36_or_greater = 243705000 <= playStoreServicesVersion
+        is_19_41_or_greater = 244305000 <= playStoreServicesVersion
+    }
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt
index 37ccb352f6..de5ecb2063 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt
@@ -28,27 +28,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
         CompatiblePackage(
             "com.google.android.youtube",
             [
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
+                "18.38.44",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ]
         )
     ]
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt
index 9e5e4f8b87..575d93e3ef 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt
@@ -21,7 +21,7 @@ internal object RecyclerViewTreeHookPatch : BytecodePatch(
 
         RecyclerViewTreeObserverFingerprint.result?.let {
             it.mutableMethod.apply {
-                val insertIndex = it.scanResult.patternScanResult!!.startIndex
+                val insertIndex = it.scanResult.patternScanResult!!.startIndex + 1
                 val recyclerViewParameter = 2
 
                 addHook = { classDescriptor ->
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt
index f40fd09c9c..b94c578129 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt
@@ -9,12 +9,11 @@ internal object RecyclerViewTreeObserverFingerprint : MethodFingerprint(
     returnType = "V",
     accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
     opcodes = listOf(
+        Opcode.CHECK_CAST,
         Opcode.NEW_INSTANCE,
         Opcode.INVOKE_DIRECT,
         Opcode.INVOKE_VIRTUAL,
-        Opcode.NEW_INSTANCE,
-        Opcode.INVOKE_DIRECT,
-        Opcode.IPUT_OBJECT
+        Opcode.NEW_INSTANCE
     ),
     strings = listOf("LithoRVSLCBinder")
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt
index 819b9d3b9b..ade624eaf9 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt
@@ -16,6 +16,7 @@ import app.revanced.patches.shared.misc.settings.preference.NonInteractivePrefer
 import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
 import app.revanced.patches.shared.misc.settings.preference.TextPreference
 import app.revanced.patches.youtube.misc.check.CheckEnvironmentPatch
+import app.revanced.patches.youtube.misc.fix.cairo.DisableCairoSettingsPatch
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.misc.settings.fingerprints.LicenseActivityOnCreateFingerprint
 import app.revanced.patches.youtube.misc.settings.fingerprints.SetThemeFingerprint
@@ -31,6 +32,7 @@ import java.io.Closeable
         IntegrationsPatch::class,
         SettingsResourcePatch::class,
         AddResourcesPatch::class,
+        DisableCairoSettingsPatch::class,
         // Currently there is no easy way to make a mandatory patch,
         // so for now this is a dependent of this patch.
         CheckEnvironmentPatch::class,
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt
index 28833df23c..a5c5962406 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt
@@ -1,14 +1,15 @@
 package app.revanced.patches.youtube.misc.settings
 
 import app.revanced.patcher.data.ResourceContext
-import app.revanced.patcher.patch.PatchException
 import app.revanced.patches.all.misc.resources.AddResourcesPatch
 import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
 import app.revanced.patches.shared.misc.settings.BaseSettingsResourcePatch
 import app.revanced.patches.shared.misc.settings.preference.IntentPreference
 import app.revanced.util.ResourceGroup
 import app.revanced.util.copyResources
-import org.w3c.dom.Element
+import app.revanced.util.copyXmlNode
+import app.revanced.util.findElementByAttributeValueOrThrow
+import app.revanced.util.inputStreamFromBundledResource
 
 object SettingsResourcePatch : BaseSettingsResourcePatch(
     IntentPreference(
@@ -37,53 +38,57 @@ object SettingsResourcePatch : BaseSettingsResourcePatch(
             context.copyResources("settings", resourceGroup)
         }
 
+        // Copy style properties used to fix over-sized copy menu that appear in EditTextPreference.
+        // For a full explanation of how this fixes the issue, see the comments in this style file
+        // and the comments in the integrations code.
+        val targetResource = "values/styles.xml"
+        inputStreamFromBundledResource(
+            "settings/host",
+            targetResource
+        )!!.let { inputStream ->
+            "resources".copyXmlNode(
+                context.xmlEditor[inputStream],
+                context.xmlEditor["res/${targetResource}"]
+            ).close()
+        }
+
         // Remove horizontal divider from the settings Preferences
         // To better match the appearance of the stock YouTube settings.
         context.xmlEditor["res/values/styles.xml"].use { editor ->
-            val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
+            val document = editor.file
 
-            for (i in 0 until resourcesNode.childNodes.length) {
-                val node = resourcesNode.childNodes.item(i) as? Element ?: continue
-                val name = node.getAttribute("name")
-                if (name == "Theme.YouTube.Settings" || name == "Theme.YouTube.Settings.Dark") {
-                    val listDividerNode = editor.file.createElement("item")
-                    listDividerNode.setAttribute("name", "android:listDivider")
-                    listDividerNode.appendChild(editor.file.createTextNode("@null"))
-                    node.appendChild(listDividerNode)
-                }
+            arrayOf(
+                "Theme.YouTube.Settings",
+                "Theme.YouTube.Settings.Dark"
+            ).forEach { value ->
+                val listDividerNode = document.createElement("item")
+                listDividerNode.setAttribute("name", "android:listDivider")
+                listDividerNode.appendChild(document.createTextNode("@null"))
+
+                document.childNodes.findElementByAttributeValueOrThrow(
+                    "name", value
+                ).appendChild(listDividerNode)
             }
         }
 
         // Modify the manifest and add a data intent filter to the LicenseActivity.
         // Some devices freak out if undeclared data is passed to an intent,
         // and this change appears to fix the issue.
-        var modifiedIntent = false
         context.xmlEditor["AndroidManifest.xml"].use { editor ->
             val document = editor.file
-            // A xml regular-expression would probably work better than this manual searching.
-            val manifestNodes = document.getElementsByTagName("manifest").item(0).childNodes
-            for (i in 0..manifestNodes.length) {
-                val node = manifestNodes.item(i)
-                if (node != null && node.nodeName == "application") {
-                    val applicationNodes = node.childNodes
-                    for (j in 0..applicationNodes.length) {
-                        val applicationChild = applicationNodes.item(j)
-                        if (applicationChild is Element && applicationChild.nodeName == "activity" &&
-                            applicationChild.getAttribute("android:name") == "com.google.android.libraries.social.licenses.LicenseActivity"
-                        ) {
-                            val intentFilter = document.createElement("intent-filter")
-                            val mimeType = document.createElement("data")
-                            mimeType.setAttribute("android:mimeType", "text/plain")
-                            intentFilter.appendChild(mimeType)
-                            applicationChild.appendChild(intentFilter)
-                            modifiedIntent = true
-                            break
-                        }
-                    }
-                }
-            }
-        }
 
-        if (!modifiedIntent) throw PatchException("Could not modify activity intent")
+            val licenseElement = document.childNodes.findElementByAttributeValueOrThrow(
+                "android:name",
+                "com.google.android.libraries.social.licenses.LicenseActivity"
+            )
+
+            val mimeType = document.createElement("data")
+            mimeType.setAttribute("android:mimeType", "text/plain")
+
+            val intentFilter = document.createElement("intent-filter")
+            intentFilter.appendChild(mimeType)
+
+            licenseElement.appendChild(intentFilter)
+        }
     }
 }
diff --git a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt
deleted file mode 100644
index f54b9ee7c8..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package app.revanced.patches.youtube.shared.fingerprints
-
-import app.revanced.patcher.fingerprint.MethodFingerprint
-
-internal object HomeActivityFingerprint : MethodFingerprint(
-    customFingerprint = { methodDef, classDef ->
-        methodDef.name == "onCreate" && classDef.type.endsWith("Shell_HomeActivity;")
-    },
-)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/RollingNumberTextViewAnimationUpdateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/RollingNumberTextViewAnimationUpdateFingerprint.kt
index 14b224eea9..a4eda997e8 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/RollingNumberTextViewAnimationUpdateFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/RollingNumberTextViewAnimationUpdateFingerprint.kt
@@ -25,6 +25,7 @@ internal object RollingNumberTextViewAnimationUpdateFingerprint : MethodFingerpr
         Opcode.INVOKE_VIRTUAL, // set textview padding using bitmap width
     ),
     customFingerprint = { _, classDef ->
-        classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;"
+        classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" || classDef.superclass ==
+                "Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;"
     }
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt
index 31141a3113..437eea94e4 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt
@@ -35,7 +35,6 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
                 "19.02.39",
                 "19.03.36",
                 "19.04.38",
-                "19.05.36",
                 "19.06.39",
                 "19.07.40",
                 "19.08.36",
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt
index 88b90ba33e..71c0a2d146 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt
@@ -183,9 +183,9 @@ object VideoInformationPatch : BytecodePatch(
         targetClass.interfaces.add(INTEGRATIONS_PLAYER_INTERFACE)
 
         arrayOf(
-            seekToMethod to "seekTo",
-            seekToRelativeMethod to "seekToRelative"
-        ).forEach { (method, name) ->
+            Triple(seekToMethod, "seekTo", true),
+            Triple(seekToRelativeMethod, "seekToRelative", false)
+        ).forEach { (method, name, returnsBoolean) ->
             // Add interface method.
             // Get enum type for the seek helper method.
             val seekSourceEnumType = method.parameterTypes[1].toString()
@@ -194,22 +194,29 @@ object VideoInformationPatch : BytecodePatch(
                 targetClass.type,
                 name,
                 listOf(ImmutableMethodParameter("J", null, "time")),
-                "Z",
+                if (returnsBoolean) "Z" else "V",
                 AccessFlags.PUBLIC or AccessFlags.FINAL,
                 null, null,
                 MutableMethodImplementation(4)
             ).toMutable()
 
-            // Insert helper method instructions.
-            interfaceImplementation.addInstructions(
-                0,
-                """
+            var instructions = """
                     # first enum (field a) is SEEK_SOURCE_UNKNOWN
                     sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
                     invoke-virtual { p0, p1, p2, v0 }, $method
-                    move-result p1
-                    return p1
                 """
+
+            instructions += if (returnsBoolean) """
+                move-result p1
+                return p1                
+            """ else """
+                return-void                
+            """
+
+            // Insert helper method instructions.
+            interfaceImplementation.addInstructions(
+                0,
+                instructions
             )
 
             targetClass.methods.add(interfaceImplementation)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/MdxSeekRelativeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/MdxSeekRelativeFingerprint.kt
index 3fd89abf16..2146a88d47 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/MdxSeekRelativeFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/MdxSeekRelativeFingerprint.kt
@@ -10,10 +10,9 @@ import com.android.tools.smali.dexlib2.Opcode
  */
 internal object MdxSeekRelativeFingerprint : MethodFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
-    returnType = "Z",
+    // Return type is boolean up to 19.39, and void with 19.39+.
     parameters = listOf("J", "L"),
     opcodes = listOf(
         Opcode.IGET_OBJECT,
-        Opcode.INVOKE_INTERFACE
     )
-)
\ No newline at end of file
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt
index 05c89b933e..3580daca87 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt
@@ -10,12 +10,10 @@ import com.android.tools.smali.dexlib2.Opcode
  */
 internal object SeekRelativeFingerprint : MethodFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
-    returnType = "Z",
+    // returnType is boolean up to 19.39, and void with 19.39+
     parameters = listOf("J", "L"),
     opcodes = listOf(
         Opcode.ADD_LONG_2ADDR,
         Opcode.INVOKE_VIRTUAL,
-        Opcode.MOVE_RESULT,
-        Opcode.RETURN
     )
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt
index 03711953ab..dbf70a0aac 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt
@@ -1,6 +1,5 @@
 package app.revanced.patches.youtube.video.playerresponse
 
-import app.revanced.util.exception
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
@@ -8,21 +7,29 @@ import app.revanced.patcher.patch.BytecodePatch
 import app.revanced.patcher.patch.annotation.Patch
 import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
+import app.revanced.patches.youtube.misc.playservice.VersionCheckPatch
 import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint
+import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderLegacyFingerprint
+import app.revanced.util.resultOrThrow
 import java.io.Closeable
 
 @Patch(
-    dependencies = [IntegrationsPatch::class],
+    dependencies = [IntegrationsPatch::class, VersionCheckPatch::class],
 )
 object PlayerResponseMethodHookPatch :
-    BytecodePatch(setOf(PlayerParameterBuilderFingerprint)),
+    BytecodePatch(
+        setOf(
+            PlayerParameterBuilderFingerprint,
+            PlayerParameterBuilderLegacyFingerprint
+        )
+    ),
     Closeable,
     MutableSet by mutableSetOf() {
 
     // Parameter numbers of the patched method.
     private const val PARAMETER_VIDEO_ID = 1
     private const val PARAMETER_PROTO_BUFFER = 3
-    private const val PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11
+    private var PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = -1
 
     // Registers used to pass the parameters to integrations.
     private var playerResponseMethodCopyRegisters = false
@@ -34,8 +41,13 @@ object PlayerResponseMethodHookPatch :
     private var numberOfInstructionsAdded = 0
 
     override fun execute(context: BytecodeContext) {
-        playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod
-            ?: throw PlayerParameterBuilderFingerprint.exception
+        if (VersionCheckPatch.is_19_23_or_greater) {
+            playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod
+            PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 12
+        } else {
+            playerResponseMethod = PlayerParameterBuilderLegacyFingerprint.resultOrThrow().mutableMethod
+            PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11
+        }
 
         // On some app targets the method has too many registers pushing the parameters past v15.
         // If needed, move the parameters to 4-bit registers so they can be passed to integrations.
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt
index 2694940fd6..4152d39aad 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt
@@ -4,6 +4,9 @@ import app.revanced.patcher.extensions.or
 import app.revanced.patcher.fingerprint.MethodFingerprint
 import com.android.tools.smali.dexlib2.AccessFlags
 
+/**
+ * For targets 19.25 and later.
+ */
 internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     returnType = "L",
@@ -14,6 +17,7 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
         "Ljava/lang/String;",
         "I",
         "I",
+        "L", // 19.25+ parameter
         "Ljava/util/Set;",
         "Ljava/lang/String;",
         "Ljava/lang/String;",
@@ -21,5 +25,6 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
         "Z", // Appears to indicate if the video id is being opened or is currently playing.
         "Z",
         "Z"
-    )
+    ),
+    strings = listOf("psps")
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderLegacyFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderLegacyFingerprint.kt
new file mode 100644
index 0000000000..f41a57e344
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderLegacyFingerprint.kt
@@ -0,0 +1,28 @@
+package app.revanced.patches.youtube.video.playerresponse.fingerprint
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * For targets 19.24 and earlier.
+ */
+internal object PlayerParameterBuilderLegacyFingerprint : MethodFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "L",
+    parameters = listOf(
+        "Ljava/lang/String;", // VideoId.
+        "[B",
+        "Ljava/lang/String;", // Player parameters proto buffer.
+        "Ljava/lang/String;",
+        "I",
+        "I",
+        "Ljava/util/Set;",
+        "Ljava/lang/String;",
+        "Ljava/lang/String;",
+        "L",
+        "Z", // Appears to indicate if the video id is being opened or is currently playing.
+        "Z",
+        "Z"
+    )
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt
index dc89623c7a..71849406ab 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt
@@ -35,24 +35,11 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
     compatiblePackages = [
         CompatiblePackage(
             "com.google.android.youtube", [
-                "18.48.39",
+                "18.38.44",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ]
         )
     ]
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt
index 7cdb7d064b..155ccecc50 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt
@@ -21,24 +21,11 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa
         CompatiblePackage(
             "com.google.android.youtube",
             [
-                "18.48.39",
+                "18.38.44",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ],
         ),
     ],
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt
index 061207c085..bfdf2bfd85 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt
@@ -4,10 +4,10 @@ import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
 import app.revanced.patcher.extensions.or
 import app.revanced.patcher.patch.BytecodePatch
-import app.revanced.patcher.patch.PatchException
 import app.revanced.patcher.patch.annotation.Patch
 import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
 import app.revanced.patches.all.misc.resources.AddResourcesPatch
@@ -18,11 +18,14 @@ import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
 import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch
 import app.revanced.patches.youtube.misc.settings.SettingsPatch
 import app.revanced.patches.youtube.video.speed.custom.fingerprints.*
-import app.revanced.util.exception
+import app.revanced.util.alsoResolve
+import app.revanced.util.getReference
+import app.revanced.util.indexOfFirstInstructionOrThrow
+import app.revanced.util.indexOfFirstWideLiteralInstructionValue
+import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
+import app.revanced.util.resultOrThrow
 import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
-import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
 import com.android.tools.smali.dexlib2.iface.reference.FieldReference
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference
 import com.android.tools.smali.dexlib2.immutable.ImmutableField
@@ -59,82 +62,77 @@ object CustomPlaybackSpeedPatch : BytecodePatch(
             TextPreference("revanced_custom_playback_speeds", inputType = InputType.TEXT_MULTI_LINE)
         )
 
-        val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
-        val arrayGenMethodImpl = arrayGenMethod.implementation!!
-
-        val sizeCallIndex = arrayGenMethodImpl.instructions
-            .indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
-
-        if (sizeCallIndex == -1) throw PatchException("Couldn't find call to size()")
-
-        val sizeCallResultRegister =
-            (arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
-
-        arrayGenMethod.replaceInstruction(
-            sizeCallIndex + 1,
-            "const/4 v$sizeCallResultRegister, 0x0"
-        )
-
-        val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex()
-            .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
-
-        val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
-
-        val playbackSpeedsArrayType = "$INTEGRATIONS_CLASS_DESCRIPTOR->customPlaybackSpeeds:[F"
-
-        arrayGenMethod.addInstructions(
-            arrayLengthConstIndex + 1,
-            """
-                sget-object v$arrayLengthConstDestination, $playbackSpeedsArrayType
-                array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
-            """
-        )
-
-        val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex()
-            .first {
-                val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
-                reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
-                        reference?.type == "[F"
+        // Replace the speeds float array with custom speeds.
+        SpeedArrayGeneratorFingerprint.resultOrThrow().mutableMethod.apply {
+            val sizeCallIndex = indexOfFirstInstructionOrThrow {
+                getReference()?.name == "size"
+            }
+            val sizeCallResultRegister = getInstruction(
+                sizeCallIndex + 1
+            ).registerA
+
+            replaceInstruction(
+                sizeCallIndex + 1,
+                "const/4 v$sizeCallResultRegister, 0x0"
+            )
+
+            val arrayLengthConstIndex = indexOfFirstWideLiteralInstructionValueOrThrow(7)
+            val arrayLengthConstDestination = getInstruction(
+                arrayLengthConstIndex
+            ).registerA
+            val playbackSpeedsArrayType = "$INTEGRATIONS_CLASS_DESCRIPTOR->customPlaybackSpeeds:[F"
+
+            addInstructions(
+                arrayLengthConstIndex + 1,
+                """
+                    sget-object v$arrayLengthConstDestination, $playbackSpeedsArrayType
+                    array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
+                """
+            )
+
+            val originalArrayFetchIndex = indexOfFirstInstructionOrThrow {
+                val reference = getReference()
+                reference?.type == "[F" && reference.definingClass.endsWith("/PlayerConfigModel;")
+            }
+            val originalArrayFetchDestination = getInstruction(
+                originalArrayFetchIndex
+            ).registerA
+
+            replaceInstruction(
+                originalArrayFetchIndex,
+                "sget-object v$originalArrayFetchDestination, $playbackSpeedsArrayType"
+            )
+        }
+
+        // Override the min/max speeds that can be used.
+        SpeedLimiterFingerprint.resultOrThrow().mutableMethod.apply {
+            val limiterMinConstIndex = indexOfFirstWideLiteralInstructionValueOrThrow(
+                0.25f.toRawBits().toLong()
+            )
+            var limiterMaxConstIndex = indexOfFirstWideLiteralInstructionValue(
+                2.0f.toRawBits().toLong()
+            )
+            // Newer targets have 4x max speed.
+            if (limiterMaxConstIndex < 0) {
+                limiterMaxConstIndex = indexOfFirstWideLiteralInstructionValueOrThrow(
+                    4.0f.toRawBits().toLong()
+                )
             }
 
-        val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
-
-        arrayGenMethod.replaceInstruction(
-            originalArrayFetchIndex,
-            "sget-object v$originalArrayFetchDestination, $playbackSpeedsArrayType"
-        )
-
-        val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!
-        val limiterMethodImpl = limiterMethod.implementation!!
-
-        val lowerLimitConst = 0.25f.toRawBits()
-        val upperLimitConst = 2.0f.toRawBits()
-        val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex()
-            .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == lowerLimitConst }
-        val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex()
-            .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == upperLimitConst }
-
-        val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
-        val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
-
-        limiterMethod.replaceInstruction(
-            limiterMinConstIndex,
-            "const/high16 v$limiterMinConstDestination, 0x0"
-        )
-        limiterMethod.replaceInstruction(
-            limiterMaxConstIndex,
-            "const/high16 v$limiterMaxConstDestination, 0x41200000  # 10.0f"
-        )
-
-        // region Force old video quality menu.
-        // This is necessary, because there is no known way of adding custom playback speeds to the new menu.
-
-        RecyclerViewTreeHookPatch.addHook(INTEGRATIONS_CLASS_DESCRIPTOR)
+            val limiterMinConstDestination = getInstruction(limiterMinConstIndex).registerA
+            val limiterMaxConstDestination = getInstruction(limiterMaxConstIndex).registerA
 
-        // Required to check if the playback speed menu is currently shown.
-        LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
+            replaceInstruction(
+                limiterMinConstIndex,
+                "const/high16 v$limiterMinConstDestination, 0.0f"
+            )
+            replaceInstruction(
+                limiterMaxConstIndex,
+                "const/high16 v$limiterMaxConstDestination, 10.0f"
+            )
+        }
 
-        GetOldPlaybackSpeedsFingerprint.result?.let { result ->
+        GetOldPlaybackSpeedsFingerprint.resultOrThrow().let { result ->
             // Add a static INSTANCE field to the class.
             // This is later used to call "showOldPlaybackSpeedMenu" on the instance.
             val instanceField = ImmutableField(
@@ -154,13 +152,13 @@ object CustomPlaybackSpeedPatch : BytecodePatch(
 
             // Get the "showOldPlaybackSpeedMenu" method.
             // This is later called on the field INSTANCE.
-            val showOldPlaybackSpeedMenuMethod = ShowOldPlaybackSpeedMenuFingerprint.also {
-                if (!it.resolve(context, result.classDef))
-                    throw ShowOldPlaybackSpeedMenuFingerprint.exception
-            }.result!!.method.toString()
+            val showOldPlaybackSpeedMenuMethod = ShowOldPlaybackSpeedMenuFingerprint.alsoResolve(
+                context,
+                GetOldPlaybackSpeedsFingerprint
+            ).method.toString()
 
             // Insert the call to the "showOldPlaybackSpeedMenu" method on the field INSTANCE.
-            ShowOldPlaybackSpeedMenuIntegrationsFingerprint.result?.mutableMethod?.apply {
+            ShowOldPlaybackSpeedMenuIntegrationsFingerprint.resultOrThrow().mutableMethod.apply {
                 addInstructionsWithLabels(
                     implementation!!.instructions.lastIndex,
                     """
@@ -171,8 +169,16 @@ object CustomPlaybackSpeedPatch : BytecodePatch(
                         invoke-virtual { v0 }, $showOldPlaybackSpeedMenuMethod
                     """
                 )
-            } ?: throw ShowOldPlaybackSpeedMenuIntegrationsFingerprint.exception
-        } ?: throw GetOldPlaybackSpeedsFingerprint.exception
+            }
+        }
+
+        // region Force old video quality menu.
+        // This is necessary, because there is no known way of adding custom playback speeds to the new menu.
+
+        RecyclerViewTreeHookPatch.addHook(INTEGRATIONS_CLASS_DESCRIPTOR)
+
+        // Required to check if the playback speed menu is currently shown.
+        LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
 
         // endregion
     }
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt
index efe99d7afd..a1297ed31d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt
@@ -3,17 +3,22 @@ package app.revanced.patches.youtube.video.videoid
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
-import app.revanced.patcher.fingerprint.MethodFingerprint
 import app.revanced.patcher.patch.BytecodePatch
 import app.revanced.patcher.patch.annotation.Patch
 import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
 import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
+import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdBackgroundPlayFingerprint
 import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprint
-import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay
-import app.revanced.util.exception
+import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdParentFingerprint
+import app.revanced.util.alsoResolve
+import app.revanced.util.getReference
+import app.revanced.util.indexOfFirstInstruction
+import app.revanced.util.resultOrThrow
+import com.android.tools.smali.dexlib2.iface.Method
 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
+import com.android.tools.smali.dexlib2.iface.reference.MethodReference
 
 @Patch(
     description = "Hooks to detect when the video id changes",
@@ -21,8 +26,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
 )
 object VideoIdPatch : BytecodePatch(
     setOf(
-        VideoIdFingerprint,
-        VideoIdFingerprintBackgroundPlay
+        VideoIdParentFingerprint,
+        VideoIdBackgroundPlayFingerprint,
     )
 ) {
     private var videoIdRegister = 0
@@ -35,35 +40,28 @@ object VideoIdPatch : BytecodePatch(
 
     override fun execute(context: BytecodeContext) {
 
-        /**
-         * Supplies the method and register index of the video id register.
-         *
-         * @param consumer Consumer that receives the method, insert index and video id register index.
-         */
-        fun MethodFingerprint.setFields(consumer: (MutableMethod, Int, Int) -> Unit) = result?.let { result ->
-            val videoIdRegisterIndex = result.scanResult.patternScanResult!!.endIndex
-
-            result.mutableMethod.let {
-                val videoIdRegister = it.getInstruction(videoIdRegisterIndex).registerA
-                val insertIndex = videoIdRegisterIndex + 1
-                consumer(it, insertIndex, videoIdRegister)
-
-            }
-        } ?: throw exception
-
-        VideoIdFingerprint.setFields { method, index, register ->
-            videoIdMethod = method
-            videoIdInsertIndex = index
-            videoIdRegister = register
+        VideoIdFingerprint.alsoResolve(context, VideoIdParentFingerprint).mutableMethod.apply {
+            videoIdMethod = this
+            val index = indexOfPlayerResponseModelString()
+            videoIdRegister = getInstruction(index + 1).registerA
+            videoIdInsertIndex = index + 2
         }
 
-        VideoIdFingerprintBackgroundPlay.setFields { method, insertIndex, videoIdRegister ->
-            backgroundPlaybackMethod = method
-            backgroundPlaybackInsertIndex = insertIndex
-            backgroundPlaybackVideoIdRegister = videoIdRegister
+        VideoIdBackgroundPlayFingerprint.resultOrThrow().mutableMethod.apply {
+            backgroundPlaybackMethod = this
+            val index = indexOfPlayerResponseModelString()
+            backgroundPlaybackVideoIdRegister = getInstruction(index + 1).registerA
+            backgroundPlaybackInsertIndex = index + 2
         }
     }
 
+    internal fun Method.indexOfPlayerResponseModelString() =
+        indexOfFirstInstruction {
+            val reference = getReference()
+            reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;" &&
+                    reference.returnType == "Ljava/lang/String;"
+        }
+
     /**
      * Hooks the new video id when the video changes.
      *
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdBackgroundPlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdBackgroundPlayFingerprint.kt
new file mode 100644
index 0000000000..afddaca5a9
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdBackgroundPlayFingerprint.kt
@@ -0,0 +1,32 @@
+package app.revanced.patches.youtube.video.videoid.fingerprint
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import app.revanced.patches.youtube.video.videoid.VideoIdPatch.indexOfPlayerResponseModelString
+import com.android.tools.smali.dexlib2.AccessFlags
+import com.android.tools.smali.dexlib2.Opcode
+
+internal object VideoIdBackgroundPlayFingerprint : MethodFingerprint(
+    returnType = "V",
+    parameters = listOf("L"),
+    opcodes = listOf(
+        Opcode.IF_EQZ,
+        Opcode.INVOKE_INTERFACE,
+        Opcode.MOVE_RESULT_OBJECT,
+        Opcode.IPUT_OBJECT,
+        Opcode.MONITOR_EXIT,
+        Opcode.RETURN_VOID,
+        Opcode.MONITOR_EXIT,
+        Opcode.RETURN_VOID
+    ),
+    // The target snippet of code is buried in a huge switch block and the target method
+    // has been changed many times by YT which makes identifying it more difficult than usual.
+    customFingerprint = { methodDef, classDef ->
+        // Access flags changed in 19.36
+        (methodDef.accessFlags == (AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED) ||
+            methodDef.accessFlags == (AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED)) &&
+                classDef.methods.count() == 17 &&
+                methodDef.implementation != null &&
+                methodDef.indexOfPlayerResponseModelString() >= 0
+    }
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt
index a01b2ebdcc..cb032b18e7 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt
@@ -2,6 +2,7 @@ package app.revanced.patches.youtube.video.videoid.fingerprint
 
 import app.revanced.patcher.extensions.or
 import app.revanced.patcher.fingerprint.MethodFingerprint
+import app.revanced.patches.youtube.video.videoid.VideoIdPatch.indexOfPlayerResponseModelString
 import com.android.tools.smali.dexlib2.AccessFlags
 import com.android.tools.smali.dexlib2.Opcode
 
@@ -10,13 +11,12 @@ internal object VideoIdFingerprint : MethodFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     parameters = listOf("L"),
     opcodes = listOf(
-        Opcode.MOVE_RESULT_OBJECT,
-        Opcode.IF_EQZ,
-        Opcode.IGET_OBJECT,
-        Opcode.IGET_OBJECT,
         Opcode.INVOKE_INTERFACE,
         Opcode.MOVE_RESULT_OBJECT,
         Opcode.INVOKE_INTERFACE,
         Opcode.MOVE_RESULT_OBJECT,
-    )
+    ),
+    customFingerprint = { methodDef, _ ->
+        methodDef.indexOfPlayerResponseModelString() >= 0
+    }
 )
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt
deleted file mode 100644
index 5bc5d4fd3b..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package app.revanced.patches.youtube.video.videoid.fingerprint
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patcher.fingerprint.MethodFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.Opcode
-
-internal object VideoIdFingerprintBackgroundPlay : MethodFingerprint(
-    returnType = "V",
-    accessFlags = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
-    parameters = listOf("L"),
-    opcodes = listOf(
-        Opcode.INVOKE_VIRTUAL,
-        Opcode.MOVE_RESULT,
-        Opcode.IF_EQZ,
-        Opcode.IGET_OBJECT,
-        Opcode.IF_EQZ,
-        Opcode.INVOKE_INTERFACE,
-        Opcode.MOVE_RESULT_OBJECT,
-    ),
-)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdParentFingerprint.kt
new file mode 100644
index 0000000000..d91633ed46
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdParentFingerprint.kt
@@ -0,0 +1,12 @@
+package app.revanced.patches.youtube.video.videoid.fingerprint
+
+import app.revanced.patcher.extensions.or
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+internal object VideoIdParentFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "[L",
+    parameters = listOf("L"),
+    literalSupplier = { 524288L }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt
index 5e60a69966..8f577d6885 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt
@@ -29,30 +29,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
         CompatiblePackage(
             "com.google.android.youtube",
             [
-                "18.32.39",
-                "18.37.36",
                 "18.38.44",
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
                 "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
                 "19.16.39",
+                "19.25.37",
+                "19.34.42",
             ],
         ),
     ],
diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
index 98ec71428e..c9b146645a 100644
--- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
+++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
@@ -3,6 +3,9 @@ package app.revanced.util
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
 import app.revanced.patcher.fingerprint.MethodFingerprint
 import app.revanced.patcher.patch.PatchException
 import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
@@ -15,7 +18,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
 import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
 import com.android.tools.smali.dexlib2.iface.reference.Reference
 import com.android.tools.smali.dexlib2.util.MethodUtil
-import org.stringtemplate.v4.compiler.Bytecode.instructions
 
 fun MethodFingerprint.resultOrThrow() = result ?: throw exception
 
@@ -66,6 +68,37 @@ fun MutableMethod.injectHideViewCall(
     "invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V",
 )
 
+/**
+ * Inserts instructions at a given index, using the existing control flow label at that index.
+ * Inserted instructions can have it's own control flow labels as well.
+ *
+ * Effectively this changes the code from:
+ * :label
+ * (original code)
+ *
+ * Into:
+ * :label
+ * (patch code)
+ * (original code)
+ */
+internal fun MutableMethod.addInstructionsAtControlFlowLabel(
+    insertIndex: Int,
+    instructions: String,
+) {
+    // Duplicate original instruction and add to +1 index.
+    addInstruction(insertIndex + 1, getInstruction(insertIndex))
+
+    // Add patch code at same index as duplicated instruction,
+    // so it uses the original instruction control flow label.
+    addInstructionsWithLabels(insertIndex + 1, instructions)
+
+    // Remove original non duplicated instruction.
+    removeInstruction(insertIndex)
+
+    // Original instruction is now after the inserted patch instructions,
+    // and the original control flow label is on the first instruction of the patch code.
+}
+
 /**
  * Get the index of the first instruction with the id of the given resource name.
  *
@@ -98,6 +131,9 @@ fun Method.indexOfIdResourceOrThrow(resourceName: String): Int {
     return index
 }
 
+// TODO Rename these from 'FirstWideLiteralInstruction' to 'FirstLiteralInstruction',
+// since NarrowLiteralInstruction is a subclass of WideLiteralInstruction.
+
 /**
  * Find the index of the first wide literal instruction with the given value.
  *
@@ -189,6 +225,23 @@ inline fun  Instruction.getReference() = (this as? Refere
 // @Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
 fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
 
+/**
+ * @return The index of the first opcode specified, or -1 if not found.
+ * @see indexOfFirstInstructionOrThrow
+ */
+fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int =
+    indexOfFirstInstruction(0, targetOpcode)
+
+/**
+ * @param startIndex Optional starting index to start searching from.
+ * @return The index of the first opcode specified, or -1 if not found.
+ * @see indexOfFirstInstructionOrThrow
+ */
+fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int =
+    indexOfFirstInstruction(startIndex) {
+        opcode == targetOpcode
+    }
+
 /**
  * Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
  *
@@ -197,7 +250,11 @@ fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = index
  * @see indexOfFirstInstructionOrThrow
  */
 fun Method.indexOfFirstInstruction(startIndex: Int = 0, predicate: Instruction.() -> Boolean): Int {
-    val index = this.implementation!!.instructions.drop(startIndex).indexOfFirst(predicate)
+    var instructions = this.implementation!!.instructions
+    if (startIndex != 0) {
+        instructions = instructions.drop(startIndex)
+    }
+    val index = instructions.indexOfFirst(predicate)
 
     return if (index >= 0) {
         startIndex + index
@@ -206,6 +263,24 @@ fun Method.indexOfFirstInstruction(startIndex: Int = 0, predicate: Instruction.(
     }
 }
 
+/**
+ * @return The index of the first opcode specified
+ * @throws PatchException
+ * @see indexOfFirstInstruction
+ */
+fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int =
+    indexOfFirstInstructionOrThrow(0, targetOpcode)
+
+/**
+ * @return The index of the first opcode specified, starting from the index specified.
+ * @throws PatchException
+ * @see indexOfFirstInstruction
+ */
+fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int =
+    indexOfFirstInstructionOrThrow(startIndex) {
+        opcode == targetOpcode
+    }
+
 /**
  * Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
  *
@@ -218,6 +293,68 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instru
     if (index < 0) {
         throw PatchException("Could not find instruction index")
     }
+
+    return index
+}
+
+/**
+ * Get the index of matching instruction,
+ * starting from and [startIndex] and searching down.
+ *
+ * @param startIndex Optional starting index to search down from. Searching includes the start index.
+ * @return -1 if the instruction is not found.
+ * @see indexOfFirstInstructionReversedOrThrow
+ */
+fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int =
+    indexOfFirstInstructionReversed(startIndex) {
+        opcode == targetOpcode
+    }
+
+/**
+ * Get the index of matching instruction,
+ * starting from and [startIndex] and searching down.
+ *
+ * @param startIndex Optional starting index to search down from. Searching includes the start index.
+ * @return -1 if the instruction is not found.
+ * @see indexOfFirstInstructionReversedOrThrow
+ */
+fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, predicate: Instruction.() -> Boolean): Int {
+    var instructions = this.implementation!!.instructions
+    if (startIndex != null) {
+        instructions = instructions.take(startIndex + 1)
+    }
+
+    return instructions.indexOfLast(predicate)
+}
+
+/**
+ * Get the index of matching instruction,
+ * starting from and [startIndex] and searching down.
+ *
+ * @param startIndex Optional starting index to search down from. Searching includes the start index.
+ * @return -1 if the instruction is not found.
+ * @see indexOfFirstInstructionReversed
+ */
+fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int =
+    indexOfFirstInstructionReversedOrThrow(startIndex) {
+        opcode == targetOpcode
+    }
+
+/**
+ * Get the index of matching instruction,
+ * starting from and [startIndex] and searching down.
+ *
+ * @param startIndex Optional starting index to search down from. Searching includes the start index.
+ * @return -1 if the instruction is not found.
+ * @see indexOfFirstInstructionReversed
+ */
+fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, predicate: Instruction.() -> Boolean): Int {
+    val index = indexOfFirstInstructionReversed(startIndex, predicate)
+
+    if (index < 0) {
+        throw PatchException("Could not find instruction index")
+    }
+
     return index
 }
 
@@ -242,6 +379,26 @@ fun Method.findOpcodeIndicesReversed(filter: Instruction.() -> Boolean): List Unit,
+) {
+    classes.forEach { classDef ->
+        classDef.methods.forEach { method ->
+            method.implementation?.instructions?.forEachIndexed { index, instruction ->
+                if (instruction.opcode == Opcode.CONST &&
+                    (instruction as WideLiteralInstruction).wideLiteral == literal
+                ) {
+                    val mutableMethod = proxy(classDef).mutableClass.findMutableMethodOf(method)
+                    block.invoke(mutableMethod, index)
+                }
+            }
+        }
+    }
+}
 
 /**
  * Return the resolved method early.
diff --git a/src/main/kotlin/app/revanced/util/patch/LiteralValueFingerprint.kt b/src/main/kotlin/app/revanced/util/patch/LiteralValueFingerprint.kt
index 6b1b67174e..db53978bcb 100644
--- a/src/main/kotlin/app/revanced/util/patch/LiteralValueFingerprint.kt
+++ b/src/main/kotlin/app/revanced/util/patch/LiteralValueFingerprint.kt
@@ -28,6 +28,7 @@ abstract class LiteralValueFingerprint(
     parameters = parameters,
     opcodes = opcodes,
     strings = strings,
+    // TODO: add a way for subclasses to also use their own custom fingerprint.
     customFingerprint = { methodDef, _ ->
         methodDef.containsWideLiteralInstructionValue(literalSupplier())
     }
diff --git a/src/main/resources/addresources/values/arrays.xml b/src/main/resources/addresources/values/arrays.xml
index 32751b87be..829f9533e5 100644
--- a/src/main/resources/addresources/values/arrays.xml
+++ b/src/main/resources/addresources/values/arrays.xml
@@ -29,7 +29,7 @@
             
         
         
-            
+            
                 @string/revanced_miniplayer_type_entry_1
                 @string/revanced_miniplayer_type_entry_2
                 @string/revanced_miniplayer_type_entry_3
@@ -37,7 +37,7 @@
                 @string/revanced_miniplayer_type_entry_5
                 @string/revanced_miniplayer_type_entry_6
             
-            
+            
                 
                 ORIGINAL
                 PHONE
@@ -58,30 +58,44 @@
             
         
         
-            
-                @string/revanced_start_page_entry_0
-                @string/revanced_start_page_entry_1
-                @string/revanced_start_page_entry_2
-                @string/revanced_start_page_entry_3
-                @string/revanced_start_page_entry_4
-                @string/revanced_start_page_entry_5
-                @string/revanced_start_page_entry_6
-                @string/revanced_start_page_entry_7
-                @string/revanced_start_page_entry_8
-                @string/revanced_start_page_entry_9
-            
-            
-                
-                MAIN
-                open.search
-                open.subscriptions
-                open.explore
-                open.shorts
-                www.youtube.com/feed/library
-                
-                www.youtube.com/playlist?list=LL
-                www.youtube.com/feed/history
-                www.youtube.com/feed/trending
+            
+                @string/revanced_change_start_page_entry_default
+                @string/revanced_change_start_page_entry_search
+                Shorts 
+                @string/revanced_change_start_page_entry_subscriptions
+                @string/revanced_change_start_page_entry_explore
+                @string/revanced_change_start_page_entry_library
+                @string/revanced_change_start_page_entry_liked_videos
+                @string/revanced_change_start_page_entry_watch_later
+                @string/revanced_change_start_page_entry_history
+                @string/revanced_change_start_page_entry_trending
+                @string/revanced_change_start_page_entry_gaming
+                @string/revanced_change_start_page_entry_live
+                @string/revanced_change_start_page_entry_music
+                @string/revanced_change_start_page_entry_movies
+                @string/revanced_change_start_page_entry_sports
+                @string/revanced_change_start_page_entry_browse
+            
+            
+                
+                ORIGINAL
+                
+                SEARCH
+                SHORTS
+                
+                SUBSCRIPTIONS
+                EXPLORE
+                LIBRARY
+                LIKED_VIDEO
+                WATCH_LATER
+                HISTORY
+                TRENDING
+                GAMING
+                LIVE
+                MUSIC
+                MOVIE
+                SPORTS
+                BROWSE
             
         
         
diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml
index c1625a4e26..00f138b057 100644
--- a/src/main/resources/addresources/values/strings.xml
+++ b/src/main/resources/addresources/values/strings.xml
@@ -972,21 +972,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
             17.33.42 - Restore old UI layout
         
         
-            Set start page
-            Default
-            
-            Home
-            Search
-            
-            Subscriptions
-            Explore
-            Shorts
-            
-            You tab
-            Liked videos
-            
-            History
-            Trending
+            Set start page
+            Default
+            Browse channels
+            Explore
+            Gaming
+            History
+            Library
+            Liked videos
+            Live
+            Movies
+            Music
+            Search
+            Sports
+            Subscriptions
+            Trending
+            Watch later
         
         
             Disable resuming Shorts player
@@ -1009,15 +1010,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
             Modern 1
             Modern 2
             Modern 3
-            Hide expand and close buttons
-            Buttons are hidden\n(swipe miniplayer to expand or close)
-            Expand and close buttons are shown
+            Enable rounded corners
+            Corners are rounded
+            Corners are square
+            Enable double-tap and pinch to resize
+            Double-tap action and pinch to resize is enabled\n\n• Double tap to increase miniplayer size\n• Double tap again to restore original size
+            Double-tap action and pinch to resize is disabled
+            Enable drag and drop
+            Drag and drop is enabled\n\nMiniplayer can be dragged to any corner of the screen
+            Drag and drop is disabled
+            Hide close button
+            Close button is hidden
+            Close button is shown
+            Hide expand and close buttons
+            Buttons are hidden\n\nSwipe to expand or close
+            Expand and close buttons are shown
             Hide subtexts
             Subtexts are hidden
             Subtexts are shown
             Hide skip forward and back buttons
             Skip forward and back are hidden
             Skip forward and back are shown
+            Initial size
+            Initial on screen size, in pixels
+            Pixel size must be between %1$s and %2$s
             Overlay opacity
             Opacity value between 0-100, where 0 is transparent
             Miniplayer overlay opacity must be between 0-100
@@ -1033,7 +1049,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
             Original seekbar color is shown
             Custom seekbar color
             The color of the seekbar
-            Invalid seekbar color value. Using default value.
+            Invalid seekbar color value
         
         
             Bypass image region restrictions
diff --git a/src/main/resources/settings/host/values/styles.xml b/src/main/resources/settings/host/values/styles.xml
new file mode 100644
index 0000000000..7c8412f9f6
--- /dev/null
+++ b/src/main/resources/settings/host/values/styles.xml
@@ -0,0 +1,25 @@
+
+
+
+    
+

From ca0c8cd973a4f4a7c21b81156a2427613640b951 Mon Sep 17 00:00:00 2001
From: semantic-release-bot 
Date: Sat, 19 Oct 2024 12:29:04 +0000
Subject: [PATCH 28/39] chore: Release v4.17.0-dev.11 [skip ci]

# [4.17.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.10...v4.17.0-dev.11) (2024-10-19)

### Features

* **YouTube:** Support versions `19.25` and `19.34` ([#3629](https://github.com/ReVanced/revanced-patches/issues/3629)) ([049e7f0](https://github.com/ReVanced/revanced-patches/commit/049e7f081358d2e1bf87d30e87b01c61b5eeafcc))
---
 CHANGELOG.md      | 7 +++++++
 gradle.properties | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac0b0e0f3a..c148a25204 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [4.17.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.10...v4.17.0-dev.11) (2024-10-19)
+
+
+### Features
+
+* **YouTube:** Support versions `19.25` and `19.34` ([#3629](https://github.com/ReVanced/revanced-patches/issues/3629)) ([049e7f0](https://github.com/ReVanced/revanced-patches/commit/049e7f081358d2e1bf87d30e87b01c61b5eeafcc))
+
 # [4.17.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.9...v4.17.0-dev.10) (2024-10-17)
 
 
diff --git a/gradle.properties b/gradle.properties
index e24f3e4f33..d8565e1d42 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
 org.gradle.parallel = true
 org.gradle.caching = true
 kotlin.code.style = official
-version = 4.17.0-dev.10
+version = 4.17.0-dev.11

From 828a634667c4005a90f3e469ad2c5d69387f0760 Mon Sep 17 00:00:00 2001
From: MarcaD <152095496+MarcaDian@users.noreply.github.com>
Date: Sat, 19 Oct 2024 15:39:08 +0300
Subject: [PATCH 29/39] feat(YouTube - Hide Shorts components): Hide `Hashtag`
 button (#3787)

---
 .../layout/hide/shorts/HideShortsComponentsResourcePatch.kt    | 1 +
 src/main/resources/addresources/values/strings.xml             | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt
index 38a7e99eba..7c1f10ccc4 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt
@@ -55,6 +55,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() {
             SwitchPreference("revanced_hide_shorts_use_template_button"),
             SwitchPreference("revanced_hide_shorts_upcoming_button"),
             SwitchPreference("revanced_hide_shorts_green_screen_button"),
+            SwitchPreference("revanced_hide_shorts_hashtag_button"),
             SwitchPreference("revanced_hide_shorts_shop_button"),
             SwitchPreference("revanced_hide_shorts_tagged_products"),
             SwitchPreference("revanced_hide_shorts_stickers"),
diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml
index 00f138b057..712d8d2fdf 100644
--- a/src/main/resources/addresources/values/strings.xml
+++ b/src/main/resources/addresources/values/strings.xml
@@ -648,6 +648,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
             Hide green screen button
             Green screen button is hidden
             Green screen button is shown
+            Hide hashtag button
+            Hashtag button is hidden
+            Hashtag button is shown
             Hide search suggestions
             Search suggestions are hidden
             Search suggestions are shown

From 9ed6ca64e5781871accdc3adf448a6950833503e Mon Sep 17 00:00:00 2001
From: semantic-release-bot 
Date: Sat, 19 Oct 2024 12:41:16 +0000
Subject: [PATCH 30/39] chore: Release v4.17.0-dev.12 [skip ci]

# [4.17.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.11...v4.17.0-dev.12) (2024-10-19)

### Features

* **YouTube - Hide Shorts components:** Hide `Hashtag` button ([#3787](https://github.com/ReVanced/revanced-patches/issues/3787)) ([828a634](https://github.com/ReVanced/revanced-patches/commit/828a634667c4005a90f3e469ad2c5d69387f0760))
---
 CHANGELOG.md      | 7 +++++++
 gradle.properties | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c148a25204..5aaba89536 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [4.17.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.11...v4.17.0-dev.12) (2024-10-19)
+
+
+### Features
+
+* **YouTube - Hide Shorts components:** Hide `Hashtag` button ([#3787](https://github.com/ReVanced/revanced-patches/issues/3787)) ([828a634](https://github.com/ReVanced/revanced-patches/commit/828a634667c4005a90f3e469ad2c5d69387f0760))
+
 # [4.17.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.10...v4.17.0-dev.11) (2024-10-19)
 
 
diff --git a/gradle.properties b/gradle.properties
index d8565e1d42..5214f0d447 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
 org.gradle.parallel = true
 org.gradle.caching = true
 kotlin.code.style = official
-version = 4.17.0-dev.11
+version = 4.17.0-dev.12

From 54bfc4b0124f0554dd1c12d4f79812c8d16bc2d5 Mon Sep 17 00:00:00 2001
From: oSumAtrIX 
Date: Sat, 19 Oct 2024 15:03:25 +0200
Subject: [PATCH 31/39] ci: Grant workflow necessary permission

---
 .github/workflows/pull_strings.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/pull_strings.yml b/.github/workflows/pull_strings.yml
index dfed101ef3..fee4fcea49 100644
--- a/.github/workflows/pull_strings.yml
+++ b/.github/workflows/pull_strings.yml
@@ -10,6 +10,7 @@ jobs:
     name: Pull strings
     permissions:
       contents: write
+      pull-requests: write
     runs-on: ubuntu-latest
     steps:
       - name: Checkout

From fccc401a596ea08fc97505c555786cb872165ba3 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Sat, 19 Oct 2024 09:08:25 -0400
Subject: [PATCH 32/39] chore: Sync translations (#3789)

Co-authored-by: revanced-bot 
---
 .../addresources/values-af-rZA/strings.xml    |   5 +-
 .../addresources/values-am-rET/strings.xml    |   5 +-
 .../addresources/values-ar-rSA/strings.xml    |  77 ++-
 .../addresources/values-as-rIN/strings.xml    |   5 +-
 .../addresources/values-az-rAZ/strings.xml    |  65 ++-
 .../addresources/values-be-rBY/strings.xml    |  29 +-
 .../addresources/values-bg-rBG/strings.xml    |  52 +-
 .../addresources/values-bn-rBD/strings.xml    |  91 ++-
 .../addresources/values-bs-rBA/strings.xml    |   5 +-
 .../addresources/values-ca-rES/strings.xml    |   7 +-
 .../addresources/values-cs-rCZ/strings.xml    |  78 ++-
 .../addresources/values-da-rDK/strings.xml    |  77 ++-
 .../addresources/values-de-rDE/strings.xml    |  78 ++-
 .../addresources/values-el-rGR/strings.xml    |  74 ++-
 .../addresources/values-es-rES/strings.xml    |  79 ++-
 .../addresources/values-et-rEE/strings.xml    |   6 +-
 .../addresources/values-eu-rES/strings.xml    |   5 +-
 .../addresources/values-fa-rIR/strings.xml    |   6 +-
 .../addresources/values-fi-rFI/strings.xml    |  78 ++-
 .../addresources/values-fil-rPH/strings.xml   |  26 +-
 .../addresources/values-fr-rFR/strings.xml    | 521 ++++++++++--------
 .../addresources/values-ga-rIE/strings.xml    |  51 +-
 .../addresources/values-gl-rES/strings.xml    |   5 +-
 .../addresources/values-gu-rIN/strings.xml    |   5 +-
 .../addresources/values-hi-rIN/strings.xml    |   7 +-
 .../addresources/values-hr-rHR/strings.xml    |   6 +-
 .../addresources/values-hu-rHU/strings.xml    |  51 +-
 .../addresources/values-hy-rAM/strings.xml    |   5 +-
 .../addresources/values-in-rID/strings.xml    |  73 +--
 .../addresources/values-is-rIS/strings.xml    |   6 +-
 .../addresources/values-it-rIT/strings.xml    |  77 ++-
 .../addresources/values-iw-rIL/strings.xml    |   7 +-
 .../addresources/values-ja-rJP/strings.xml    |  75 ++-
 .../addresources/values-ka-rGE/strings.xml    |   5 +-
 .../addresources/values-kk-rKZ/strings.xml    |   5 +-
 .../addresources/values-km-rKH/strings.xml    |   5 +-
 .../addresources/values-kn-rIN/strings.xml    |   5 +-
 .../addresources/values-ko-rKR/strings.xml    |  63 ++-
 .../addresources/values-ky-rKG/strings.xml    |   5 +-
 .../addresources/values-lo-rLA/strings.xml    |   5 +-
 .../addresources/values-lt-rLT/strings.xml    |   6 +-
 .../addresources/values-lv-rLV/strings.xml    |   6 +-
 .../addresources/values-mk-rMK/strings.xml    |   5 +-
 .../addresources/values-ml-rIN/strings.xml    |   5 +-
 .../addresources/values-mn-rMN/strings.xml    |   5 +-
 .../addresources/values-mr-rIN/strings.xml    |   5 +-
 .../addresources/values-ms-rMY/strings.xml    |   5 +-
 .../addresources/values-my-rMM/strings.xml    |   5 +-
 .../addresources/values-nb-rNO/strings.xml    |  76 ++-
 .../addresources/values-ne-rIN/strings.xml    |   5 +-
 .../addresources/values-nl-rNL/strings.xml    |  77 ++-
 .../addresources/values-or-rIN/strings.xml    |   6 +-
 .../addresources/values-pa-rIN/strings.xml    |   5 +-
 .../addresources/values-pl-rPL/strings.xml    |  81 ++-
 .../addresources/values-pt-rBR/strings.xml    |  38 +-
 .../addresources/values-pt-rPT/strings.xml    |  77 ++-
 .../addresources/values-ro-rRO/strings.xml    |  78 ++-
 .../addresources/values-ru-rRU/strings.xml    |  79 ++-
 .../addresources/values-si-rLK/strings.xml    |   5 +-
 .../addresources/values-sk-rSK/strings.xml    |  29 +-
 .../addresources/values-sl-rSI/strings.xml    |   7 +-
 .../addresources/values-sq-rAL/strings.xml    |   5 +-
 .../addresources/values-sr-rCS/strings.xml    |  59 +-
 .../addresources/values-sr-rSP/strings.xml    |  59 +-
 .../addresources/values-sv-rSE/strings.xml    |  77 ++-
 .../addresources/values-sw-rKE/strings.xml    |   5 +-
 .../addresources/values-ta-rIN/strings.xml    |   7 +-
 .../addresources/values-te-rIN/strings.xml    |   5 +-
 .../addresources/values-th-rTH/strings.xml    |   6 +-
 .../addresources/values-tr-rTR/strings.xml    |  46 +-
 .../addresources/values-uk-rUA/strings.xml    |  94 +++-
 .../addresources/values-ur-rIN/strings.xml    |   5 +-
 .../addresources/values-uz-rUZ/strings.xml    |   5 +-
 .../addresources/values-vi-rVN/strings.xml    |  35 +-
 .../addresources/values-zh-rCN/strings.xml    |  76 ++-
 .../addresources/values-zh-rTW/strings.xml    | 115 ++--
 .../addresources/values-zu-rZA/strings.xml    |   5 +-
 77 files changed, 1879 insertions(+), 1160 deletions(-)

diff --git a/src/main/resources/addresources/values-af-rZA/strings.xml b/src/main/resources/addresources/values-af-rZA/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-af-rZA/strings.xml
+++ b/src/main/resources/addresources/values-af-rZA/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-am-rET/strings.xml b/src/main/resources/addresources/values-am-rET/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-am-rET/strings.xml
+++ b/src/main/resources/addresources/values-am-rET/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-ar-rSA/strings.xml b/src/main/resources/addresources/values-ar-rSA/strings.xml
index df70bc4809..9ec87c816b 100644
--- a/src/main/resources/addresources/values-ar-rSA/strings.xml
+++ b/src/main/resources/addresources/values-ar-rSA/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   يتم عرض قسم النص
   وصف الفيديو
   إخفاء أو عرض مكونات وصف الفيديو
+  
+  إخفاء رسومات YouTube
+  تم إخفاء رسومات شريط البحث
+  يتم عرض رسومات شريط البحث
+  تظهر رسومات  YouTube Doodles لعدة أيام كل عام.\n\nإذا كانت الرسومات تظهر حاليًا في منطقتك وإعداد الإخفاء هذا قيد التشغيل، سيتم أيضًا إخفاء شريط الفلتر أسفل شريط البحث.
   فلتر مخصص
   إخفاء المكونات باستخدام فلاتر مخصصة
   تمكين الفلتر المخصص
@@ -628,14 +633,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   تم إخفاء تسمية الموقع
   يتم عرض تسمية الموقع
   إخفاء زر حفظ الموسيقى
-  تم إخفاء حفظ الموسيقى
-  يتم عرض حفظ الموسيقى
+  تم إخفاء زر حفظ الموسيقى
+  يتم عرض زر حفظ الموسيقى
+  إخفاء زر استخدام القالب
+  تم إخفاء زر استخدام القالب
+  يتم عرض زر استخدام القالب
+  إخفاء زر القادم
+  تم إخفاء زر القادم
+  يتم عرض زر القادم
+  إخفاء زر الشاشة الخضراء
+  تم إخفاء زر الشاشة الخضراء
+  يتم عرض زر الشاشة الخضراء
+  إخفاء زر Hashg
+  زر علامة هاشج مخفي
+  يتم عرض زر الوسم
   إخفاء اقتراحات البحث
   تم إخفاء اقتراحات البحث
   يتم عرض اقتراحات البحث
   إخفاء الملصقات
   تم إخفاء الملصقات
   يتم عرض الملصقات
+  إخفاء نافورة أعجبني
+  تم إخفاء تأثير النافورة لـزر أعجبني
+  يتم عرض تأثير النافورة لـزر أعجبني
   إخفاء زر أعجبني
   تم إخفاء زر أعجبني
   يتم عرض زر أعجبني
@@ -946,20 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - استعادة تصميم واجهة المستخدم القديم
   
   
-  تعيين صفحة البداية
-  إفتراضي
-  
-  الصفحة الرئيسية
-  البحث
-  
-  الاشتراكات
-  استكشف
-  
-  علامة التبويب أنت
-  الفيديوهات التي أعجبتني
-  
-  السّجل
-  المحتوى الرائج
+  تعيين صفحة البداية
+  الافتراضي
+  تصفح القنوات
+  استكشف
+  ألعاب
+  السّجل
+  المكتبة
+  الفيديوهات التي أعجبتني
+  مباشر
+  أفلام
+  الموسيقى
+  البحث
+  الرياضة
+  الاشتراكات
+  المحتوى الرائج
+  شاهد لاحقاً
   
   
   تعطيل استئناف مشغل Shorts
@@ -982,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   حديث 1
   حديث 2
   حديث 3
-  إخفاء أزرار التوسيع والإغلاق
-  تم إخفاء الأزرار\n(مرر المشغل المصغر للتوسع أو الإغلاق)
-  يتم عرض أزرار التوسيع والإغلاق
+  تمكين زوايا مستديرة
+  يتم تدوير الزوايا
+  الزوايا مربعة
+  تمكين النقر المزدوج و الدبوس لتغيير الحجم
+  تم تمكين إجراء الضغط المزدوج والدبوس لتغيير الحجم\n\n• النقر المزدوج لزيادة حجم اللاعب الصغير\n• النقر المزدوج مرة أخرى لاستعادة الحجم الأصلي
+  إجراء النقر المزدوج والدبوس لتغيير الحجم معطل
+  تمكين السحب والإفلات
+  السحب والإسقاط مفعلان\n\nيمكن سحب اللاعب الصغير إلى أي زاوية من الشاشة
+  تم تعطيل السحب والإسقاط
+  إخفاء زر الإغلاق
+  زر الإغلاق مخفي
+  يتم عرض زر الإغلاق
+  إخفاء أزرار التوسيع والإغلاق
+  الأزرار مخفية\n\nمرر للتوسع أو الإغلاق
+  تظهر أزرار التمديد والإغلاق
   إخفاء النصوص الفرعية
   تم إخفاء النصوص الفرعية
   يتم عرض النصوص الفرعية
   إخفاء أزرار التخطي للأمام والخلف
   تم إخفاء تخطي للأمام والخلف
   يتم عرض تخطي للأمام والخلف
+  الحجم الأولي
+  المبدئي على حجم الشاشة، بالبكسل
+  حجم البكسل يجب أن يكون بين %1$s و %2$s
   شفافية الواجهة
   قيمة الشفافية بين 0-100، حيث يكون 0 شفاف
   شفافية واجهة المشغل المصغر يجب أن تكون بين 0-100
@@ -1006,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   يتم عرض لون شريط تقدم الفيديو الاصلي
   لون شريط تقدم الفيديو المخصص
   لون شريط التقدم
-  لون الشريط غير صالح. استخدام القيمة الافتراضية.
+  لون شريط التقدم غير صالح
   
   
   تجاوز قيود منطقة الصورة
diff --git a/src/main/resources/addresources/values-as-rIN/strings.xml b/src/main/resources/addresources/values-as-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-as-rIN/strings.xml
+++ b/src/main/resources/addresources/values-as-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-az-rAZ/strings.xml b/src/main/resources/addresources/values-az-rAZ/strings.xml
index 34e9bb200a..e3141b5075 100644
--- a/src/main/resources/addresources/values-az-rAZ/strings.xml
+++ b/src/main/resources/addresources/values-az-rAZ/strings.xml
@@ -36,7 +36,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Yoxlamalar uğursuz oldu
   Xidməti veb saytı aç
   Yan keç
-  <h5>Bu tətbiq sizin tərəfinizdən yamaqlanmayıb.</h5><br>Bu tətbiq düzgün işləməyə bilər, <b>istifadə etmək zərərli və ya hətta təhlükəli ola bilər</b>.<br><br><br>Bu yoxlamalar bu tətbiqin əvvəldən yamaqlandığını və ya başqasından əldə edildiyini göstərir:<br><br><small>%1$s</small><br> <br>onu silməyiniz və özünüz yamaqlamağınız tövsiyə olunur. </b>təsdiqlənmiş və təhlükəsiz tətbiq istifadə etdiyinizə əmin olmaq üçün. <p><br> İnkar edilməzsə, bu xəbərdarlıq yalnız iki dəfə göstəriləcək.
+  <h5>Bu tətbiq sizin tərəfinizdən yamaqlanmayıb.</h5><br>Bu tətbiq düzgün işləməyə bilər, <b>istifadə etmək zərərli və ya hətta təhlükəli ola bilər</b>.<br><br>Bu yoxlamalar bu tətbiqin əvvəldən yamaqlandığını və ya başqasından əldə edildiyini göstərir:<br><br><small>%1$s</small><br> <br>onu silməyiniz və özünüz yamaqlamağınız tövsiyə olunur. </b>təsdiqlənmiş və təhlükəsiz tətbiq istifadə etdiyinizə əmin olmaq üçün. <p><br> İnkar edilməzsə, bu xəbərdarlıq yalnız iki dəfə göstəriləcək.
   Fərqli cihazda yamaqlanıb
   ReVanced Manager tərəfindən quraşdırılmayıb
   10 dəqiqədən çox əvvəl yamaqlanıb
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Transkripsiya bölməsi göstərilir
   Video açıqlaması
   Video açıqlaması elementlərini gizlət və ya göstər
+  
+  YouTube Doodle-ları gizlət
+  Axtarış çubuğu Doodle-ları gizlidir
+  Axtarış çubuğu Doodle-ları göstərilir
+  YouTube Doodle-lar hər il bir neçə gün göstərilir.\n\nDoodle hazırda bölgənizdə görünür və bu gizlətmə seçimi aktivdirsə, axtarış çubuğu altındakı filtr paneli də gizlədiləcək.
   Şəxsi filtr
   Fərdi filtrlər ilə elementləri gizlət
   Fərdi filtri aktivləşdir
@@ -438,8 +443,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Yayım düyməsi göstərilir
   
   
-  Naviqasiya düymələri
-  Naviqasiya çubuğundakı düymələri gizlət və ya dəyişdir
+  Fəaliyyət düymələri
+  Fəaliyyət çubuğundakı düymələri gizlət və ya dəyiş
   
   \"Ev\"i gizlət
   Əsas səhifə düyməsi gizlidir
@@ -460,7 +465,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   \"Yarat\"ı \"Bildirişlər\" ilə dəyişdir
   Yarat düyməsi Bildirişlər düyməsi ilə dəyişdirilir\n\nQeyd: Bunu aktivləşdirmə video reklamları da məcburən gizlədir
   \"Yarat\" düyməsi, \"Bildirişlər\" düyməsi ilə dəyişdirilmir
-  Naviqasiya düymə etiketlərini gizlət
+  Fəaliyyət düymə etiketlərini gizlət
   Etiketlər gizlidir
   Etiketlər göstərilir
   
@@ -628,14 +633,26 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Məkan etiketi gizlidir
   Məkan etiketi göstərilir
   \"Musiqini saxla\" düyməsini gizlət
-  \"Musiqini saxla\" gizlidir
-  \"Musiqini saxla\" göstərilir
+  \"Musiqini saxla\" düyməsi gizlidir
+  \"Musiqini saxla\" düyməsi göstərilir
+  \"Şablonu istifadə et\" düyməsini gizlət
+  \"Şablonu istifadə et\" düyməsi gizlidir
+  \"Şablonu istifadə et\" düyməsi göstərilir
+  \"Yaxınlaşan\" düyməsini gizlət
+  \"Yaxınlaşan\" düyməsi gizlidir
+  \"Yaxınlaşan\" düyməsi göstərilir
+  \"Yaşıl ekran\" düyməsini gizlət
+  \"Yaşıl ekran\" düyməsi gizlidir
+  \"Yaşıl ekran\" düyməsi göstərilir
   Axtarış təkliflərini gizlət
   Axtarış təklifləri gizlədilib
   Axtarış təklifləri göstərilir
   Stikerləri gizlət
   Stikerlər gizlidir
   Stikerlər göstərilir
+  Bəyən fəvvarəsini gizlət
+  \"Bəyən\" fəvvarə animasiyası gizlidir
+  \"Bəyən\" fəvvarə animasiyası göstərilir
   \"Bəyən\" düyməsini gizlət
   Bəyənmə düyməsi gizlidir
   Bəyənmə düyməsi göstərilir
@@ -671,9 +688,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Səs düyməsini gizlət
   Səs düyməsi gizlidir
   Səs düyməsi göstərilir
-  Naviqasiya çubuğunu gizlət
-  Naviqasiya çubuğu gizlidir
-  Naviqasiya çubuğu göstərilir
+  Fəaliyyət çubuğunu gizlət
+  Fəaliyyət çubuğu gizlidir
+  Fəaliyyət çubuğu göstərilir
   
   
   Təklif edilən video bitiş ekranın ləğv et
@@ -946,20 +963,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Köhnə UI tərtibatını bərpa et
   
   
-  Başlanğıc səhifəsini tənzimlə
-  İlkin
-  
-  Ev
-  Axtar
-  
-  Abunəliklər
-  Kəşf et
-  
-  \"Siz\" paneli
-  Bəyənilən videolar
-  
-  Tarixçə
-  Trenddə olan
+  Başlanğıc səhifəsini tənzimlə
+  İlkin
+  Kəşf et
+  Tarixçə
+  Kitabxana
+  Bəyənilən videolar
+  Axtar
+  Abunəliklər
+  Trenddə olan
   
   
   Shorts oynadıcı başladıcını bağla
@@ -982,9 +994,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Müasir 1
   Müasir 2
   Müasir 3
-  Genişləndir və bağla düymələrini gizlət
-  Gizlidir\n(genişləndirmək və ya bağlamaq üçün kiçik oynadıcını sürüşdür)
-  Genişləndirmə və bağlama düymələri göstərilir
+  Genişləndir və bağla düymələrini gizlət
+  Genişləndirmə və bağlama düymələri göstərilir
   Alt mətnləri gizlət
   Alt mətnlər gizlədilir
   Alt mətnlər göstərilir
@@ -1006,7 +1017,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Orijinal axtarma çubuğu rəngi göstərilir
   Fərdi axtarma çubuğu rəngi
   Axtarma çubuğu rəngi
-  Etibarsız axtarış çubuğu rəng dəyəri. İlkin dəyər işlədilir.
+  Yararsız zaman çubuğu rəng dəyəri
   
   
   Təsvir bölgə məhdudiyyətlərini ötür
diff --git a/src/main/resources/addresources/values-be-rBY/strings.xml b/src/main/resources/addresources/values-be-rBY/strings.xml
index 5215f5282e..df8a93411c 100644
--- a/src/main/resources/addresources/values-be-rBY/strings.xml
+++ b/src/main/resources/addresources/values-be-rBY/strings.xml
@@ -220,6 +220,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Паказваецца раздзел стэнаграмы
   Апісанне відэа
   Схаваць або паказаць кампаненты апісання відэа
+  
   Карыстальніцкі фільтр
   Схавайце кампаненты з дапамогай карыстацкіх фільтраў
   Уключыць карыстальніцкі фільтр
@@ -919,20 +920,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Аднавіць стары макет інтэрфейсу
   
   
-  Усталяваць стартавую старонку
-  Па змаўчанні
-  
-  дадому
-  Пошук
-  
-  Падпіскі
-  Дасьледуйце
-  
-  Вы ўкладка
-  Спадабаліся відэа
-  
-  Гісторыя
-  У трэндзе
+  Усталяваць стартавую старонку
+  Па змаўчанні
+  Дасьледуйце
+  Гісторыя
+  Спадабаліся відэа
+  Пошук
+  Падпіскі
+  У трэндзе
   
   
   Адключыць аднаўленне прайгравання Shorts
@@ -955,9 +950,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Сучасны 1
   Сучасны 2
   Сучасны 3
-  Схаваць кнопкі разгортвання і закрыцця
-  Кнопкі схаваны\n(правядзіце міні-прайгравальнік, каб разгарнуць або закрыць)
-  Паказваюцца кнопкі разгарнуць і закрыць
+  Схаваць кнопкі разгортвання і закрыцця
+  Паказваюцца кнопкі разгарнуць і закрыць
   Схаваць падтэксты
   Падтэксты схаваныя
   Паказваюцца падтэксты
@@ -979,7 +973,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Паказаны зыходны колер панэлі пошуку
   Карыстальніцкі колер панэлі пошуку
   Колер панэлі пошуку
-  Няправільнае значэнне колеру панэлі пошуку. Выкарыстоўваецца значэнне па змаўчанні.
   
   
   Абыход абмежаванняў рэгіёну
diff --git a/src/main/resources/addresources/values-bg-rBG/strings.xml b/src/main/resources/addresources/values-bg-rBG/strings.xml
index 50bacde86f..ec3dd07258 100644
--- a/src/main/resources/addresources/values-bg-rBG/strings.xml
+++ b/src/main/resources/addresources/values-bg-rBG/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Разделът за транскрипция е показан
   Описание на видеото
   Скриване или показване на компонентите за описание на видеоклиповете
+  
+  YouTube Doodles
+  Doodles в лентата за търсене са скрити
+  Doodles в лентата за търсене се показват
+  YouTube Doodles се появяват няколко дни в годината.\n\nАко Doodle в момента се показва във вашия регион и тази опция за скриване е активирана, филтърната лента под лентата за търсене също ще бъде скрита.
   Потребителски филтър
   Скриване на компоненти с помощта на потребителски филтри
   Активиране на потребителските филтри
@@ -627,9 +632,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Етикет за местоположение
   Етикет за местоположение е скрит
   Етикет за местоположение се показва
+  Скриване на бутона Запазване на музика
+  Бутонът за запазване на музика е скрит
+  Показан е бутонът за запазване на музика
+  Бутон за \"Използване на шаблон\"
+  Бутон за \"Използване на шаблон\" е скрит
+  Бутон за \"Използване на шаблон\" се показва
+  Бутон \"Предстоящи събития\"
+  Бутон \"Предстоящи събития\" е скрит
+  Бутон \"Предстоящи събития\" се показва
+  Бутон \"Зелен екран\"
+  Бутон \"Зелен екран\" е скрит
+  Бутон \"Зелен екран\" се показва
   Скриване на предложенията за търсене
   Предложенията за търсене са скрити
   Предложенията за търсене се показват
+  Скриване на стикери
+  Стикерите са скрити
+  Стикери са показани
+  Анимация на бутона \"Харесвам\"
+  Анимацията на бутона „Харесва ми“ е скрита
+  Анимацията на бутона „Харесва ми“ се показва
   Скриване на бутона за харесване
   Бутона за харесване е скрит
   Бутона за харесване се показва
@@ -940,21 +963,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Възстановява стария изглед
   
   
-  Задай начална страница
-  По подразбиране
-  
-  Начало
-  Търсене
-  
-  Абонаменти
-  Разгледайте
-  Shorts
-  
-  Раздел \"Вие\"
-  Харесани видеа
-  
-  История
-  Популярни
+  Задай начална страница
+  По подразбиране
+  Разгледайте
+  История
+  Харесани видеа
+  Търсене
+  Абонаменти
+  Популярни
   
   
   Скриване на Shorts плейъра при стартиране
@@ -977,9 +993,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Модерен 1
   Модерен 2
   Модерен 3
-  Бутони за разширяване и свиване на екрана
-  Скрит.\n(плъзнете минимизирания екран на плейъра, за да разширите или затворите видеоклипа)
-  Бутони за разширяване и свиване на екрана са видими
+  Бутони за разширяване и свиване на екрана
+  Бутони за разширяване и свиване на екрана са видими
   Екранни текстове, етикети
   Скрити
   Показват се
@@ -1001,7 +1016,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Показва се оригиналния цвят на лентата за напредък
   Персонализиран цвят на лентата за напредък
   Цветове на лентата за напредък
-  Невалидна стойност на цвета. Използвй стойност по подразбиране.
   
   
   Прескочете забраната за зареждане на изображение
diff --git a/src/main/resources/addresources/values-bn-rBD/strings.xml b/src/main/resources/addresources/values-bn-rBD/strings.xml
index a6fbeb5e8c..96a0208f15 100644
--- a/src/main/resources/addresources/values-bn-rBD/strings.xml
+++ b/src/main/resources/addresources/values-bn-rBD/strings.xml
@@ -33,6 +33,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
 
   
   
+  চেক ফেইল করেছে
+  অফিশ্যাল ওয়েবসাইট খুলুন
+  অবজ্ঞা করুন
+  অন্য ডিভাইসে প্যাচ করা হয়েছে
+  ReVanced Manager দ্বারা প্যাচ করা হয়নি
+  ১০ মিনিটেরও বেশি আগে প্যাচ করা হয়েছে
+  %s দিন আগে প্যাচ করা হয়েছে
+  APK তৈরির তারিখ ত্রুটিপূর্ণ
   
   
   আপনি কি এগিয়ে যেতে ইচ্ছুক?
@@ -51,6 +59,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   দ্রষ্টব্য
   এই সংস্করণ একটি প্রাক-প্রকাশনা এবং এতে আপনি অনাকাঙ্খিত সমস্যার সম্মুখিন হতে পারেন
   অফিশ্যাল লিংকসমূহ
+  দান করুন
   
   
   
@@ -203,6 +212,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   বৈশিষ্ট্য বিভাগ লুকান
   \'বৈশিষ্ট্যযুক্ত স্থান\', গেম এবং সঙ্গীত বিভাগগুলি লুকানো আছে
   \'বৈশিষ্ট্যযুক্ত স্থান\', গেম এবং সঙ্গীত বিভাগগুলি প্রদর্শিত হয়েছে
+  চ্যাপ্টার বিভাগ লুকান
+  চ্যাপ্টার বিভাগ লুকিয়ে রয়েছে
+  চ্যাপ্টার বিভাগ প্রদর্শিত হয়েছে
   তথ্য কার্ড সেকশন লুকান
   তথ্য কার্ড সেকশন লুকিয়ে রয়েছে
   তথ্য কার্ড সেকশন প্রদর্শিত হয়েছে
@@ -210,6 +222,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   ট্রান্সস্ক্রিপ্ট বিভাগ প্রদর্শিত হয়েছে
   ভিডিওর বিবরণ
   ভিডিও বিবরণ এর উপাদান লুকান বা প্রদর্শন করুন
+  
   কাস্টম ফিল্টার
   কাস্টম ফিল্টার ব্যবহার করে বিভিন্ন উপাদান লুকান
   কাস্টম ফিল্টার সক্রিয় করুন
@@ -375,6 +388,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
+  কাস্ট বাটন লুকান
+  কাস্ট বাটন লুকিয়ে রয়েছে
+  কাস্ট বাটন প্রদর্শিত হয়েছে
   
   
   নেভিগেশন বোতাম
@@ -390,20 +406,46 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   লুকান তৈরি করুন
   তৈরি বোতাম লুকানো আছে
+  ক্রিয়েট বাটন প্রদর্শিত হয়েছে
   
+  সদস্যতা লুকান
+  সদস্যতা নিন বোতাম লুকিয়ে রয়েছে
+  সদস্যতা নিন বোতাম প্রদর্শিত হয়েছে
   
+  তৈরি বোতামকে বিজ্ঞপ্তি বোতাম দ্বারা সুইচ করুন
   তৈরি করুন বোতাম বিজ্ঞপ্তিগুলো বোতাম দ্বারা স্থান পরিবর্তিত হয়েছে\n\nবিঃদ্রঃ এটি সক্রিয় করার ফলে ভিডিও বিজ্ঞাপন জোরপূর্বক বন্ধ থাকবে
+  তৈরি বোতামকে বিজ্ঞপ্তি বোতাম দ্বারা সুইচ করা হয়নি
   নেভিগেশন বোতাম লেবেল লুকান
   লেবেল লুকিয়ে রয়েছে
   লেবেল প্রদর্শিত হয়েছে
   
   
+  ফ্লাইআউট মেনু
+  ফ্লাইআউট মেনুর আইটেম দেখান বা লুকান
   
+  ক্যাপশন লুকান
+  ক্যাপশন মেনু লুকিয়ে রয়েছে
+  ক্যাপশন মেনু প্রদর্শিত হয়েছে
   
+  আরও সেটিংস দেখুন লুকান
+  আরও সেটিংস দেখুন মেনু লুকিয়ে রয়েছে
+  আরও সেটিংস দেখুন মেনু প্রদর্শিত হয়েছে
   
+  ভিডিও লুপ করুন লুকান
+  ভিডিও লুপ করুন মেনু লুকিয়ে রয়েছে
+  ভিডিও লুপ করুন মেনু প্রদর্শিত হয়েছে
   
+  অ্যাম্বিয়েন্ট মোড লুকান
+  অ্যাম্বিয়েন্ট মোড মেনু লুকিয়ে রয়েছে
+  অ্যাম্বিয়েন্ট মোড মেনু প্রদর্শিত হয়েছে
   
+  সাহায্য এবং ফিডব্যাক মেনু লুকান
+  সহায়তা ও প্রতিক্রিয়া মেনু লুকিয়ে রয়েছে
+  সহায়তা ও প্রতিক্রিয়া মেনু প্রদর্শিত হয়েছে
   
+  প্লেব্যাকের স্পিড লুকান
+  প্লেব্যাকের স্পিড মেনু লুকিয়ে রয়েছে
+  প্লেব্যাকের স্পিড মেনু প্রদর্শিত হয়েছে
   
   আরো তথ্য লুকান
@@ -428,6 +470,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   বোতাম দেখানো হয়
   
   
+  অ্যালবাম কার্ড লুকান
+  অ্যালবাম কার্ড লুকিয়ে রয়েছে
   অ্যালবাম কার্ড প্রদর্শিত হয়েছে
   
   
@@ -439,6 +483,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   মন্তব্য বিভাগ লুকান
   মন্তব্য বিভাগ লুকিয়ে রয়েছে
   মন্তব্য বিভাগ প্রদর্শিত হয়েছে
+  \'Short তৈরি করুন\' বোতাম লুকান
+  \'Short তৈরি করুন\' বোতাম লুকিয়ে রয়েছে
+  \'Short তৈরি করুন\' বোতাম প্রদর্শিত হয়েছে
   মন্তব্যের পূর্বরূপ লুকান
   মন্তব্যের পূর্বরূপ লুকিয়ে রয়েছে
   মন্তব্যের পূর্বরূপ প্রদর্শিত হয়েছে
@@ -535,9 +582,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
   অবস্থান লেবেল লুকান
   অবস্থান লেবেল লুকিয়ে রয়েছে
   অবস্থান লেবেল প্রদর্শিত হয়েছে
+  সঙ্গীত সেভ করুন বোতাম লুকান
   অনুসন্ধান পরামর্শগুলি লুকান
   অনুসন্ধান পরামর্শগুলি লুকিয়ে রয়েছে
   অনুসন্ধান পরামর্শগুলি প্রদর্শিত হয়েছে
+  স্টিকার লুকান
+  স্টিকার লুকিয়ে রয়েছে
+  স্টিকার প্রদর্শিত হয়েছে
+  পছন্দ বোতাম ঝর্ণা লুকান
+  পছন্দ বোতাম ঝর্ণা অ্যানিমেশন লুকিয়ে রয়েছে
+  পছন্দ বোতাম ঝর্ণা অ্যানিমেশন প্রদর্শিত হয়েছে
   পছন্দ বোতাম লুকান
   পছন্দ বোতাম লুকিয়ে রয়েছে
   পছন্দ বোতাম প্রদর্শিত হয়েছে
@@ -845,21 +899,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - পুরোনো UI লেআউট পুনরুদ্ধার করে
   
   
-  শুরুর পৃষ্ঠা সেট করুন
-  পূর্ব-নির্ধারিত
-  
-  হোম পেজ
-  অনুসন্ধান
-  
-  সদস্যতা
-  ঘুরে দেখুন
-  Shorts
-  
-  আপনি ট্যাব
-  পছন্দ করা ভিডিওগুলি
-  
-  ইতিহাস
-  এখন জনপ্রিয়
+  শুরুর পৃষ্ঠা সেট করুন
+  পূর্ব-নির্ধারিত
+  ঘুরে দেখুন
+  ইতিহাস
+  পছন্দ করা ভিডিওগুলি
+  অনুসন্ধান
+  সদস্যতা
+  এখন জনপ্রিয়
   
   
   Shorts প্লেয়ার আবার চালানো নিষ্ক্রিয় করুন
@@ -882,9 +929,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   মর্ডান ১
   মর্ডান ২
   মর্ডান ৩
-  বিস্তৃত ও বন্ধ করার বোতাম লুকান
-  বোতামগুলো লুকিয়ে রয়েছে\n(সোয়াইপ করে মিনিপ্লেয়ার বিস্তৃত বা বন্ধ করা)
-  বিস্তৃত এবং বন্ধ করার বোতাম প্রদর্শিত হয়েছে
+  বিস্তৃত ও বন্ধ করার বোতাম লুকান
   উপপাঠ লুকান
   উপপাঠ লুকিয়ে রয়েছে
   উপপাঠ প্রদর্শিত হয়েছে
@@ -906,7 +951,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   সিকবারে মূল রং প্রদর্শিত হয়েছে
   নিজস্ব সিকবার রং
   সিকবারের রং
-  সিকবারে ভুল রং দেয়া হয়েছে। মূল রং ব্যবহার করছে।
   
   
   
@@ -1029,7 +1073,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
   ভিডিওর নির্দিষ্ট অংশে যেতে টানুন সক্রিয় করা হয়নি
   
   
+  ভিডিও স্ট্রিমিং স্পুফ করুন
+  প্লেব্যাক সমস্যা প্রতিরোধ করতে ক্লায়েন্ট ভিডিও স্ট্রিম স্পুফ করুন
+  ভিডিও স্ট্রিমিং স্পুফ করুন
+  ভিডিও স্ট্রিম স্পুফ করা হয়েছে
+  ভিডিও স্ট্রিম স্পুফ করা হয়নি\n\nভিডিও প্লেব্যাক ঠিকমতো কাজ নাও করতে পারে
   এই সেটিংটি বন্ধ করার ফলে ভিডিও প্লেব্যাক ত্রুটি হতে পারে।
+  ডিফল্ট ক্লায়েন্ট
+  AVC (H.264) ফোর্স করুন
+  ভিডিও কোডেক AVC (H.264) ব্যবহৃত হচ্ছে
+  ভিডিও কোডেক VP9 বা AV1 ব্যবহৃত হচ্ছে
   
   
   
diff --git a/src/main/resources/addresources/values-bs-rBA/strings.xml b/src/main/resources/addresources/values-bs-rBA/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-bs-rBA/strings.xml
+++ b/src/main/resources/addresources/values-bs-rBA/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-ca-rES/strings.xml b/src/main/resources/addresources/values-ca-rES/strings.xml
index 6b952133b9..5cac830d10 100644
--- a/src/main/resources/addresources/values-ca-rES/strings.xml
+++ b/src/main/resources/addresources/values-ca-rES/strings.xml
@@ -57,6 +57,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -187,11 +188,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  Per defecte
-  
-  
-  
-  
+  Per defecte
   
   
   
diff --git a/src/main/resources/addresources/values-cs-rCZ/strings.xml b/src/main/resources/addresources/values-cs-rCZ/strings.xml
index bad36679ac..d965ed90fd 100644
--- a/src/main/resources/addresources/values-cs-rCZ/strings.xml
+++ b/src/main/resources/addresources/values-cs-rCZ/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Je zobrazena sekce přepisu
   Popis videa
   Skrýt nebo zobrazit komponenty popisu videa
+  
+  Skrýt YouTube Dveody
+  Vyhledávací lišty jsou skryté Doodles
+  Vyhledávací lišty jsou zobrazeny
+  YouTube Doodles se zobrazí každý rok několik dní.\n\nPokud se ve vašem regionu zobrazuje Doodle a toto nastavení je zapnuto, pak bude také skryta lišta filtrů pod vyhledávacím řádkem.
   Vlastní filtr
   Skrýt komponenty pomocí vlastních filtrů
   Povolit vlastní filtr
@@ -629,14 +634,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Štítek polohy je skrytý
   Popisek umístění je zobrazen
   Skrýt tlačítko uložit hudbu
-  Uložení hudby je skryté
-  Ukládání hudby je zobrazeno
+  Uložit hudební tlačítko je skryté
+  Zobrazí se tlačítko pro uložení hudby
+  Skrýt tlačítko šablony
+  Tlačítko šablony je skryté
+  Tlačítko použití šablony je zobrazeno
+  Skrýt nadcházející tlačítko
+  Nadcházející tlačítko je skryté
+  Zobrazí se nadcházející tlačítko
+  Skrýt zelené tlačítko
+  Zelené tlačítko obrazovky je skryté
+  Zobrazí se zelené tlačítko
+  Skrýt tlačítko hashtag
+  Tlačítko Hashtag je skryté
+  Zobrazí se tlačítko Hashtag
   Skrýt návrhy hledání
   Návrhy hledání jsou skryty
   Návrhy hledání jsou zobrazeny
   Skrýt nálepky
   Samolepky jsou skryté
   Samolepky jsou zobrazeny
+  Skrýt jako fontánku
+  Animace fontánského tlačítka „To se mi líbí“ je skrytá
+  Zobrazí se animace fontánu, které se líbí tlačítku
   Skrýt tlačítko „To se mi líbí“
   Tlačítko se mi líbí je skryté
   Tlačítko se mi líbí
@@ -947,21 +967,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Obnovit staré rozložení UI
   
   
-  Nastavit úvodní stránku
-  Výchozí
-  
-  Domů
-  Hledat
-  
-  Předplatné
-  Prozkoumat
-  Shorts
-  
-  Karta
-  Líbí se vám videa
-  
-  Historie
-  Populární
+  Nastavit úvodní stránku
+  Výchozí
+  Procházet kanály
+  Prozkoumat
+  Hra
+  Historie
+  Knihovna
+  Líbí se vám videa
+  Živé
+  Filmy
+  Hudba
+  Hledat
+  Sporty
+  Předplatné
+  Populární
+  Sledujte později
   
   
   Zakázat obnovení krátkého přehrávače
@@ -984,15 +1005,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderní 1
   Moderní 2
   Moderní 3
-  Skrýt tlačítka rozbalit a zavřít
-  Tlačítka jsou skrytá\n(potáhněte minipřehrávač pro rozšíření nebo zavření)
-  Tlačítka rozbalit a zavřít jsou zobrazena
+  Povolit zaoblené rohy
+  Rohy jsou zaoblené
+  Rohy jsou čtvereční
+  Povolit dvojité klepnutí a připnutí pro změnu velikosti
+  Dvojitým poklepáním a přetažením změníte velikost je povoleno\n\n• Dvojitým poklepáním zvýšit velikost minipřehrávače\n• Opětovným poklepáním obnovíte původní velikost
+  Akce dvojitým poklepáním a připnutí pro změnu velikosti je zakázáno
+  Povolit přetažení
+  Přetažení je povoleno\n\nMiniplayer může být přetažen do libovolného rohu obrazovky
+  Přetažení je zakázáno
+  Skrýt tlačítko zavření
+  Tlačítko zavřít je skryté
+  Tlačítko zavření je zobrazeno
+  Skrýt tlačítka rozbalit a zavřít
+  Tlačítka jsou skryta\n\nPřejeďte pro rozbalení nebo zavření
+  Tlačítka rozbalit a zavřít jsou zobrazena
   Skrýt podtexty
   Podtexty jsou skryty
   Podtexty jsou zobrazeny
   Skrýt přeskočit tlačítka vpřed a zpět
   Přeskočit vpřed a zpět jsou skryty
   Přeskočit vpřed a zpět jsou zobrazeny
+  Počáteční velikost
+  Počátek na velikosti obrazovky, v pixelech
+  Velikost pixelu musí být mezi %1$s a %2$s
   Neprůhlednost překrytí
   Neprůhlednost mezi 0-100, kde 0 je průhledná
   Neprůhlednost překrytí minipřehrávače musí být mezi 0-100
@@ -1008,7 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Zobrazí se původní barva vyhledávacího panelu
   Vlastní barva vyhledávacího panelu
   Barva vyhledávacího panelu
-  Neplatná hodnota barvy vyhledávacího panelu. Použít výchozí hodnotu.
+  Neplatná hodnota barvy vyhledávacího panelu
   
   
   Obejít omezení oblasti obrázku
diff --git a/src/main/resources/addresources/values-da-rDK/strings.xml b/src/main/resources/addresources/values-da-rDK/strings.xml
index 6e3edec6b9..2fd0fbf069 100644
--- a/src/main/resources/addresources/values-da-rDK/strings.xml
+++ b/src/main/resources/addresources/values-da-rDK/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Afsnittet er vist
   Video beskrivelse
   Skjul eller vis komponenter til videobeskrivelse
+  
+  Skjul YouTube-Doudler
+  Søgebjælke Doudler er skjult
+  Søgebjælke Doudler vises
+  YouTube Doodles dukker op et par dage hvert år.\n\nHvis en Doodle i øjeblikket vises i din region og denne skjul-indstilling er slået til, så vil filterbjælken under søgelinjen også være skjult.
   Tilpasset filter
   Skjul komponenter ved hjælp af brugerdefinerede filtre
   Aktiver brugerdefineret filter
@@ -628,14 +633,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Placeringsetiket er skjult
   Placeringsetiket er vist
   Skjul gem musik knap
-  Gem musik er skjult
-  Gem musik er vist
+  Gem musik knap er skjult
+  Gem musik knap er vist
+  Skjul brug skabelon knap
+  Brug skabelon knappen er skjult
+  Brug skabelon knappen er vist
+  Skjul kommende knap
+  Kommende knap er skjult
+  Kommende knap vises
+  Skjul grøn skærm knap
+  Grøn skærmknap er skjult
+  Grøn skærmknap vises
+  Skjul hashtag knap
+  Hashtag knap er skjult
+  Hashtag knappen er vist
   Skjul søgeforslag
   Søgeforslag er skjult
   Søgeforslag er vist
   Skjul klistermærker
   Klistermærker er skjult
   Klistermærker vises
+  Skjul som springvand
+  Ligesom knap springvand animation er skjult
+  Animation af springvand vises som knap
   Skjul lignende knap
   Ligesom knappen er skjult
   Lideknap vises
@@ -946,20 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Gendan gammelt UI-layout
   
   
-  Indstil startside
-  Standard
-  
-  Hjem
-  Søg
-  
-  Abonnementer
-  Udforsk
-  
-  Dig fane
-  Syntes om videoer
-  
-  Historik
-  Populære
+  Indstil startside
+  Standard
+  Gennemse kanaler
+  Udforsk
+  Spil
+  Historik
+  Bibliotek
+  Syntes om videoer
+  Levende
+  Film
+  Musik
+  Søg
+  Sport
+  Abonnementer
+  Populære
+  Se senere
   
   
   Deaktivér genoptagelse af Shorts spiller
@@ -982,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderne 1
   Moderne 2
   Moderne 3
-  Skjul udvid og luk knapper
-  Knapper er skjult\n(stryg miniplayer for at udvide eller lukke)
-  Udvid og luk knapper vises
+  Aktiver afrundede hjørner
+  Hjørner er afrundede
+  Hjørner er firkantede
+  Aktiver dobbelttryk og klemme for at ændre størrelse
+  Dobbelttryk handling og klemme for at ændre størrelse er aktiveret\n\n• Dobbelttryk for at øge miniplayer størrelse\n• Dobbelttryk igen for at gendanne original størrelse
+  Dobbelttryk handling og klemme for at ændre størrelse er deaktiveret
+  Aktiver træk og slip
+  Træk og slip er aktiveret\n\nMiniplayer kan trækkes til ethvert hjørne af skærmen
+  Træk og slip er deaktiveret
+  Skjul lukkeknap
+  Luk knappen er skjult
+  Luk knappen vises
+  Skjul udvid og luk knapper
+  Knapper er skjult\n\nStryg for at udvide eller lukke
+  Udvid og luk knapper vises
   Skjul undertekster
   Undertekster er skjult
   Undertekster er vist
   Skjul overspring fremad og tilbage knapper
   Spring frem og tilbage er skjult
   Spring frem og tilbage vises
+  Oprindelig størrelse
+  Indledende på skærmstørrelse, i pixels
+  Pixel størrelse skal være mellem %1$s og %2$s
   Overlay uigennemsigtighed
   Gennemsigtighedsværdi mellem 0-100, hvor 0 er gennemsigtig
   Miniplayer overlay gennemsigtighed skal være mellem 0-100
@@ -1006,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Original søgelinje farve vises
   Brugerdefineret søgelinje farve
   Farven på den søgende bar
-  Ugyldig søgelinje farveværdi. Brug standardværdi.
+  Ugyldig søgelinje farveværdi
   
   
   Bypass billede region restriktioner
diff --git a/src/main/resources/addresources/values-de-rDE/strings.xml b/src/main/resources/addresources/values-de-rDE/strings.xml
index cdef51c0c0..0981d82784 100644
--- a/src/main/resources/addresources/values-de-rDE/strings.xml
+++ b/src/main/resources/addresources/values-de-rDE/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Sektion Transkripte wird angezeigt
   Videobeschreibung
   Komponenten der Videobeschreibung ausblenden oder anzeigen
+  
+  YouTube Doodles ausblenden
+  Suchleiste Doodles sind versteckt
+  Suchleiste Doodles werden angezeigt
+  YouTube Doodles erscheinen jedes Jahr ein paar Tage.\n\nWenn ein Doodle in deiner Region angezeigt wird und diese Versteckeinstellung aktiviert ist dann wird auch die Filterleiste unterhalb der Suchleiste ausgeblendet.
   Eigener Filter
   Komponenten mit benutzerdefinierten Filtern ausblenden
   Eigenen Filter aktivieren
@@ -628,14 +633,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Ortsbezeichnung ist ausgeblendet
   Ortsbezeichnung wird angezeigt
   Musikspeichern-Button ausblenden
-  Musik speichern ist ausgeblendet
-  Musik speichern wird angezeigt
+  Musikspeicher Button ist ausgeblendet
+  Musikspeicher Button wird angezeigt
+  Template-Schaltfläche ausblenden
+  Template-Schaltfläche verwenden ist ausgeblendet
+  Template-Schaltfläche verwenden wird angezeigt
+  Anstehende Schaltfläche ausblenden
+  Kommender Button ist ausgeblendet
+  Kommende Schaltfläche wird angezeigt
+  grüne Bildschirmschaltfläche ausblenden
+  Grünbildschirm-Taste ist ausgeblendet
+  Grünbildschirm-Taste wird angezeigt
+  Hashtag Button ausblenden
+  Hashtag Button ist ausgeblendet
+  Hashtag Button wird angezeigt
   Suchvorschläge ausblenden
   Suchvorschläge sind ausgeblendet
   Suchvorschläge werden angezeigt
   Sticker ausblenden
   Sticker sind versteckt
   Sticker werden angezeigt
+  Verstecke wie Fontäne
+  Wie Knopf Fontänen-Animation ist ausgeblendet
+  Wie Button Fontänen-Animation wird angezeigt
   Verstecke \"Gefällt mir\" Button
   \"Gefällt mir\" Button ist ausgeblendet
   \"Gefällt mir\" Button wird angezeigt
@@ -946,21 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Altes UI-Layout wiederherstellen
   
   
-  Startseite festlegen
-  Standard
-  
-  Zuhause
-  Suchen
-  
-  Abonnements
-  Erforschen
-  Shorts
-  
-  Tab
-  Videos, die ich mag
-  
-  Verlauf
-  Beliebt
+  Startseite festlegen
+  Standard
+  Kanäle durchsuchen
+  Erforschen
+  Spielen
+  Verlauf
+  Bibliothek
+  Videos, die ich mag
+  Live
+  Filme
+  Musik
+  Suchen
+  Sport
+  Abonnements
+  Beliebt
+  Später ansehen
   
   
   Fortsetzen des Shorts Players deaktivieren
@@ -983,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
-  Ausklappen und Schließen der Tasten ausblenden
-  Tasten sind ausgeblendet\n(wische den Miniplayer zum Erweitern oder Schließen)
-  Erweitern und Schließen Tasten werden angezeigt
+  Abgerundete Ecken aktivieren
+  Ecken sind abgerundet
+  Ecken sind Quadrat
+  Aktiviere doppeltes Tippen und Pratzen um die Größe zu ändern
+  Doppeltipp-Aktion und Pinsel, um die Größe zu verändern, ist aktiviert\n\n• Doppeltippen, um die Größe des Miniplayers\nzu erhöhenformat@@2 • Doppeltippen erneut, um die Originalgröße wiederherzustellen
+  Doppel-Tipp-Aktion und Pinch um die Größe zu verändern, ist deaktiviert
+  Drag and Drop aktivieren
+  Drag and Drop ist aktiviert\n\nMiniplayer kann in jede Ecke des Bildschirms gezogen werden
+  Drag and Drop ist deaktiviert
+  Schließen-Button ausblenden
+  Schließen-Button ist ausgeblendet
+  Schließen-Schaltfläche wird angezeigt
+  Ausklappen und Schließen der Tasten ausblenden
+  Tasten sind ausgeblendet\n\nWischen um zu erweitern oder zu schließen
+  Erweitern und Schließen Tasten werden angezeigt
   Untertexte ausblenden
   Subtexte sind ausgeblendet
   Untertexte werden angezeigt
   Vorwärts- und Rückwärts-Buttons ausblenden
   Vorwärts skippen und zurück sind ausgeblendet
   Vorwärts und zurück springen werden angezeigt
+  Anfangsgröße
+  Initiale Bildschirmgröße, in Pixeln
+  Pixelgröße muss zwischen %1$s und %2$s liegen
   Deckkraft der Überlagerung
   Deckkraft Wert zwischen 0-100, wobei 0 transparent ist
   Miniplayer-Overlay-Deckkraft muss zwischen 0-100 liegen
@@ -1007,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Originalfarbe der Suchleiste wird angezeigt
   Farbe der Suchleiste
   Die Farbe der Suchleiste
-  Ungültiger Suchleisten-Farbwert. Standardwert wird verwendet.
+  Ungültiger Suchleisten-Farbwert
   
   
   Bildgebietsbeschränkungen umgehen
diff --git a/src/main/resources/addresources/values-el-rGR/strings.xml b/src/main/resources/addresources/values-el-rGR/strings.xml
index 4857852b83..faa10a1c66 100644
--- a/src/main/resources/addresources/values-el-rGR/strings.xml
+++ b/src/main/resources/addresources/values-el-rGR/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Εμφανίζεται
   Περιγραφή βίντεο
   Απόκρυψη ή εμφάνιση στοιχείων περιγραφής βίντεο
+  
+  YouTube Doodles
+  Κρυμμένα
+  Εμφανίζονται
+  Τα YouTube Doodles εμφανίζονται για μερικές μέρες κάθε χρόνο.\n\nΑν ένα Doodle εμφανίζεται αυτόν τον καιρό στην περιοχή σας και η ρύθμιση απόκρυψης τους είναι ενεργοποιημένη, τότε η γραμμή φίλτρου κάτω από τη γραμμή αναζήτησης θα είναι επίσης κρυμμένη.
   Προσαρμοσμένο φίλτρο
   Απόκρυψη στοιχείων χρησιμοποιώντας προσαρμοσμένα φίλτρα
   Χρήση προσαρμοσμένου φίλτρου
@@ -630,12 +635,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Κουμπί «Αποθήκευση μουσικής»
   Κρυμμένο
   Εμφανίζεται
+  Κουμπί «Χρήση προτύπου»
+  Κρυμμένο
+  Εμφανίζεται
+  Κουμπί επερχόμενης πρεμιέρας/ζωντανής ροής
+  Κρυμμένο
+  Εμφανίζεται
+  Κουμπί «Πράσινη οθόνη»
+  Κρυμμένο
+  Εμφανίζεται
+  Απόκρυψη κουμπιού hashtag
+  Το κουμπί Hashtag είναι κρυμμένο
+  Εμφανίζεται το κουμπί Hashtag
   Προτάσεις αναζήτησης
   Κρυμμένες
   Εμφανίζονται
   Αυτοκόλλητα
   Κρυμμένα
   Εμφανίζονται
+  Εφέ κίνησης κουμπιού «Μου αρέσει»
+  Κρυμμένο
+  Εμφανίζεται
   Κουμπί «Μου αρέσει»
   Κρυμμένο
   Εμφανίζεται
@@ -946,21 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Επαναφορά της παλιάς εμφάνισης UI
   
   
-  Αλλαγή της αρχικής σελίδας
-  Προεπιλογή
-  
-  Αρχική
-  Αναζήτηση
-  
-  Εγγραφές
-  Εξερεύνηση
-  Shorts
-  
-  Καρτέλα «Εσείς»
-  Βίντεο που σας αρέσουν
-  
-  Ιστορικό
-  Τάσεις
+  Αλλαγή της αρχικής σελίδας
+  Προεπιλογές
+  Αναζήτηση καναλιών
+  Εξερεύνηση
+  Παιχνίδι
+  Ιστορικό
+  Βιβλιοθήκη
+  Βίντεο που σας αρέσουν
+  Ζωντανά
+  Ταινίες
+  Μουσική
+  Αναζήτηση
+  Αθλητισμός
+  Εγγραφές
+  Τάσεις
+  Δείτε αργότερα
   
   
   Απενεργοποίηση συνέχισης των Shorts
@@ -983,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Μοντέρνος 1
   Μοντέρνος 2
   Μοντέρνος 3
-  Κουμπιά επέκτασης και κλεισίματος
-  Κρυμμένα\n(σύρετε την ελαχιστοποιημένη οθόνη αναπαραγωγής για επέκταση ή κλείσιμο του βίντεο)
-  Εμφανίζονται
+  Ενεργοποίηση στρογγυλεμένων γωνιών
+  Οι γωνίες είναι στρογγυλεμένες
+  Οι γωνίες είναι τετράγωνες
+  Ενεργοποίηση διπλού πατήματος και πρέζας για αλλαγή μεγέθους
+  Ενέργεια διπλού πατήματος και πρέζα για αλλαγή μεγέθους είναι ενεργοποιημένη η λειτουργία\n\n• Διπλό πάτημα για αύξηση μεγέθους miniplayer\n• Διπλό πάτημα ξανά για επαναφορά του αρχικού μεγέθους
+  Ενέργεια διπλού πατήματος και πρέζα για αλλαγή μεγέθους είναι απενεργοποιημένη
+  Ενεργοποίηση μεταφοράς και απόθεσης
+  Drag and drop is enabled\n\nMiniplayer can be dragged to any corner of the screen
+  Το σύρσιμο και η απόθεση είναι απενεργοποιημένη
+  Απόκρυψη κουμπιού κλεισίματος
+  Το κουμπί κλεισίματος είναι κρυμμένο
+  Το κουμπί κλεισίματος εμφανίζεται
+  Κουμπιά επέκτασης και κλεισίματος
+  Τα κουμπιά είναι κρυμμένα\n\nΣύρετε για επέκταση ή κλείσιμο
+  Εμφανίζονται τα κουμπιά επέκτασης και κλεισίματος
   Κείμενα στην οθόνη αναπαραγωγής
   Κρυμμένα
   Εμφανίζονται
   Κουμπιά παράλειψης και επιστροφής
   Κρυμμένα
   Εμφανίζονται
+  Αρχικό μέγεθος
+  Αρχικό μέγεθος οθόνης, σε εικονοστοιχεία
+  Το μέγεθος του Pixel πρέπει να είναι μεταξύ %1$s και %2$s
   Αδιαφάνεια επικάλυψης
   Τιμή αδιαφάνειας μεταξύ 0-100, όπου το 0 είναι διαφανές
   Η αδιαφάνεια φόντου οθόνης αναπαραγωγής πρέπει να είναι μεταξύ 0-100
@@ -1007,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Η γραμμή προόδου εμφανίζεται με το αρχικό χρώμα
   Χρώμα γραμμής προόδου
   Το χρώμα της γραμμής προόδου
-  Μη έγκυρη τιμή χρώματος. Επαναφορά...
+  Μη έγκυρη τιμή χρώματος γραμμής προόδου
   
   
   Παράκαμψη μπλοκαρίσματος φόρτωσης εικόνων
diff --git a/src/main/resources/addresources/values-es-rES/strings.xml b/src/main/resources/addresources/values-es-rES/strings.xml
index da2f62d082..a25a3ae740 100644
--- a/src/main/resources/addresources/values-es-rES/strings.xml
+++ b/src/main/resources/addresources/values-es-rES/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Se muestra la sección transcripción
   Descripción del vídeo
   Ocultar o mostrar componentes de descripción de vídeo
+  
+  Ocultar YouTube Doodles
+  Barra de búsqueda Doodles están ocultos
+  Mostrar la barra de búsqueda Doodles
+  Los Doodles de YouTube aparecen unos pocos días cada año.\n\nSi un Doodle se muestra actualmente en tu región y esta opción de ocultación está activada, entonces la barra de filtro bajo la barra de búsqueda también se ocultará.
   Filtro personalizado
   Ocultar componentes usando filtros personalizados
   Activar filtro personalizado
@@ -258,7 +263,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Los resultados de inicio/suscripción/búsqueda se filtran para ocultar el contenido que coincide con las frases de palabras clave\n\nLimitaciones\n• Los cortos no se pueden ocultar con el nombre del canal\n• Algunos componentes de la interfaz pueden no estar ocultos\n• Buscar una palabra clave no puede mostrar resultados
   Coincidir palabras completas
   
-  Rodear una palabra clave/frase con comillas dobles evitará las coincidencias parciales de títulos de vídeo y nombres de canales<br><br>Por ejemplo,<br><b>\"ia\"</b> ocultará el vídeo: <b>¿Cómo funciona la AI?</b><br>pero no ocultará: <b>¿Quieres aprender a bailar?</b>
+  Rodear una palabra clave/frase con comillas dobles evitará las coincidencias parciales de títulos de vídeo y nombres de canales<br><br>Por ejemplo,<br><b>\"ai\"</b> ocultará el vídeo: <b>¿Cómo funciona la AI?</b><br>pero no ocultará: <b>¿Quieres aprender a bailar?</b>
   
   No se puede usar la palabra clave: %s
   Añadir comillas para usar palabra clave: %s
@@ -628,14 +633,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Etiqueta de ubicación oculta
   Etiqueta de ubicación mostrada
   Ocultar botón de guardar música
-  Guardar música está oculta
-  Guardar música se muestra
+  Guardar botón de música está oculto
+  Mostrar el botón de guardar música
+  Ocultar botón de usar plantilla
+  Botón de plantilla de uso está oculto
+  Se muestra el botón de usar plantilla
+  Ocultar botón próximo
+  El botón próximo está oculto
+  Se muestra el botón próximo
+  Ocultar botón verde de pantalla
+  El botón verde de pantalla está oculto
+  Se muestra el botón verde de pantalla
+  Ocultar botón de hashtag
+  El botón Hashtag está oculto
+  Se muestra el botón Hashtag
   Ocultar sugerencias de búsqueda
   Las sugerencias de búsqueda están ocultas
   Se muestran sugerencias de búsqueda
   Ocultar stickers
   Los pegatinas están ocultos
   Se muestran pegatinas
+  Ocultar como fuente
+  La animación de fuente de botón \"Me gusta\" está oculta
+  Se muestra la animación de fuente de botón \"Me gusta\"
   Ocultar botón me gusta
   El botón Me gusta está oculto
   Se muestra el botón Me Gusta
@@ -946,20 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Restaurar la disposición antigua de la interfaz de usuario
   
   
-  Establecer página de inicio
-  Predeterminado
-  
-  Inicio
-  Buscar
-  
-  Suscripciones
-  Explorar
-  
-  Pestaña
-  Vídeos gustados
-  
-  Historial
-  Tendencias
+  Establecer página de inicio
+  Predeterminado
+  Navegar canales
+  Explorar
+  Juego
+  Historial
+  Biblioteca
+  Vídeos gustados
+  Vivo
+  Películas
+  Música
+  Buscar
+  Deportes
+  Suscripciones
+  Tendencias
+  Ver más tarde
   
   
   Desactivar reanudación del reproductor
@@ -982,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderna 1
   Moderna 2
   Moderna 3
-  Ocultar botones de expansión y cierre
-  Los botones están ocultos\n(desliza el minijugador para expandir o cerrar)
-  Mostrar los botones de ampliación y cierre
+  Habilitar esquinas redondeadas
+  Las esquinas están redondeadas
+  Las esquinas son cuadradas
+  Habilitar doble toque y pellizco para redimensionar
+  Acción de doble toque y pulsar para cambiar el tamaño está habilitado\n\n• Doble toque para aumentar el tamaño de minijugador\n• Doble toque de nuevo para restaurar el tamaño original
+  Acción de doble toque y pellizco para redimensionar está desactivado
+  Activar arrastrar y soltar
+  Arrastrar y soltar está habilitado\n\nMinijugador puede ser arrastrado a cualquier esquina de la pantalla
+  Arrastre y suelte está desactivado
+  Ocultar botón de cerrar
+  El botón de cierre está oculto
+  Se muestra el botón de cerrar
+  Ocultar botones de expansión y cierre
+  Los botones están ocultos\n\nDesliza para expandir o cerrar
+  Mostrar los botones de ampliación y cierre
   Ocultar subtextos
   Los subtextos están ocultos
   Los subtextos se muestran
   Ocultar botones de omitir hacia adelante y atrás
   Saltar adelante y atrás están ocultos
   Saltar adelante y atrás se muestran
+  Tamaño inicial
+  Inicial en tamaño de pantalla, en píxeles
+  El tamaño del píxel debe estar entre %1$s y %2$s
   Opacidad de la capa superpuesta
   Valor de potencia entre 0-100, donde 0 es transparente
    Opacidad de reproductor debe estar en 0 -100
@@ -1006,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Se muestra el color original de la barra de búsqueda
   Color personalizado de la barra de búsqueda
   El color de la barra de ajustes
-  Valor de color de la barra de búsqueda inválido. Usando el valor por defecto.
+  Valor de color de la barra de búsqueda inválido
   
   
   Evitar restricción regional de imágenes
diff --git a/src/main/resources/addresources/values-et-rEE/strings.xml b/src/main/resources/addresources/values-et-rEE/strings.xml
index 719d9fa295..27f20ce37b 100644
--- a/src/main/resources/addresources/values-et-rEE/strings.xml
+++ b/src/main/resources/addresources/values-et-rEE/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  Vaikimisi
   
   
   
diff --git a/src/main/resources/addresources/values-eu-rES/strings.xml b/src/main/resources/addresources/values-eu-rES/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-eu-rES/strings.xml
+++ b/src/main/resources/addresources/values-eu-rES/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-fa-rIR/strings.xml b/src/main/resources/addresources/values-fa-rIR/strings.xml
index 0ada3d9d42..d8ff921581 100644
--- a/src/main/resources/addresources/values-fa-rIR/strings.xml
+++ b/src/main/resources/addresources/values-fa-rIR/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  پیشفرض
   
   
   
diff --git a/src/main/resources/addresources/values-fi-rFI/strings.xml b/src/main/resources/addresources/values-fi-rFI/strings.xml
index 2e7fd4c41b..f645af99ae 100644
--- a/src/main/resources/addresources/values-fi-rFI/strings.xml
+++ b/src/main/resources/addresources/values-fi-rFI/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Transkriptio-osio näytetään
   Videon kuvaus
   Piilota tai näytä videon kuvauskomponentteja
+  
+  Piilota YouTube-ovet
+  Hakupalkki Doodles on piilotettu
+  Hakupalkki Doodles näytetään
+  YouTube Doodles esiintyy muutaman päivän joka vuosi.\n\nJos Doodle näyttää tällä hetkellä alueellasi ja tämä piilon asetus on päällä, sitten myös hakupalkin alla oleva suodatinpalkki piilotetaan.
   Mukautettu suodatin
   Piilota komponentteja mukautetuilla suodattimilla
   Käytä mukautettua suodatinta
@@ -629,14 +634,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Sijaintitieto on piilotettu
   Sijaintitieto näytetään
   Piilota musiikin tallennus painike
-  Tallenna musiikki on piilotettu
-  Tallenna musiikki näytetään
+  Tallenna musiikki-painike on piilotettu
+  Tallenna musiikkipainike näytetään
+  Piilota käytä mallinappia
+  Käytä malli-painiketta on piilotettu
+  Käytä malli-painiketta näytetään
+  Piilota tuleva painike
+  Tuleva painike on piilotettu
+  Tuleva painike näytetään
+  Piilota vihreän näytön painike
+  Vihreä näyttöpainike on piilotettu
+  Vihreä näyttöpainike näytetään
+  Piilota aihetunnistepainike
+  Hashtag painike on piilotettu
+  Hashtag painike näytetään
   Piilota hakuehdotukset
   Hakuehdotukset on piilotettu
   Hakuehdotukset näytetään
   Piilota tarrat
   Tarrat on piilotettu
   Tarrat näytetään
+  Piilota kuin suihkulähde
+  Kuten painikkeen lähteen animaatio on piilotettu
+  Kuten painikkeen lähteen animaatio näytetään
   Piilota tykkää-painike
   Tykkä-painike on piilotettu
   Tykkää-painike näytetään
@@ -947,21 +967,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Palauta vanha käyttöliittymäasettelu
   
   
-  Aseta aloitussivu
-  Oletus
-  
-  Koti
-  Haku
-  
-  Tilaukset
-  Tutustu
-  Shortsit
-  
-  Sinä-välilehti
-  Tykätyt videot
-  
-  Historia
-  Nousussa
+  Aseta aloitussivu
+  Oletus
+  Selaa kanavia
+  Tutustu
+  Pelaaminen
+  Historia
+  Kirjasto
+  Tykätyt videot
+  Suora
+  Elokuvat
+  Musiikki
+  Haku
+  Urheilu
+  Tilaukset
+  Nousussa
+  Katso myöhemmin
   
   
   Poista Shorts-soittimen jatkaminen käytöstä
@@ -984,15 +1005,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderni 1
   Moderni 2
   Moderni 3
-  Piilota laajenna- ja sulje-painikkeet
-  Painikkeet on piilotettu\n(laajenna tai sulje minisoitin pyyhkäisemällä)
-  Laajenna- ja sulje-painikkeet näytetään
+  Ota pyöristetyt kulmat käyttöön
+  Kulmat on pyöristetty
+  Kulmat ovat neliöitä
+  Ota kaksoisnapautus käyttöön ja purista kokoa
+  Kaksoisnapautuksen toiminto ja nollaus koon muuttamiseksi on käytössä\n\n• Lisää minipelaajan kokoa\n• Kaksoisnapautus uudelleen palauttaaksesi alkuperäisen koon
+  Kaksoisnapautuksen toiminto ja ponnahdusikkunan koon muuttaminen on poistettu käytöstä
+  Ota käyttöön vedä ja pudota
+  Vedä ja pudota on käytössä\n\nMiniplayer voidaan vetää mihin tahansa ruudun kulmaan
+  Vedä ja pudotus pois käytöstä
+  Piilota sulje painike
+  Sulje painike on piilotettu
+  Sulje painike näytetään
+  Piilota laajenna- ja sulje-painikkeet
+  Painikkeet ovat piilossa\n\nPyyhkäise laajentaaksesi tai sulkeaksesi
+  Laajenna- ja sulje-painikkeet näytetään
   Piilota alatekstit
   Alatekstit on piilotettu
   Alatekstit näytetään
   Piilota ohita etu- ja takapainikkeet
   Ohita eteenpäin ja takaisin on piilotettu
   Ohita eteenpäin ja takaisin näytetään
+  Alkukoko
+  Alkuperäinen näytön koossa, pikseleinä
+  Pikselin koon on oltava välillä %1$s ja %2$s
   Peittokuvan läpinäkyvyys
   Läpinäkyvyysarvo välillä 0–100, jossa 0 on läpinäkyvä
   Miniplayer peittokuvan läpinäkyvyyden on oltava välillä 0-100
@@ -1008,7 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Alkuperäinen liukusäätimen väri näytetään
   Mukautettu liukusäätimen väri
   Liukusäätimen väri
-  Virheellinen liukusäätimen väri. Käytetään oletusta.
+  Virheellinen seekbarin värin arvo
   
   
   Ohita kuvan alueen rajoitukset
diff --git a/src/main/resources/addresources/values-fil-rPH/strings.xml b/src/main/resources/addresources/values-fil-rPH/strings.xml
index 8c031f2d84..74f2ec399a 100644
--- a/src/main/resources/addresources/values-fil-rPH/strings.xml
+++ b/src/main/resources/addresources/values-fil-rPH/strings.xml
@@ -214,6 +214,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Ipinapakita ang seksyon ng transcript
   Paglalarawan ng video
   Itago o ipakita ang mga bahagi ng paglalarawan ng video
+  
   Custom na filter
   Itago ang mga bahagi gamit ang mga custom na filter
   Paganahin ang custom na filter
@@ -903,18 +904,13 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Ibalik ang lumang layout ng UI
   
   
-  Itakda ang panimulang pahina
-  
-  Bahay
-  Maghanap
-  
-  Mga subscription
-  Galugarin
-  
-  Tab mo
-  Nagustuhan ang mga video
-  
-  Kasaysayan
+  Itakda ang panimulang pahina
+  Regular
+  Galugarin
+  Kasaysayan
+  Nagustuhan ang mga video
+  Maghanap
+  Mga subscription
   
   
   Huwag paganahin ang pagpapatuloy na manlalaro ng Shorts
@@ -936,9 +932,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderno 1
   Moderno 2
   Moderno 3
-  Itago ang mga button na palawakin at isara
-  Nakatago ang mga button\n(i-swipe ang miniplayer para palawakin o isara)
-  Ang mga pindutan ng palawakin at isara ay ipinapakita
+  Itago ang mga button na palawakin at isara
+  Ang mga pindutan ng palawakin at isara ay ipinapakita
   Itago ang mga subtext
   Nakatago ang mga subtext
   Ipinapakita ang mga subtext
@@ -959,7 +954,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Ipinapakita ang orihinal na kulay ng seekbar
   Pasadyang kulay ng seekbar
   Ang kulay ng seekbar
-  Di-wastong halaga ng kulay ng seekbar. Gamit ang default na halaga.
   
   
   
diff --git a/src/main/resources/addresources/values-fr-rFR/strings.xml b/src/main/resources/addresources/values-fr-rFR/strings.xml
index 839753bbb1..2e0a60836a 100644
--- a/src/main/resources/addresources/values-fr-rFR/strings.xml
+++ b/src/main/resources/addresources/values-fr-rFR/strings.xml
@@ -36,26 +36,28 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Les vérifications ont échoué
   Ouvrir le site web officiel
   Ignorer
-  Corrigé sur un autre appareil
-  Non installé par ReVanced Manager
-  Corrigé il y a plus de 10 minutes
-  La date de compilation APK est corrompue
+  <h5>Cette application ne semble pas avoir été patché par vous.</h5><br>Cette application peut ne pas fonctionner correctement, <b>être nocive ou même dangereuse à utiliser<br><br><small>Cette vérification implique que cette application à été pré-patché ou obtenue par quelqu\'un d\'autre:<br><br><small>%1$s</small><br>Il est fortement conseillé de <b>désinstaller cette application et de le patcher vous-même</b> afin d\'être sûr d\'utiliser une application valide et sécurisée.<p><br>Si cet avertissement est ignoré, il sera affiché deux fois.
+  Patché depuis un appareil différent
+  Non installé depuis ReVanced Manager
+  Patché il y a plus de 10 minutes
+  Patché il y as %s jours
+  La date de compilation de l\'APK est corrompue
   
   
   ReVanced
   Souhaitez-vous continuer ?
   Réinitialiser
-  Actualiser et redémarrer
+  Appliquer et redémarrer ?
   Redémarrer
   Importer
   Copier
-  Réglages ReVanced réinitialisés aux valeurs par défaut
+  Les paramètres ReVanced ont étés réinitialisés
   %d paramètres importés
   Échec de l\'importation : %s
   Importer / Exporter
   Importer / Exporter les paramètres ReVanced
   
-  Vous utilisez la version de ReVanced Patches <i>%s</i>
+  Vous utilisez la version <i>%s</i> de ReVanced Patches 
   Note
   Cette version est une pré-version et vous pourriez rencontrer des problèmes inattendus
   Liens officiels
@@ -63,11 +65,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  MicroG GmsCore n\'est pas installé. Installez-le.
+  MicroG GmsCore n\'est pas installé. Veuillez l’installer.
   Action requise 
-  MicroG GmsCore n\'est pas autorisé à s\'exécuter en arrière-plan.\n\nSuivez le guide \"Ne pas tuer mon application\" sur votre téléphone et appliquez les instructions à votre installation de MicroG.\n\nCeci est nécessaire pour que l\'application fonctionne.
+  MicroG GmsCore n\'a pas les permissions pour fonctionner en arrière-plan.\n\nSuivez le guide \"Don\'t kill my app!\" pour votre appareil, et appliquez les instructions pour votre installation MicroG.\n\nRequis pour que l\'application fonctionne.
   Ouvrir le site web
-  Les optimisations de batterie MicroG GmsCore doivent être désactivées pour éviter les problèmes.\n\nAppuyez sur le bouton continuer et désactivez les optimisations de batterie.
+  L\'optimisation de la batterie de MicroG GmsCore doit être désactivé pour éviter tout problème.\n\nCliquez sur le bouton Continuer et désactivez les optimisations de la batterie.
   Continuer
   
   
@@ -78,9 +80,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Miniatures alternatives
   Flux
   Lecteur
-  Disposition générale
+  Mise en page générale
   Barre de progression
-  Contrôle par gestes
+  Contrôles par gestes
   Divers
   Vidéo
   
@@ -90,7 +92,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Journal de débogage
   Les journaux de débogage sont activés
   Les journaux de débogage sont désactivés
-  Mémoire tampon du protocole de journal
+  Journaliser le protocole de mise en mémoire tampon 
   Les journaux de débogage incluent le proto buffer
   Les journaux de débogage n\'incluent pas le proto buffer
   Enregistrer les traces de la pile
@@ -102,47 +104,47 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Désactiver les toasts d\'erreur masque toutes les notifications d\'erreur ReVanced\n\nVous ne serez pas notifié des événements inattendus.
   
   
-  Désactiver la lueur du bouton \"J\'aime\" / \"S\'abonner\"
-  Le bouton J\'aime et S\'abonner ne clignotera pas lorsque mentionné
-  Le bouton J\'aime et S\'abonner clignotera lorsque mentionné
-  Masquer le séparateur gris
+  Désactiver la lueur des boutons \"J\'aime\" / \"Je n\'aime pas\"
+  Les boutons \"J\'aime\" et \"Je n\'aime pas\" ne s\'illuminerons pas lorsqu\'ils sont mentionné
+  Les boutons \"J\'aime\" et \"Je n\'aime pas\" s\'illuminerons lorsqu\'ils sont mentionné
+  Masquer les séparateurs gris
   Les séparateurs gris sont masqués
   Les séparateurs gris sont affichés
-  Masquer le filigrane de la chaîne
+  Masquer le filigrane de chaine
   Le filigrane est masqué
   Le filigrane est affiché
-  Masquer les tablettes horizontales
-  Les étagères sont cachées telles que :\n• Breaking News\n• Continue watching\n• Explorer plus de canaux\n• Shopping\n• Regarder
+  Masquer les étagères horizontales
+  Les étagères sont masquées telles que :\n• Actualités\n• Continuer à regarder\n• Explorer d\'autres chaînes\n• Produits\n• Regarder à nouveau
   Les étagères sont affichées
   
-  Cacher le bouton \'Rejoindre\'
+  Masquer le bouton \'Rejoindre\'
   Le bouton est masqué
   Le bouton est affiché
   
-  Cacher l\'étagère \'Pour vous\' dans la page du canal
+  Masquer l\'étagère \'Pour vous\' dans la page de la chaine
   L\'étagère est masquée
   L\'étagère est affichée
   
-  Cacher le bouton \'Notifier moi\'
+  Masquer le bouton \'Recevoir une Notification\'
   Le bouton est masqué
   Le bouton est affiché
   
-  Masquer les recommandations \'Les gens ont aussi regardé\'
+  Masquer les recommandations \'Les internautes ont aussi regardé\'
   Les recommandations sont masquées
   Les recommandations sont affichées
   
-  Cacher le bouton \'Afficher plus\'
+  Marquer le bouton \'Voir plus\'
   Le bouton est masqué
   Le bouton est affiché
   Masquer les réactions en temps réel
-  Les réactions en temps réel sont masquées
-  Les réactions en temps réel sont affichées
-  Masquer le tiroir d\'en-tête des résultats de recherche
-  Le tiroir d\'en-tête est masqué
-  Le tiroir d\'en-tête est affiché
+  Les réactions en temps réel sont masqués
+  Les réactions en temps réel sont affichés
+  Masquer l\'en-tête de l\'étagère des résultats de recherche
+  L\'en-tête de l\'étagère est masqué
+  L\'en-tête de l\'étagère est affiché
   Masquer les règles de la chaîne
   Les règles de la chaîne sont masqués
   Les règles de la chaîne sont affichés
@@ -155,9 +157,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Masquer le pied de page du menu de la qualité de la vidéo
   Le pied de page du menu de la qualité de la vidéo est masqué
   Le pied de page du menu de la qualité de la vidéo est affiché
-  Masquer les posts de la communauté
-  Les posts de la communauté sont masqués
-  Les posts de la communauté sont affichés
+  Masquer les posts communautaires
+  Les posts communautaires sont masqués
+  Les posts communautaires sont affichés
   Masquer les bannières compactes
   Les bannières compactes sont masquées
   Les bannières compactes sont affichées
@@ -167,188 +169,193 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Masquer les sondages dans les flux
   Les sondages dans les flux sont masqués
   Les sondages dans les flux sont affichés
-  Masquer les règlements de la communauté
-  Les règlements de la communauté sont masqués
-  Les règlements de la communauté sont affichés
-  Masquer les règlements de la communauté des abonnés
-  Les règlements de la communauté des abonnés sont masqués
-  Les règlements de la communauté des abonnés sont affichés
-  Masquer le tiroir des membres de la chaîne
-  Le tiroir des membres de la chaîne est masqué
-  Le tiroir des membres de la chaîne est affiché
+  Masquer les règles de la communauté
+  Les règles de la communauté sont masqués
+  Les règles de la communauté sont affichés
+  Masquer les règles de la communauté des abonnés
+  Les règles de la communauté des abonnés sont masqués
+  Les règles de la communauté des abonnés sont affichés
+  Masquer l\'étagère des membres de la chaîne
+  L\'étagère des membres de la chaîne est masqué
+  L\'étagère des membres de la chaîne est affiché
   Masquer les boîtes d\'urgence
   Les boîtes d\'urgence sont masquées
   Les boîtes d\'urgence sont affichées
   Masquer les panneaux d\'information
   Les panneaux d\'information sont masqués
   Les panneaux d\'information sont affichés
-  Masquer les panneaux médicaux
-  Les panneaux médicaux sont masqués
-  Les panneaux médicaux sont affichés
-  Masquer la barre de la chaîne
-  La barre de la chaîne est masquée
-  La barre de la chaîne est affichée
+  Masquer les panneaux d\'infos médicaux
+  Les panneaux d\'infos médicaux sont masqués
+  Les panneaux d\'infos médicaux sont affichés
+  Masquer la barre de chaîne 
+  La barre de chaîne est masquée
+  La barre de chaîne est affichée
   Masquer les jeux intégrés
-  Les jeux sont masqués
-  Les jeux sont affichés
+  Les jeux intêgrés sont masqués
+  Les jeux intégrés sont affichés
   Masquer les actions rapides en plein écran
-  Les actions rapides en plein écran sont masquées
-  Les actions rapides en plein écran sont affichées
-  Masquer les vidéos associées dans les actions rapides
-  Les vidéos associées sont masquées
-  Les vidéos associées sont affichées
+  Les actions rapides sont masquées
+  Les actions rapides sont affichées
+  Masquer les vidéos similaires dans les actions rapides
+  Les vidéos similaires sont masquées
+  Les vidéos similaires sont affichées
   Masquer l\'étagère d\'image dans les résultats de recherche
   L\'étagère d\'image est masquée
   L\'étagère d\'image est affichée
-  Masquer les derniers posts
-  Les derniers posts sont masqués
-  Les derniers posts sont affichés
-  Masquer les playlists Mix
-  Les playlists Mix sont masquées
-  Les playlists Mix sont affichées
+  Masquer les posts récents
+  Les posts récents sont masqués
+  Les posts récents sont affichés
+  Masquer les playlists mix
+  Les playlists mix sont masqués
+  Les playlists mix sont affichés
   Masquer les cartes d\'artiste
   Les cartes d\'artiste sont masquées
   Les cartes d\'artiste sont affichées
-  Masquer la section des attributs
-  Les sections « Lieux en vedette », « Jeux » et « Musique » sont masquées
-  Les sections « Lieux en vedette », « Jeux » et « Musique » sont affichées
+  Masquer la section mentions
+  Les sections \'Lieux Populaires\', \'Jeux\' et \'Musique\' sont masquées
+  Les sections \'Lieux Populaires\', \'Jeux\' et \'Musique\' sont affichées
   Masquer la section des chapitres
   La section des chapitres est masquée
   La section des chapitres est affichée
-  Masquer la section « Explorer le podcast »
-  La section « Explorer le podcast » est masquée
-  La section « Explorer le podcast » est affichée
-  Masquer les cartes d\'information
-  Les cartes d\'information sont masquées
-  Les cartes d\'information sont affichées
-  Masquer la section \"concepts clés\"
-  La section \"Concepts clé\" est masquée
-  La section \"Concepts clé\" est affichée
-  Masquer la section de transcription
-  La section transcription est masquée
-  La section transcription est affichée
+  Masquer la section \'Explorer les podcasts\'
+  La section \'Explorer les podcasts\' est masquée
+  La section \'Explorer les podcasts\' est affichée
+  Masquer la section des fiches infos
+  La section des fiches infos est masquée
+  La section des fiches infos est affichée
+  Masquer la section \'Concepts clés\'
+  La section \"Concepts clés\" est masqué
+  La section \"Concepts clés\" est affiché
+  Masquer la section \'Transcription\'
+  La section \'Transcription\' est masqué
+  La section \'Transcription\' est affiché
   Description vidéo
-  Masquer ou afficher les composants de la description de la vidéo
+  Masquer ou afficher des éléments de la description de la vidéo
+  
+  Masquer les Doodles YouTube
+  Les Doodles de la barre de recherche sont masquées
+  Les Doodles de la barre de recherche sont affichées
+  Les Doodles YouTube apparaissent quelques jours par an.\n\nSi un Doodle YouTube est actuellement diffusé dans votre région et que le paramètre pour le masquer est activé, la barre de filtre située à côté de la barre de recherche sera également masquée.
   Filtre personnalisé
-  Masquer les composants utilisant des filtres personnalisés
-  Activer le filtre personnalisé
-  Le filtre personnalisé est activé
-  Le filtre personnalisé est désactivé
+  Masquer des composants en utilisant des filtres personnalisés
+  Activer les filtres personnalisés
+  Les filtres personnalisés sont activés
+  Les filtres personnalisés sont désactivés
   Filtre personnalisé
   
-  Liste de chaînes de caractères à filtrer, séparées par une nouvelle ligne
+  Filtrer la liste des noms du composant séparés par un saut de ligne
   Filtre personnalisé invalide : %s
-  Masquer le contenu du mot-clé
-  Masquer les recherches et les vidéos du flux à l\'aide de filtres par mots-clés
-  Masquer les vidéos de l\'onglet \"Accueil\" par mots-clés
-  Les vidéos dans l\'onglet \"Accueil\" sont filtrées par mots-clés
-  Les vidéos dans l\'onglet \"Accueil\" ne sont pas filtrées par mots-clés
-  Masquer les vidéos de l\'onglet \"Abonnements\" par mots-clés
-  Les vidéos de l\'onglet \"Abonnements\" sont filtrées par mots-clés
-  Les vidéos de l\'onglet \"Abonnements\" ne sont pas filtrées par mots-clés
-  Masquer les résultats de recherche par mots-clés
+  Masquer le contenu par mot-clé
+  Filtrer les recherches et le flux des vidéos par mots-clés
+  Filtrer la page d\'accueil par mot-clés
+  Les vidéos dans l\'onglet \'accueil\' sont filtrées par des mots-clés
+  Les vidéos dans l\'onglet \'accueil\' ne sont pas filtrées par des mots-clés
+  Filtrer les vidéos de l\'onglet \"Abonnements\" par mots-clés
+  Les vidéos de l\'onglet \'Abonnements\' sont filtrées par mots-clés
+  Les vidéos de l\'onglet \'Abonnements\' ne sont pas filtrées par mots-clés
+  Filtrer les résultats de recherches par mots-clés
   Les résultats de recherche sont filtrés par mots-clés
   Les résultats de recherche ne sont pas filtrés par mots-clés
-  Mots-clés à cacher
+  Mots-clés à masquer
   
-  Mots-clés et phrases à cacher, séparés par les nouvelles lignes\n\nLes mots-clés peuvent être des noms de canaux ou tout texte affiché dans les titres vidéo\n\nLes mots avec des lettres majuscules au milieu doivent être saisis avec la casse (i: iPhone, TikTok, LeBlanc)
+  Mots-clés et phrases à masquer, séparés par des sauts de lignes.\n\nLes mots-clés peuvent être des noms de chaînes ou tout texte figurant dans les titres des vidéos.\n\nLes mots comportant des majuscules au milieu doivent être saisis de la même façon (par exemple : iPhone, TikTok, TheoBabac)
   À propos du filtrage par mots-clés
-  Les résultats d\'accueil/abonnement/recherche sont filtrés pour masquer le contenu qui correspond aux expressions clés\n\nLimitations\n• Les courts ne peuvent pas être cachés par le nom du canal\n• Certains composants de l\'interface utilisateur ne peuvent pas être cachés\n• La recherche d\'un mot clé peut n\'afficher aucun résultat
-  Correspond à des mots entiers
+  Les onglets \'Pages d\'accueil\' / \'Abonnements\' / Résultats de recherche sont filtrés pour masquer le contenu correspondant aux mots clés.\n\nLimitations\n• Les shorts ne peuvent pas être masqués par le nom de la chaîne\n• Certains éléments de l\'interface utilisateur peuvent ne pas être masqués\n• La recherche par mot-clé peut n\'afficher aucun résultat
+  Faire correspondre des mots complets
   
-  Arrondir un mot-clé/phrase avec des guillemets doubles empêchera les correspondances partielles des titres vidéo et des noms de chaîne<br><br>Par exemple,<br><b>\"ai\"</b> masquera la vidéo : <b>How does AI work?</b><br>mais ne se cachera pas : <b>What does fair use mean?</b>
+  Le fait de placer un mot-clé ou une expression entre guillemets permet d\'éviter les correspondances partielles entre les titres de vidéos et les noms des chaînes.<br><br>Par exemple,<br><b>\"ia\"</b> masquera la vidéo : <b>Comment fonctionne les IA ?</b><br>mais ne masquera pas : <b>Quelles études pour devenir commercial ?</b>
   
-  Impossible d\'utiliser le mot clé : %s
-  Ajouter des guillemets pour utiliser le mot clé: %s
-  Le mot clé a des déclarations conflictuelles : %s
-  Le mot clé est trop court et nécessite des guillemets : %s
-  Le mot-clé masquera toutes les vidéos : %s
+  Impossible d\'utiliser ce mot-clé : %s
+  Ajouter des guillemets pour utiliser un mot-clé : %s
+  Le mot-clé a des déclarations en conflit : %s
+  Le mot-clé est trop court et nécessite des guillemets : %s
+  Ce mot-clé va masquer toutes les vidéos : %s
   
   
-  Masquer les pubs générales
-  Les pubs générales sont masquées
-  Les pubs générales sont affichées
+  Masquer les publicités générales
+  Les publicités générales sont masquées
+  Les publicités générales sont affichées
   Masquer les publicités en plein écran
-  Les publicités en plein écran sont masquées\n\nCette fonctionnalité est uniquement disponible pour les appareils plus anciens
+  Les publicités en plein écran sont masquées\n\nCette fonctionnalité n\'est disponible uniquement pour les appareils plus anciens
   Les publicités en plein écran sont affichées
-  Masquer les boutons de publicité
-  Les boutons de publicité sont masqués
-  Les boutons de publicité sont affichés
-  Masquer la bannière \"Communication commerciale\"
-  La bannière \"Communication commerciale\" est masquée
-  La bannière \"Communication commerciale\" est affichée
-  Masquer les cartes auto-sponsorisées
-  Les cartes auto-sponsorisées sont masquées
-  Les cartes auto-sponsorisées sont affichées
-  Masquer la bannière pour visualiser les produits
+  Masquer les publicités cliquables
+  Les publicités cliquables sont masqués
+  Les publicités cliquables sont affichés
+  Masquer la bannière \'Communication commerciale\'
+  La bannière \"Inclut une communication commerciale\" est masqué
+  La bannière \"Inclut une communication commerciale\" est affiché
+  Masquer les cartes autosponsorisées
+  Les cartes autosponsorisées sont masquées
+  Les cartes autosponsorisées sont affichées
+  Masquer la bannière \'Afficher les produits\'
   La bannière est masquée
   La bannière est affichée
-  Masquer les liens d\'achat dans la description de la vidéo
-  Les liens d\'achat sont masqués
-  Les liens d\'achat sont affichés
+  Masquer les liens des produits dans la description de la vidéo
+  Les liens des produits sont masqués
+  Les liens de produits sont affichés
   
   Masquer le bouton \'Visiter la boutique\' sur la page de la chaîne
   Le bouton est masqué
   Le bouton est affiché
-  Masquer les résultats de la recherche web
-  Les résultats de recherche sur le web sont masqués
-  Les résultats de la recherche sur le web sont affichés
-  Cacher les bannières commerciales
-  Les bannières de marchandise de la chaîne sont masquées
-  Les bannières de marchandise sont affichées
+  Masquer les résultats web
+  Les résultats web sont masqués
+  Les résultats web sont affichés
+  Masquer la bannière \'Effectuer des achats dans le magasin ... \'
+  La bannière \'Effectuer des achats dans le magasin ...\' est masquée
+  L\'étagère \'Effectuer des achats dans le magasin ...\' est affichée
   
   Masquer les publicités en plein écran ne fonctionne qu\'avec les appareils plus anciens
   
   
-  Masquer les publicités YouTube Premium
-  Les publicités YouTube Premium sous le lecteur vidéo sont masquées.
-  Les publicités YouTube Premium sous le lecteur vidéo sont affichées
+  Masquer les publicités pour YouTube Premium 
+  Les publicités pour YouTube Premium sous le lecteur vidéo sont masquées
+  Les publicités pour YouTube Premium sous le lecteur vidéo sont affichées
   
   
-  Masquer les annonces vidéo
-  Les annonces vidéo sont masquées
-  Les annonces vidéo sont affichées
+  Masquer les publicités vidéo
+  Les publicités vidéo sont masquées
+  Les publicités vidéo sont affichées
   
   
-  URL copiée dans le presse-papier
-  URL avec horodatage copiée
-  Afficher le bouton Copier l\'URL de la vidéo
-  Le bouton est affiché. Appuyez pour copier l\'URL de la vidéo. Appuyez et maintenez pour copier l\'URL de la vidéo avec l\'horodatage
+  URL copié dans le presse-papier
+  URL avec horodatage copié
+  Afficher un bouton \"Copier le lien de la vidéo\"
+  Le bouton est affiché. Appuyez pour copier l\'URL de la vidéo. Appuyez longuement pour copier l\'URL de la vidéo avec l\'horodatage
   Le bouton n\'est pas affiché
-  Afficher le bouton copier l\'URL avec horodatage
-  Le bouton est affiché. Appuyez pour copier l\'URL de la vidéo avec horodatage. Appuyez et maintenez enfoncé pour copier la vidéo sans horodatage
+  Afficher un bouton \'Copier lien avec horodatage\'
+  Le bouton est affiché. Appuyez pour copier le lien de la vidéo avec horodatage. Appuyez longuement pour copier la vidéo sans horodatage
   Le bouton n\'est pas affiché
   
   
-  Supprimer la confirmation pour les vidéos avec limite d\'âge
-  Le dialogue de confirmation sera supprimé
-  Le dialogue de confirmation sera affiché
-  Cela ne contourne pas la restriction d\'âge. Il l\'accepte tout simplement automatiquement.
+  Supprimer le message \'Confirmer votre âge\'
+  Le message sera supprimé
+  Le message sera affiché
+  Cela ne contourne pas la restriction d\'âge, mais le confirme automatiquement.
   
   
-  Téléchargements externes
-  Paramètres pour utiliser un téléchargeur externe
+  Téléchargeur externe
+  Paramètres d\'utilisation du téléchargeur externe
   Afficher le bouton de téléchargement externe
-  Bouton de téléchargement affiché dans le lecteur
-  Bouton de téléchargement non affiché dans le lecteur
+  Bouton de téléchargement affiché sur le lecteur
+  Bouton de téléchargement non affiché sur le lecteur
   
-  Remplacer l\'action du bouton téléchargement
+  Remplacer l\'action du bouton de téléchargement
   Le bouton de téléchargement ouvre votre téléchargeur externe
   Le bouton de téléchargement ouvre le téléchargeur natif dans l\'application
-  Nom du package du téléchargeur
-  Nom du package de votre application de téléchargement externe installée, comme NewPipe ou Seal
+  Nom du paquet du téléchargeur vidéo
+  Nom du paquet de l\'appli de téléchargement externe installée, telle que NewPipe ou Seal
   %s n\'est pas installé. Veuillez l\'installer.
   
   
   Désactiver le geste de recherche précise
-  Geste désactivé
-  Le geste est activé
+  Les gestes sont désactivés
+  Les gestes sont activés
   
   
-  Activer l\'appui dans la barre de lecture
-  L\'appui dans la barre de lecture est activé
-  L\'appui dans la barre de lecture est désactivé
+  Activer l\'appui sur la barre de progression
+  L\'appui sur la barre de progression est activé
+  L\'appui sur la barre de progression est désactivé
   
   
   Activer les gestes pour la luminosité
@@ -357,27 +364,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Activer les gestes pour le volume
   Les gestes de contrôle du volume sont activés
   Les gestes de contrôle du volume sont désactivés
-  Activer le geste d\'appui pour glisser
-  Appui pour glisser est activé
-  Appui pour glisser est désactivé
+  Activer les gestes de commande
+  Les gestes de commande sont activés
+  Les gestes de commande sont désactivés
   Activer le retour haptique
   Le retour haptique est activé
   Le retour haptique est désactivé
   Enregistrer et restaurer la luminosité
   Enregistrer et restaurer la luminosité en quittant ou en entrant en plein écran
-  Ne pas enregistrer et restaurer la luminosité en quittant ou en entrant en plein écran
-  Activer le geste de luminosité automatique
-  Glisser vers le bas vers la valeur la plus basse du geste de luminosité active la luminosité automatique
-  Glisser vers le bas vers la valeur la plus basse n\'active pas la luminosité automatique
+  N\'enregistre et ne restaure pas la luminosité en quittant ou en entrant en plein écran
+  Activer les gestes de luminosité automatique
+  Glisser vers le bas à la valeur la plus basse des gestes de luminosité active la luminosité automatique
+  Glisser vers le bas à la valeur la plus basse n\'active pas la luminosité automatique
   Automatique
   Délai de l\'overlay des gestes
-  Le temps en millisecondes où l\'overlay est visible
-  Taille du texte de l\'overlay des gestes
-  La taille du texte pour l\'overlay des gestes
-  Visibilité de l\'arrière-plan en glissant
-  La visibilité de l\'arrière-plan de l\'overlay des gestes
-  Seuil de magnitude de balayage
-  La quantité de seuil pour que le balayage se produise
+  La durée en millisecondes pendant laquelle l\'overlay est visible
+  Taille du texte sur l\'overlay lors des gestes
+  La taille du texte sur l\'overlay lors des gestes
+  Visibilité de l\'arrière-plan lors des gestes
+  La visibilité de l\'overlay en arrière-plan lors des gestes
+  Intensité des gestes
+  L\'intensité du mouvement à effectuer pour que les gestes se produise
   
   
   Désactiver les sous-titres automatiques
@@ -386,86 +393,86 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   Boutons d\'action
-  Masquer ou afficher les boutons sous les vidéos
-  Masquer J\'aime et je n\'aime pas
-  Les boutons J\'aime et je n\'aime pas sont cachés
-  Les boutons J\'aime et Je n\'aime pas sont affichés
+  Masque ou affiche les boutons sous les vidéos
+  Masquer les \'J\'aime\' et \'Je n\'aime pas\'
+  Les boutons \'J\'aime\' et \'Je n\'aime pas\' sont masqués
+  Les boutons \'J\'aime\' et \'Je n\'aime pas\' sont affichés
   
-  Cacher le partage
-  Le bouton de partage est masqué
-  Le bouton de partage est affiché
+  Masquer \'Partager\'
+  Le bouton \'Partager\' est masqué
+  Le bouton \'Partager\' est affiché
   
-  Masquer le rapport
-  Le bouton de rapport est caché
-  Le bouton de rapport est affiché
+  Masquer \'Signaler\'
+  Le bouton \'Signaler\' est masqué
+  Le bouton \'Signaler\' est affiché
   
-  Masquer le remix
-  Le bouton Remix est masqué
-  Le bouton Remix est affiché
+  Masquer \'Remixer\'
+  Le bouton \'Remixer\' est masqué
+  Le bouton \'Remixer\' est affiché
   
-  Masquer le téléchargement
-  Le bouton de téléchargement est caché
-  Le bouton de téléchargement est affiché
+  Masquer \'Télécharger\'
+  Le bouton \'Télécharger\' est masqué
+  Le bouton \'Télécharger\' est affiché
   
-  Cacher les remerciements
-  Le bouton de remerciement est caché
-  Le bouton de remerciement est affiché
+  Masquer \'Merci\'
+  Le bouton \'Merci\' est masqué
+  Le bouton \'Merci\' est affiché
   
-  Masquer Extrait
-  Le bouton Extrait est masqué
-  Le bouton Extrait est affiché
+  Masquer \'Extrait\'
+  Le bouton \'Extrait\' est masqué
+  Le bouton \'Extrait\' est affiché
   
-  Cacher Enregistrer dans la playlist
-  Le bouton Enregistrer dans la liste de lecture est masqué
-  Le bouton Enregistrer dans la liste de lecture est affiché
+  Masquer \'Enregistrer dans la playlist\'
+  Le bouton \'Enregistrer dans la playlist\' est masqué
+  Le bouton \'Enregistrer dans la playlist\' est affiché
   
   
-  Masquer le bouton de lecture automatique
-  Le bouton de lecture automatique est masqué
-  Le bouton de lecture automatique est affiché
+  Masquer le bouton \'Lecture automatique\'
+  Le bouton \"Lecture automatique\" est masqué
+  Le bouton \"Lecture automatique\" est affiché
   
   
   
-  Masquer le bouton des légendes
-  Le bouton des légendes est caché
-  Le bouton des légendes est affiché
+  Masquer le bouton \'Sous-titres\'
+  Le bouton \'Sous-titres\' est masqué
+  Le bouton \'Sous-titres\' est affiché
   
   
-  Cacher le bouton de diffusion
-  Le bouton de Cast est masqué
-  Le bouton de Cast est affiché
+  Masquer le bouton \'Caster\'
+  Le bouton \'Caster\' est masqué
+  Le bouton \'Caster\' est affiché
   
   
-  Navigation buttons
+  Boutons de navigation
   Masquer ou modifier les boutons dans la barre de navigation
   
-  Masquer la page d\'accueil
-  Le bouton Accueil est caché
-  Le bouton d\'accueil est affiché
+  Masquer \'Accueil\'
+  Le bouton \'Accueil\' est masqué
+  Le bouton \'Accueil\' est affiché
   
-  Cacher les Shorts
-  Le bouton Shorts est masqué
-  Le bouton Shorts est affiché
+  Masquer \'Shorts\'
+  Le bouton \'Shorts\' est masqué
+  Le bouton \'Shorts\' est affiché
   
-  Cacher la création
-  Le bouton de création est masqué
-  Le bouton de création est affiché
+  Masquer \'Créer\'
+  Le bouton \'Créer\' est masqué
+  Le bouton \'Créer\' est affiché
   
-  Cacher les abonnements
-  Le bouton des abonnements est masqué
-  Le bouton des abonnements est affiché
+  Masquer \'Abonnements\'
+  Le bouton \'Abonnements\' est masqué
+  Le bouton \'Abonnements\' est affiché
   
-  Changer de création avec les notifications
-  Le bouton de création est échangé avec le bouton de notifications\n\nNote: L\'activation de cette option masque également les publicités vidéo
-  Le bouton Créer n\'est pas basculé avec le bouton Notifications
-  Masquer les libellés des boutons de navigation
-  Les libellés sont masquées
-  Les libellés sont affichées
+  Échanger \'Créer\' et \'Notifications\'
+  Le bouton \'Créer\' est échangé avec le bouton \'Notification\'\n\nNote : Activer ceci masquera également les publicités vidéos
+  Le bouton \'Créer\' n\'est pas échangé avec le bouton \'Notification\'
+  Masquer les noms des boutons de navigation
+  Les noms sont masqués
+  Les noms sont affichés
   
   
-  Flyout menu
-  Masquer ou afficher les éléments du menu Flyout du joueur
+  Menu déroulant
+  Masquer ou afficher les éléments du menu déroulant du lecteur
   
   Cacher les légendes
   Le menu des sous-titres est masqué
@@ -627,14 +634,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Le libellé de l\'emplacement est masqué
   Le libellé de l\'emplacement est affiché
   Masquer le bouton \"Enregistrer la musique\" 
-  \"Enregistrer la musique\" est masqué 
-  \"Enregistrer la musique\" est affiché 
+  Le bouton Enregistrer de la musique est masqué
+  Le bouton Enregistrer la musique est affiché
+  Cacher le bouton utiliser le modèle
+  Le bouton utiliser le modèle est caché
+  Utiliser le bouton du modèle est affiché
+  Masquer le bouton à venir
+  Le bouton à venir est masqué
+  Le bouton à venir est affiché
+  Masquer le bouton de l\'écran vert
+  Le bouton de l\'écran vert est masqué
+  Le bouton de l\'écran vert est affiché
+  Masquer le bouton de hashtag
+  Le bouton Hashtag est caché
+  Le bouton Hashtag est affiché
   Masquer les suggestions de recherche
   Les suggestions de recherche sont masquées
   Suggestions de recherche affichées
   Masquer les stickers
   Les stickers sont masqués
   Les stickers sont affichés
+  Cacher comme fontaine
+  L\'animation \"J\'aime\" de la fontaine du bouton est cachée
+  Animation de la fontaine du bouton J\'aime est affichée
   Masquer le bouton \"J\'aime\"
   Le bouton J\'aime est caché
   Le bouton J\'aime est affiché
@@ -945,20 +967,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Restaurer l\'ancienne mise en page de l\'interface
   
   
-  Définir la page de démarrage
-  Par défaut
-  
-  Domicile
-  Chercher
-  
-  Abonnements
-  Explorer
-  
-  Votre onglet
-  Vidéos aimées
-  
-  Historique
-  Tendance
+  Définir la page de démarrage
+  Par défaut
+  Parcourir les chaînes
+  Explorer
+  Jeu
+  Historique
+  Bibliothèque
+  Vidéos aimées
+  En direct
+  Films
+  Musique
+  Chercher
+  Sportif
+  Abonnements
+  Tendance
+  Regarder plus tard
   
   
   Désactiver la reprise du joueur Shorts
@@ -981,15 +1005,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderne 1
   Moderne 2
   Moderne 3
-  Masquer les boutons d\'agrandissement et de fermeture
-  Les boutons sont cachés\n(glisser le lecteur réduit pour l\'agrandir ou le fermer)
-  Les boutons agrandir et fermer sont affichés
+  Activer les coins arrondis
+  Les coins sont arrondis
+  Les coins sont carrés
+  Activer le double appui et pincer pour redimensionner
+  L\'action de double appui et le pincement pour redimensionner est activé\n\n• Double appui pour augmenter la taille du mini-joueur\n• Double appui à nouveau pour restaurer la taille d\'origine
+  Action de double appui et pincement pour redimensionner est désactivé
+  Activer le glisser-déposer
+  Le glisser-déposer est activé\n\nMiniplayer peut être déplacé vers n\'importe quel coin de l\'écran
+  Glisser-déposer est désactivé
+  Masquer le bouton de fermeture
+  Le bouton de fermeture est masqué
+  Le bouton de fermeture est affiché
+  Masquer les boutons d\'agrandissement et de fermeture
+  Les boutons sont cachés\n\nGlisser pour s\'étendre ou fermer
+  Les boutons agrandir et fermer sont affichés
   Masquer les sous-textes
   Les sous-textes sont cachés
   Les sous-textes sont affichés
   Masquer les boutons avancer et reculer
   Les boutons avancer et reculer sont masqués
   Les boutons avancer et reculer sont affichés
+  Taille initiale
+  Initial à la taille de l\'écran, en pixels
+  La taille du pixel doit être comprise entre %1$s et %2$s
   Opacité de l\'overlay
   Valeur d\'opacité entre 0 et 100, où 0 est transparent
   L\'opacité de l\'overlay du Miniplayer doit être comprise entre 0 et 100
@@ -1005,7 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   La couleur originale de la barre de recherche est affichée
   Couleur personnalisée de la barre de recherche
   La couleur de la barre de recherche
-  Valeur de couleur de la barre de recherche invalide.
+  Valeur de couleur de la barre de recherche invalide
   
   
   Ignorer les restrictions de région de l\'image
diff --git a/src/main/resources/addresources/values-ga-rIE/strings.xml b/src/main/resources/addresources/values-ga-rIE/strings.xml
index d27ea0c815..f77e1b0976 100644
--- a/src/main/resources/addresources/values-ga-rIE/strings.xml
+++ b/src/main/resources/addresources/values-ga-rIE/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Taispeántar alt an tras-scríbhinn
   Cur síos físeán
   Folaigh nó taispeáint comhpháirteanna tuairisc
+  
+  Folaigh YouTube Doodles
+  Barra cuardaigh Tá Doodles i bhfolach
+  Barra cuardaigh Taispeántar Doodles
+  Taispeántar Doodles YouTube cúpla lá gach bliain.\n\nMá tá Doodle á thaispeáint i do réigiún faoi láthair agus an socrú folaithe seo ar siúl, ansin beidh an barra scagaire faoin mbarra cuardaigh i bhfolach freisin.
   Scagaire saincheaptha
   Folaigh comhpháirteanna ag baint úsáide as
   Cumasaigh scagaire saincheaptha
@@ -627,9 +632,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Folaigh lipéad suímh
   Tá lipéad suímh i bhfolach
   Taispeántar lipéad suímh
+  Folaigh an cnaipe Sábháil ceoil
+  Tá an cnaipe Sábháil ceoil i bhfolach
+  Taispeántar an cnaipe Sábháil ceoil
+  Folaigh an cnaipe teimpléid úsáide
+  Tá cnaipe teimpléad Úsáid i bhfolach
+  Taispeántar an cnaipe teimpléad a úsáid
+  Folaigh an cnaipe atá le teacht
+  Tá cnaipe atá le teacht i bhfolach
+  Taispeántar an cnaipe atá le teacht
+  Folaigh an cnaipe scáileán glas
+  Tá cnaipe an scáileáin glas i bhfolach
+  Taispeántar cnaipe an scáileáin glas
   Folaigh moltaí cuardaigh
   Tá moltaí cuardaigh i bhfolach
   Taispeántar moltaí cuardaigh
+  Folaigh greamáin
+  Tá greamáin i bhfolach
+  Taispeántar greamáin
+  Folaigh cosúil le tobair
+  Cosúil le beochan tobair cnaipe i bhfolach
+  Taispeántar beochan tobair cnaipe cosúil le cnaipe
   Folaigh cosúil le cnaipe
   Tá an cnaipe Cosúil i bhfolach
   Taispeántar an cnaipe Cosúil
@@ -940,20 +963,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Athchóirigh sean leagan amach Chomhéadain
   
   
-  Socraigh leathanach tosaigh
-  Réamhshocraithe
-  
-  Baile
-  Cuardaigh
-  
-  Síntiúis
-  Déan iniúchadh
-  
-  Tú cluaisín
-  Físeáin a thaitin
-  
-  Stair
-  Ag treocht
+  Socraigh leathanach tosaigh
+  Réamhshocraithe
+  Déan iniúchadh
+  Stair
+  Físeáin a thaitin
+  Cuardaigh
+  Síntiúis
+  Ag treocht
   
   
   Díchumasaigh an t-imreoir Shorts atá ag tosú arís
@@ -976,9 +993,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Nua-aimseartha 1
   Nua-Aimseartha 2
   Nua-aimseartha 3
-  Folaigh cnaipí leathnú agus dún
-  Tá cnaipí i bhfolach\n(sleamhnaigh miniplayer chun leathnú nó dúnadh)
-  Taispeántar cnaipí leathnaigh agus dún
+  Folaigh cnaipí leathnú agus dún
+  Taispeántar cnaipí leathnaigh agus dún
   Folaigh fothéacsanna
   Tá fothéacsanna i bhfolach
   Taispeántar fothéacsanna
@@ -1000,7 +1016,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Taispeántar dath barr cuardaigh bunaidh
   Dath barra cuardaigh saincheaptha
   Dath an bharra cuardaigh
-  Luach dath barra cuardaigh neamhbhailí. Ag úsáid luach réamhshocraithe.
   
   
   Seachbhóthar srianta réigiún íomhá
diff --git a/src/main/resources/addresources/values-gl-rES/strings.xml b/src/main/resources/addresources/values-gl-rES/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-gl-rES/strings.xml
+++ b/src/main/resources/addresources/values-gl-rES/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-gu-rIN/strings.xml b/src/main/resources/addresources/values-gu-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-gu-rIN/strings.xml
+++ b/src/main/resources/addresources/values-gu-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-hi-rIN/strings.xml b/src/main/resources/addresources/values-hi-rIN/strings.xml
index 546abac188..7eaeff1eb9 100644
--- a/src/main/resources/addresources/values-hi-rIN/strings.xml
+++ b/src/main/resources/addresources/values-hi-rIN/strings.xml
@@ -57,6 +57,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -187,11 +188,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  डिफॉल्ट
-  
-  
-  
-  
+  डिफॉल्ट
   
   
   
diff --git a/src/main/resources/addresources/values-hr-rHR/strings.xml b/src/main/resources/addresources/values-hr-rHR/strings.xml
index 394abff1b6..acfdbda832 100644
--- a/src/main/resources/addresources/values-hr-rHR/strings.xml
+++ b/src/main/resources/addresources/values-hr-rHR/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  Zadano
   
   
   
diff --git a/src/main/resources/addresources/values-hu-rHU/strings.xml b/src/main/resources/addresources/values-hu-rHU/strings.xml
index 743aab1e44..31624d45c2 100644
--- a/src/main/resources/addresources/values-hu-rHU/strings.xml
+++ b/src/main/resources/addresources/values-hu-rHU/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Az átirat rész megjelenik
   Videóleírás
   A videóleírás komponenseinek elrejtése vagy megjelenítése
+  
+  YouTube Doodles elrejtése
+  A Doodles Keresősáv el van rejtve
+  A Doodles Keresősáv megjelenik
+  A YouTube Doodles minden évben néhány napra megjelenik.\n\nHa a régiódban jelenleg látható egy embléma, és ez az elrejtési beállítás be van kapcsolva, akkor a keresősáv alatti szűrősáv is el van rejtve.
   Egyedi szűrő
   Komponensek elrejtése egyedi szűrők használatával
   Egyedi szűrők engedélyezése
@@ -627,9 +632,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Helycímke elrejtése
   A helycímke el van rejtve
   A helycímke megjelenik
+  Zene mentés gomb elrejtése
+  A zene mentés gomb el van rejtve
+  A zene mentés gomb látható
+  A sablon használata gomb elrejtése
+  A Sablon használata gomb el van rejtve
+  A sablon használata gomb látható
+  Közelgő gomb elrejtése
+  A közelgő gomb el van rejtve
+  Megjelenik a Közelgő gomb
+  A zöld képernyőgomb elrejtése
+  A zöld képernyő gomb el van rejtve
+  A zöld képernyő gomb látható
   Keresési javaslatok elrejtése
   A keresési javaslatok el vannak rejtve
   A keresési javaslatok megjelennek
+  Matricák elrejtése
+  A matricák el vannak rejtve
+  A matricák láthatóak
+  Tetszik szökőkút elrejtése
+  A Like gomb szökőkút animáció el van rejtve
+  A Like gomb szökőkút animáció látható
   Tetszik gomb elrejtése
   A tetszik gomb elrejtve
   A tetszik gomb megjelenik
@@ -940,21 +963,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Régi felhasználói felület visszaállítása
   
   
-  Kezdőlap beállítása
-  Alapértelmezett
-  
-  Kezdőlap
-  Keresés
-  
-  Feliratkozások
-  Felfedezés
-  Shorts
-  
-  Te lap
-  Kedvelt videók
-  
-  Előzmények
-  Felkapott
+  Kezdőlap beállítása
+  Alapértelmezett
+  Felfedezés
+  Előzmények
+  Kedvelt videók
+  Keresés
+  Feliratkozások
+  Felkapott
   
   
   A Shorts lejátszás folytatásának kikapcsolása
@@ -977,9 +993,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
-  Kibontás és bezárás gombok elrejtése
-  A gombok el vannak rejtve\n(csúsztassa a minilejátszót a kibontáshoz vagy bezáráshoz)
-  A kibontás és bezárás gombok láthatók
+  Kibontás és bezárás gombok elrejtése
   Alszövegek elrejtése
   Az alszövegek el vannak rejtve
   Alszövegek megjelennek
@@ -1001,7 +1015,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Az egyéni keresősáv szín nem jelenik meg
   Egyéni keresősáv színe
   A keresősáv színe
-  Érvénytelen színérték. Az alap érték használata.
   
   
   Területi kép-korlátozások megkerülése
diff --git a/src/main/resources/addresources/values-hy-rAM/strings.xml b/src/main/resources/addresources/values-hy-rAM/strings.xml
index a97b42f8b2..89d212bf5d 100644
--- a/src/main/resources/addresources/values-hy-rAM/strings.xml
+++ b/src/main/resources/addresources/values-hy-rAM/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-in-rID/strings.xml b/src/main/resources/addresources/values-in-rID/strings.xml
index 02dcde37bb..df3f8941f4 100644
--- a/src/main/resources/addresources/values-in-rID/strings.xml
+++ b/src/main/resources/addresources/values-in-rID/strings.xml
@@ -141,18 +141,18 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Sembunyikan waktu reaksi
   Waktu reaksi disembunyikan
   Tampilkan Waktu Reaksi
-  Sembunyikan header rak pencarian
-  Sembunyikan Shelf Header
-  Tampilkan Shelf Header
+  Sembunyikan judul rak hasil pencarian
+  Judul rak disembunyikan
+  Judul rak ditampilkan
   Sembunyikan Panduan Saluran
   Panduan saluran disembunyikan
   Panduan saluran ditampilkan
   Sembunyikan rak chip
   Rak opsi deret disembunyikan
   Rak chip ditampilkan
-  Sembunyikan opsi deret di bawah video
-  Opsi deret disembunyikan
-  Chip yang dapat diperluas ditampilkan
+  Sembunyikan kepingan deret di bawah video
+  Kepingan deret disembunyikan
+  Kepingan yang dapat diperluas ditampilkan
   Sembunyikan footer menu kualitas video
   Footer menu kualitas video disembunyikan
   Footer menu kualitas video ditampilkan
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Bagian transkrip sudah ditampilkan
   Keterangan video
   Sembunyi/tampilkan komponen keterangan video
+  
+  Sembunyikan YouTube Doodles
+  Bilah pencarian Doodle disembunyikan
+  Bilah pencarian Doodle ditampilkan
+  YouTube Doodle muncul beberapa hari setiap tahun.\n\nJika Doodle saat ini ditampilkan di wilayah Anda dan pengaturan sembunyikan ini aktif, maka bilah filter di bawah bilah pencarian juga akan disembunyikan.
   Penyaring kustom
   Sembunyikan komponen menggunakan penyaring khusus
   Aktifkan penyaring khusus
@@ -628,14 +633,26 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Label lokasi disembunyikan
   Label lokasi ditampilkan
   Sembunyikan tombol simpan musik
-  Simpan musik disembunyikan
-  Simpan musik ditampilkan
+  Tombol simpan musik disembunyikan
+  Tombol simpan musik ditampilkan
+  Sembunyikan tombol gunakan templat
+  Tombol gunakan templat disembunyikan
+  Tombol gunakan templat ditampilkan
+  Sembunyikan tombol yang akan datang
+  Tombol yang akan datang disembunyikan
+  Tombol yang akan datang ditampilkan
+  Sembunyikan tombol layar hijau
+  Tombol layar hijau disembunyikan
+  Tombol layar hijau ditampilkan
   Sembunyikan saran penelusuran
   Saran penelusuran disembunyikan
   Saran penelusuran ditampilkan
   Sembunyikan stiker
   Stiker disembunyikan
   Stiker ditampilkan
+  Sembunyikan tombol suka yang memancar
+  Animasi tombol suka yang memancar disembunyikan
+  Animasi tombol suka yang memancar ditampilkan
   Sembunyikan tombol suka
   Tombol suka disembunyikan
   Tombol suka ditampilkan
@@ -883,7 +900,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Ubah kategori
   Tidak ada segmen untuk di vote
   Pilih kategori segmen
-  Kategori dinonaktifkan di pengaturan. Aktifkan untuk kirim.
+  Kategori dinonaktifkan di pengaturan. Aktifkan kategori untuk dikirim.
   Segmen SponsorBlock Baru
   Tetapkan %s sebagai awal atau akhir segmen baru?
   awal
@@ -946,20 +963,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Mengembalikan tata letak UI lama
   
   
-  Tetapkan halaman awal
-  Bawaan
-  
-  Beranda
-  Pencarian
-  
-  Langganan
-  Jelajahi
-  
-  Tab Anda
-  Video yang disukai
-  
-  Riwayat
-  Sedang tren
+  Tetapkan halaman awal
+  Bawaan
+  Jelajahi
+  Riwayat
+  Video yang disukai
+  Pencarian
+  Langganan
+  Sedang tren
   
   
   Matikan melanjutkan pemutar video Shorts
@@ -982,9 +993,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
-  Sembunyikan perbesar dan tutup
-  Tombol disembunyikan\n(usap miniplayer untuk membentang/tutup)
-  Tombol bentang dan tutup ditampilkan
+  Sembunyikan perbesar dan tutup
+  Tombol bentang dan tutup ditampilkan
   Sembunyikan subteks
   Subteks disembunyikan
   Subteks ditampilkan
@@ -1006,7 +1016,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Warna bilah pencarian asli ditampilkan
   Warna seekbar kustom
   Warna dari seekbar
-  Nilai warna bilah pencarian tidak sah.
   
   
   Abaikan pembatasan wilayah gambar
@@ -1059,9 +1068,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Jangan tampilkan lagi
   
   
-  Aktifkan ulang-otomatis
-  Ulang-otomatis diaktifkan
-  Ulang-otomatis dinonaktifkan
+  Aktifkan pengulangan otomatis
+  Pengulangan otomatis diaktifkan
+  Pengulangan otomatis dinonaktifkan
   
   
   Palsukan dimensi perangkat
@@ -1204,8 +1213,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Iklan sisi klien
   Iklan surestream di sisi server
   Log awakutu
-  Log awakutu diaktifkan
-  Log awakutu dinonaktifkan
+  Log debug diaktifkan
+  Log debug dinonaktifkan
   
   
 
diff --git a/src/main/resources/addresources/values-is-rIS/strings.xml b/src/main/resources/addresources/values-is-rIS/strings.xml
index d7394f015e..b8bbba97c4 100644
--- a/src/main/resources/addresources/values-is-rIS/strings.xml
+++ b/src/main/resources/addresources/values-is-rIS/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  Sjálfgefinn
   
   
   
diff --git a/src/main/resources/addresources/values-it-rIT/strings.xml b/src/main/resources/addresources/values-it-rIT/strings.xml
index aef26f8b25..0a1628615e 100644
--- a/src/main/resources/addresources/values-it-rIT/strings.xml
+++ b/src/main/resources/addresources/values-it-rIT/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   La sezione della trascrizione è mostrata
   Descrizione video
   Nascondi o mostra i componenti della descrizione video
+  
+  Nascondi Doodles Di YouTube
+  Barra di ricerca Doodles sono nascosti
+  Barra di ricerca Le Doodles sono mostrate
+  YouTube Doodles si presenta un paio di giorni ogni anno.\n\nSe un Doodle è attualmente in mostra nella tua regione e questa impostazione di nascondimento è attiva, poi la barra dei filtri sotto la barra di ricerca sarà anche nascosta.
   Filtro personalizzato
   Nascondi componenti utilizzando filtri personalizzati
   Abilita filtro personalizzato
@@ -628,14 +633,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   L\'etichetta di localizzazione è nascosta
   L\'etichetta di posizione è mostrata
   Nascondi il pulsante per salvare musica
-  Salva musica nascosta
-  Salva musica mostrata
+  Il pulsante Salva musica è nascosto
+  Il pulsante Salva musica è mostrato
+  Nascondi il pulsante modello di utilizzo
+  Il pulsante Usa modello è nascosto
+  Il pulsante Usa modello è mostrato
+  Nascondi il pulsante imminente
+  Il prossimo pulsante è nascosto
+  Prossimo pulsante è mostrato
+  Nascondi pulsante schermo verde
+  Il pulsante dello schermo verde è nascosto
+  Il pulsante schermo verde è mostrato
+  Nascondi pulsante hashtag
+  Il pulsante Hashtag è nascosto
+  Il pulsante Hashtag è mostrato
   Nascondi suggerimenti di ricerca
   I suggerimenti di ricerca sono nascosti
   I suggerimenti di ricerca sono mostrati
   Nascondi adesivi
   Gli adesivi sono nascosti
   Gli adesivi sono mostrati
+  Nascondi come fontana
+  Come l\'animazione della fontana del pulsante è nascosta
+  Come l\'animazione del pulsante fontana è mostrata
   Nascondi pulsante come
   Il pulsante simile è nascosto
   Il pulsante simile è mostrato
@@ -946,20 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Ripristina il vecchio layout UI
   
   
-  Imposta pagina iniziale
-  Predefinito
-  
-  Home
-  Cerca
-  
-  Abbonamenti
-  Esplora
-  
-  È scheda
-  Piaciuti video
-  
-  Storico
-  Tendenze
+  Imposta pagina iniziale
+  Predefinito
+  Sfoglia canali
+  Esplora
+  Gioco
+  Storico
+  Libreria
+  Piaciuti video
+  Live
+  Film
+  Musica
+  Cerca
+  Sport
+  Abbonamenti
+  Tendenze
+  Guarda più tardi
   
   
   Disabilita il ripristino del giocatore Shorts
@@ -982,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderno 1
   Moderno 2
   Moderno 3
-  Nascondi i pulsanti espandi e chiudi
-  I pulsanti sono nascosti\n(fai scorrere il miniplayer per espandere o chiudere)
-  I pulsanti Espandi e chiudi sono visibili
+  Abilita angoli arrotondati
+  Gli angoli sono arrotondati
+  Gli angoli sono quadrati
+  Abilita il doppio tocco e il pizzico per ridimensionare
+  Azione a doppio tocco e pizzico per ridimensionare è abilitato\n\n• Doppio tocco per aumentare la dimensione\n• Doppio tocco per ripristinare la dimensione originale
+  L\'azione a doppio tocco e il pizzico da ridimensionare è disabilitato
+  Abilita drag and drop
+  Drag and drop è abilitato\n\nMiniplayer può essere trascinato in qualsiasi angolo dello schermo
+  Trascinare e rilasciare è disabilitato
+  Nascondi pulsante di chiusura
+  Il pulsante di chiusura è nascosto
+  Il pulsante Chiudi è mostrato
+  Nascondi i pulsanti espandi e chiudi
+  I pulsanti sono nascosti Scorrimento\n\nper espandere o chiudere
+  I pulsanti Espandi e chiudi sono visibili
   Nascondi sottotitoli
   I sottotitoli sono nascosti
   I sottotitoli sono visibili
   Nascondi i pulsanti salta avanti e indietro
   Salta avanti e indietro sono nascosti
   Salta avanti e indietro sono visibili
+  Dimensione iniziale
+  Dimensione iniziale dello schermo, in pixel
+  La dimensione del pixel deve essere compresa tra %1$s e %2$s
   Opacità di sovrapposizione
   Valore di opacità tra 0-100, dove 0 è trasparente
   L\'opacità della sovrapposizione Miniplayer deve essere compresa tra 0-100
@@ -1006,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Il colore originale della barra di ricerca è mostrato
   Colore della barra di ricerca personalizzato
   Il colore della barra di ricerca
-  Valore colore seekbar non valido. Usare il valore predefinito.
+  Valore colore seekbar non valido
   
   
   Bypass restrizioni regione immagine
diff --git a/src/main/resources/addresources/values-iw-rIL/strings.xml b/src/main/resources/addresources/values-iw-rIL/strings.xml
index e7a9ec66ae..f740352bbf 100644
--- a/src/main/resources/addresources/values-iw-rIL/strings.xml
+++ b/src/main/resources/addresources/values-iw-rIL/strings.xml
@@ -59,6 +59,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -240,11 +241,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  ברירת מחדל
-  
-  
-  
-  
+  ברירת מחדל
   
   
   
diff --git a/src/main/resources/addresources/values-ja-rJP/strings.xml b/src/main/resources/addresources/values-ja-rJP/strings.xml
index ccc891ccd4..ef2f99d840 100644
--- a/src/main/resources/addresources/values-ja-rJP/strings.xml
+++ b/src/main/resources/addresources/values-ja-rJP/strings.xml
@@ -229,6 +229,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   文字起こしセクションは表示されます
   概要欄
   概要欄のコンポーネントを非表示または表示
+  
+  YouTubeのDoodlesを隠す
+  検索バーの落書きは非表示です
+  検索バーの落書きが表示されます
+  YouTubeの落書きは毎年数日を表示します。\n\n現在お住まいの地域で落書きが表示されており、この非表示設定がオンの場合。 検索バーの下のフィルターバーも非表示になります。
   カスタムフィルター
   カスタムフィルタを使用してコンポーネントを隠す
   カスタムフィルタを有効にする
@@ -625,14 +630,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   ロケーションラベルは非表示です
   位置情報ラベルが表示されます
   保存ボタンを隠す
-  音楽を非表示にする
-  音楽を保存します。
+  音楽を保存ボタンを非表示にします
+  音楽を保存ボタンが表示されます
+  使用するテンプレートボタンを隠す
+  テンプレートボタンを非表示にする
+  Use template button is showed
+  今後のボタンを隠す
+  今後のボタンは表示されません
+  今後のボタンが表示されます
+  緑色の画面ボタンを隠す
+  緑色の画面ボタンは非表示です
+  緑色の画面ボタンを表示する
+  ハッシュタグボタンを隠す
+  ハッシュタグボタンは非表示です
+  ハッシュタグボタンが表示されます
   検索候補を非表示
   検索候補が非表示になります
   検索候補が表示されます
   ステッカーを隠す
   ステッカーを非表示
   ステッカーを表示
+  噴水のように隠す
+  ボタン噴水のアニメーションが非表示になります
+  ボタン噴水のようなアニメーションが表示されます
   「いいね」ボタンを隠す
   Like button is hidden
   いいねボタンが表示されます
@@ -943,20 +963,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - 古いUIレイアウトを復元
   
   
-  開始ページを設定
-  既定
-  
-  ホーム
-  検索
-  
-  サブスクリプション
-  探索
-  
-  マイページ
-  高評価した動画
-  
-  履歴
-  トレンド
+  開始ページを設定
+  既定
+  チャンネルを参照
+  探索
+  ゲーム
+  履歴
+  ライブラリ
+  高評価した動画
+  ライブ
+  映画
+  音楽
+  検索
+  スポーツ
+  サブスクリプション
+  トレンド
+  後で見る
   
   
   Shorts プレイヤーの再開を無効にする
@@ -979,15 +1001,28 @@ This is because Crowdin requires temporarily flattening this file and removing t
   モダン 1
   モダン 2
   モダン 3
-  展開と閉じるボタンを非表示
-  拡大/縮小のボタンを非表示にします\n(ミニプレーヤーをスワイプして拡大/縮小できます) 
-  展開と閉じる ボタンが表示されます
+  角の丸みを有効にする
+  角が丸くなっています
+  角が正方形です
+  ダブルタップとピンチでサイズ変更を有効にする
+  ダブルタップでピンチでサイズを変更できません
+  ドラッグ&ドロップを有効にする
+  ドラッグ&ドロップが有効です\n\nミニプレーヤーは画面の隅にドラッグできます
+  ドラッグ&ドロップは無効です
+  閉じるボタンを隠す
+  閉じるボタンは非表示です
+  閉じるボタンが表示されます
+  展開と閉じるボタンを非表示
+  展開と閉じる ボタンが表示されます
   サブテキストを非表示
   サブテキストは非表示です
   サブテキストを表示します
   スキップと戻るボタンを隠す
   スキップとバックが非表示になります
   スキップとバックが表示されます
+  初期サイズ
+  最初の画面サイズ(ピクセル)
+  ピクセルサイズは %1$s と %2$sの間でなければなりません
   オーバーレイの不透明度
   透明度の値は 0〜100 の範囲で、0 が透明です
   ミニプレーヤーオーバーレイの不透明度は0-100の間でなければなりません
@@ -1003,7 +1038,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   元のシークバーの色が表示されます
   カスタムシークバーの色
   シークバーの色
-  シークバーの色の値が無効です。デフォルト値を使用してください。
+  無効なシークバーの色の値
   
   
   画像表示の地域制限をバイパスする
diff --git a/src/main/resources/addresources/values-ka-rGE/strings.xml b/src/main/resources/addresources/values-ka-rGE/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-ka-rGE/strings.xml
+++ b/src/main/resources/addresources/values-ka-rGE/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-kk-rKZ/strings.xml b/src/main/resources/addresources/values-kk-rKZ/strings.xml
index 10827c2ae2..942ca5b502 100644
--- a/src/main/resources/addresources/values-kk-rKZ/strings.xml
+++ b/src/main/resources/addresources/values-kk-rKZ/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-km-rKH/strings.xml b/src/main/resources/addresources/values-km-rKH/strings.xml
index 3bc97e7d8f..4ed6c04386 100644
--- a/src/main/resources/addresources/values-km-rKH/strings.xml
+++ b/src/main/resources/addresources/values-km-rKH/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-kn-rIN/strings.xml b/src/main/resources/addresources/values-kn-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-kn-rIN/strings.xml
+++ b/src/main/resources/addresources/values-kn-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-ko-rKR/strings.xml b/src/main/resources/addresources/values-ko-rKR/strings.xml
index e626664438..def0e58229 100644
--- a/src/main/resources/addresources/values-ko-rKR/strings.xml
+++ b/src/main/resources/addresources/values-ko-rKR/strings.xml
@@ -33,10 +33,10 @@ This is because Crowdin requires temporarily flattening this file and removing t
 
   
   
-  확인에 실패함
+  환경 검사에 실패함
   공식 홈페이지 열기
   닫기
-  <h5>이 앱은 사용자가 패치하지 않은 것 같습니다.</h5><br>이 앱은 제대로 작동하지 않을 수 있으며, <b>사용 시 해롭거나 심지어 위험할 수도 있습니다</b>.<br><br>이러한 확인은 이 앱이 사전에 패치되었거나 다른 사람으로부터 받은 것임을 의미합니다:<br><br><small>%1$s</small><br>검증되고 안전한 앱을 사용하고 있는지 확인하려면 <b>이 앱을 제거하고 직접 패치하는 것</b>을 강력히 권장합니다.<p><br>이 경고는 두 번만 표시됩니다.
+  <h5>이 앱은 사용자가 패치하지 않은 것 같습니다.</h5><br>이 앱은 제대로 작동하지 않을 수 있으며, <b>사용 시 해롭거나 심지어 위험할 수도 있습니다</b>.<br><br>이러한 검사는 이 앱이 사전에 패치되었거나 다른 사람으로부터 받은 것임을 의미합니다:<br><br><small>%1$s</small><br>검증되고 안전한 앱을 사용하고 있는지 확인하려면 <b>이 앱을 제거하고 직접 패치하는 것</b>을 강력히 권장합니다.<p><br>이 경고는 두 번만 표시됩니다.
   다른 기기에서 패치됨
   ReVanced Manager에 의해 설치되지 않음
   10분 이상 전에 패치됨
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   스크립트 섹션이 표시됩니다
   동영상 설명
   동영상 설명에서 구성요소를 숨기거나 표시할 수 있습니다
+  
+  YouTube Doodles 숨기기
+  YouTube Doodles가 숨겨집니다\n• 이벤트성 YouTube 헤더
+  YouTube Doodles가 표시됩니다\n• 이벤트성 YouTube 헤더
+  YouTube Doodles는 공휴일이나 기념일 등, 그날에 맞춘 디자인으로 변경되는 왼쪽 상단의 YouTube 헤더를 말합니다\n\n현재 거주하는 지역에서 YouTube Doodles가 표시되어 있는데 이 설정이 활성화되어 있는 경우에는 검색창 아래에 표시되는 카테고리 바도 숨겨집니다
   사용자 정의 필터
   사용자 정의 필터를 사용하여 구성요소를 숨길 수 있습니다
   사용자 정의 필터 활성화하기
@@ -241,7 +246,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   필터링할 컴포넌트 패스 빌더 문자열을 줄바꿈으로 구분하여 설정합니다\n• 컴포넌트 패스 빌더 문자열은 숨겨질 레이아웃 구성요소를 식별하는 기술적인 이름입니다
   잘못된 사용자 정의 필터 값입니다: %s
   키워드 필터링
-  키워드 필터를 사용하여 검색 결과와 피드에서 동영상을 숨길 수 있습니다
+  키워드 필터를 사용하여 검색 결과 및 피드에서 동영상을 숨길 수 있습니다
   홈 탭에서 키워드 필터 활성화하기
   홈 탭에서 키워드 필터를 활성화합니다
   홈 탭에서 키워드 필터를 비활성화합니다
@@ -628,15 +633,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   위치 라벨 숨기기
   위치 라벨이 숨겨집니다
   위치 라벨이 표시됩니다
-  음악 저장 버튼 숨기기
-  음악 저장 버튼이 숨겨집니다
-  음악 저장 버튼이 표시됩니다
+  (재생목록에) 음악 저장 버튼 숨기기
+  (재생목록에) 음악 저장 버튼이 숨겨집니다
+  (재생목록에) 음악 저장 버튼이 표시됩니다
+  탬플릿 사용 버튼 숨기기
+  탬플릿 사용 버튼이 숨겨집니다
+  탬플릿 사용 버튼이 표시됩니다
+  예정 버튼 숨기기
+  (Premiere 또는 실시간) 예정 버튼이 숨겨집니다
+  (Premiere 또는 실시간) 예정 버튼이 표시됩니다
+  그린 스크린 버튼 숨기기
+  그린 스크린 버튼이 숨겨집니다
+  그린 스크린 버튼이 표시됩니다
   검색 추천 숨기기
   검색 추천이 숨겨집니다
   검색 추천이 표시됩니다
   스티커 숨기기
   스티커가 숨겨집니다
   스티커가 표시됩니다
+  좋아요 상단 애니메이션 비활성화하기
+  좋아요 버튼 상단에 표시되는 애니메이션을 비활성화합니다
+  좋아요 버튼 상단에 표시되는 애니메이션을 활성화합니다
   좋아요 버튼 숨기기
   좋아요 버튼이 숨겨집니다
   좋아요 버튼이 표시됩니다
@@ -942,26 +959,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   18.33.40 - 시크릿 모드에서 Shorts RYD를 복원합니다
   18.20.39 - 넓은 동영상 재생 속도 & 화질 메뉴를 복원합니다
-  16.09.39 - 이전 보관함 탭을 복원합니다 (나 탭을 비활성화합니다)
+  16.09.39 - 이전 보관함 탭을 복원합니다 (내 페이지 탭을 비활성화합니다)
   17.41.37 - 이전 재생목록 선반으로 복원합니다
   17.33.42 - 이전 레이아웃으로 복원합니다
   
   
-  앱 시작 페이지 변경하기
-  기본값
-  
-  
-  검색
-  
-  구독
-  탐색
-  Shorts
-  
-  내 페이지
-  좋아요 표시한 동영상
-  
-  기록
-  인기 급상승
+  앱 시작 페이지 변경하기
+  SponsorBlock 활성화
+  플레이어에서 구간 투표 버튼을 표시합니다
+  일반적인 건너뛰기 버튼을 표시합니다
+  나 (보관함)
+  최소화된 건너뛰기 버튼을 표시합니다
+  외관
+  투표 버튼 표시하기
+  자동으로 건너뛰기 버튼 숨기기
   
   
   앱을 시작할 때, Shorts 플레이어 비활성화하기
@@ -977,16 +988,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   미니 플레이어
   앱 내에서 최소화된 플레이어의 스타일을 변경할 수 있습니다
-  미니 플레이어 타입 설정
+  미니 플레이어 유형 설정
   기기 기본값 사용
   
   태블릿
   최신 스타일 1
   최신 스타일 2
   최신 스타일 3
-  \'펼치기\' & \'닫기\' 버튼 숨기기
-  \'펼치기\' & \'닫기\' 버튼이 숨겨집니다\n• 스와이프하여 미니 플레이어를 펼치거나 닫을 수 있습니다
-  \'펼치기\' & \'닫기\' 버튼이 표시됩니다
+  \'펼치기\' & \'닫기\' 버튼 숨기기
+  \'펼치기\' & \'닫기\' 버튼이 표시됩니다
   서브텍스트 숨기기
   서브텍스트가 숨겨집니다\n• 왼쪽 하단에서 표시되는 \'유료 광고 포함\'과 같은 라벨
   서브텍스트가 표시됩니다\n• 왼쪽 하단에서 표시되는 \'유료 광고 포함\'과 같은 라벨
@@ -1008,7 +1018,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   기본 재생바 색상을 활성화합니다
   사용자 정의 재생바 색상 설정
   재생바 색상
-  잘못된 재생바 색상 값이므로 기본값으로 초기화합니다
   
   
   이미지 표시 제한 국가 우회하기
diff --git a/src/main/resources/addresources/values-ky-rKG/strings.xml b/src/main/resources/addresources/values-ky-rKG/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-ky-rKG/strings.xml
+++ b/src/main/resources/addresources/values-ky-rKG/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-lo-rLA/strings.xml b/src/main/resources/addresources/values-lo-rLA/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-lo-rLA/strings.xml
+++ b/src/main/resources/addresources/values-lo-rLA/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-lt-rLT/strings.xml b/src/main/resources/addresources/values-lt-rLT/strings.xml
index 94586827b0..413b708cb8 100644
--- a/src/main/resources/addresources/values-lt-rLT/strings.xml
+++ b/src/main/resources/addresources/values-lt-rLT/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  Numatyti
   
   
   
diff --git a/src/main/resources/addresources/values-lv-rLV/strings.xml b/src/main/resources/addresources/values-lv-rLV/strings.xml
index 5f69c090c0..d3f8eb875f 100644
--- a/src/main/resources/addresources/values-lv-rLV/strings.xml
+++ b/src/main/resources/addresources/values-lv-rLV/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  Parasts
   
   
   
diff --git a/src/main/resources/addresources/values-mk-rMK/strings.xml b/src/main/resources/addresources/values-mk-rMK/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-mk-rMK/strings.xml
+++ b/src/main/resources/addresources/values-mk-rMK/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-ml-rIN/strings.xml b/src/main/resources/addresources/values-ml-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-ml-rIN/strings.xml
+++ b/src/main/resources/addresources/values-ml-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-mn-rMN/strings.xml b/src/main/resources/addresources/values-mn-rMN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-mn-rMN/strings.xml
+++ b/src/main/resources/addresources/values-mn-rMN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-mr-rIN/strings.xml b/src/main/resources/addresources/values-mr-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-mr-rIN/strings.xml
+++ b/src/main/resources/addresources/values-mr-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-ms-rMY/strings.xml b/src/main/resources/addresources/values-ms-rMY/strings.xml
index 675080765a..66dc6696bb 100644
--- a/src/main/resources/addresources/values-ms-rMY/strings.xml
+++ b/src/main/resources/addresources/values-ms-rMY/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-my-rMM/strings.xml b/src/main/resources/addresources/values-my-rMM/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-my-rMM/strings.xml
+++ b/src/main/resources/addresources/values-my-rMM/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-nb-rNO/strings.xml b/src/main/resources/addresources/values-nb-rNO/strings.xml
index 8a78084a09..a31f921319 100644
--- a/src/main/resources/addresources/values-nb-rNO/strings.xml
+++ b/src/main/resources/addresources/values-nb-rNO/strings.xml
@@ -227,6 +227,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Transskripsjonsseksjonen vises
   Beskrivelse av videoen
   Skjul eller vis video-beskrivelse komponenter
+  
+  Skjul YouTube dører
+  Søk i barnerøvinger er skjult
+  Søk i barnetjener vises
+  YouTube Doodles dukker opp noen dager hvert år.\n\nHvis en Doodle viser for øyeblikket i ditt fylke, og denne skjul-innstillingen er på deretter vil filterlinjen under søkefeltet også bli skjult.
   Egne filtre
   Skjul komponenter ved hjelp av tilpassede filtre
   Aktiver tilpasset filter
@@ -624,14 +629,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Posisjonsetiketten er skjult
   Posisjonsetikett vises
   Skjul \"Lagre musikk\"-knapp
-  Lagre musikk er skjult
-  Lagre musikk vises
+  Lagre-knappen er skjult
+  Lagre musikkknapp vises
+  Skjul knapp for bruk av mal
+  Bruk malknappen er skjult
+  Bruk malknapp er vist
+  Skjul kommende knapp
+  Kommende knapp er skjult
+  Kommende knapp er vist
+  Skjul grønn skjermknapp
+  Grønn skjermknapp er skjult
+  Grønn skjermknapp vises
+  Skjul hashtag knapp
+  Hashtag knappen er skjult
+  Hashtag knappen er vist
   Skjul søkeforslag
   Søkeforslag er skjult
   Søk forslag vises
   Skjul klistremerker
   Klistremerker er skjult
   Klistremerker vises
+  Skjul som kilde
+  Lik knappens kildeanimasjon er skjult
+  Lik knappens animasjon vises
   Skjul som knappen
   Lik knappen er skjult
   Liker-knappen vises
@@ -934,20 +954,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Gjenopprett gammelt UI oppsett
   
   
-  Angi startside
-  Standard
-  
-  Hjem
-  Søk
-  
-  Abonnementer
-  Utforsk
-  
-  Du har fane
-  Likte videoer
-  
-  Historikk
-  Populært
+  Angi startside
+  Standard
+  Bla gjennom kanaler
+  Utforsk
+  Spilling
+  Historikk
+  Bibliotek
+  Likte videoer
+  Direkte
+  Filmer
+  Musikk
+  Søk
+  Sport
+  Abonnementer
+  Populært
+  Se senere
   
   
   Deaktiver gjenopptakelse av Shorts spiller
@@ -970,15 +992,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderne 1
   Moderne 2
   Moderne 3
-  Skjul utvid og lukk-knapper
-  Knapper er skjult\n(sveip miniplayer for å utvide eller lukke)
-  Utvid og lukk knapper vises
+  Aktiver avrundede hjørner
+  Hjørnene er avrundet
+  Hjørnene er firkantede
+  Aktiver dobbeltrykk og knip for å endre størrelse
+  Dobbelttrykk handling og klemme for å endre størrelse er deaktivert
+  Aktiver dra og slipp
+  Dra og slipp er aktivert\n\nHjelperavspiller kan flyttes til et hvilken som helst hjørne av skjermen
+  Dra og slipp er deaktivert
+  Skjul lukkeknapp
+  Lukk-knappen er skjult
+  Lukk-knappen vises
+  Skjul utvid og lukk-knapper
+  Knappene er gjemte\n\nSveip for å utvide eller lukke
+  Utvid og lukk knapper vises
   Skjul undertekster
   Undertekster er skjult
   Undertekster er vist
   Skjul hopp forover og tilbake knapper
   Hopp over og tilbake er skjult
   Hopp over og tilbake vises
+  Innledende størrelse
+  Opprinnelig størrelse på skjermen i piksler
+  Pikselstørrelse må være mellom %1$s og %2$s
   Gjennomsiktighet mellom 0-100, der 0 er gjennomsiktig
   Minispiller overlegg opasitet må være mellom 0-100
   
@@ -993,7 +1029,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Opprinnelig søkelinjens farge vises
   Egendefinert søkelinjefarge
   Farge på søkefeltet
-  Ugyldig farge på søkelinjen. Bruker standardverdien.
+  Ugyldig søkelinjens fargeverdi
   
   
   Forbigå bilde-restriksjoner
diff --git a/src/main/resources/addresources/values-ne-rIN/strings.xml b/src/main/resources/addresources/values-ne-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-ne-rIN/strings.xml
+++ b/src/main/resources/addresources/values-ne-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-nl-rNL/strings.xml b/src/main/resources/addresources/values-nl-rNL/strings.xml
index 7d9f7b00b4..a051e09430 100644
--- a/src/main/resources/addresources/values-nl-rNL/strings.xml
+++ b/src/main/resources/addresources/values-nl-rNL/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Transcriptsectie wordt weergegeven
   Video beschrijving
   Verberg of toon video beschrijving componenten
+  
+  Youtube Doodles verbergen
+  Zoekbalk Doodsen zijn verborgen
+  Zoekbalk Doodles worden weergegeven
+  YouTube Doodles verschijnen een paar dagen per jaar.\n\nAls een Doodle momenteel zichtbaar is in jouw regio en deze instelling is ingeschakeld dan wordt de filterbalk onder de zoekbalk ook verborgen.
   Aangepast filter
   Componenten met aangepaste filters verbergen
   Aangepaste filter inschakelen
@@ -629,14 +634,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Locatie label is verborgen
   Locatie label wordt weergegeven
   Verberg bewaar muziek knop
-  Muziek opslaan is verborgen
-  Muziek opslaan wordt weergegeven
+  Muziekknop opslaan is verborgen
+  Muziekknop wordt weergegeven
+  Verberg gebruik sjabloonknop
+  Gebruik sjabloonknop is verborgen
+  Gebruik sjabloonknop wordt weergegeven
+  Aankomende knop verbergen
+  Aankomende knop is verborgen
+  Aankomende knop wordt weergegeven
+  Verberg groene schermknop
+  Groene schermknop is verborgen
+  Groene schermknop wordt weergegeven
+  hashtag knop verbergen
+  Hashtag knop is verborgen
+  Hashtag knop wordt weergegeven
   Zoeksuggesties verbergen
   Zoeksuggesties zijn verborgen
   Zoeksuggesties worden getoond
   Verberg stickers
   Stickers zijn verborgen
   Stickers worden getoond
+  Verbergen als fontein
+  Like knop fontein animatie is verborgen
+  De vind-ik-leuk-knop animatie wordt weergegeven
   Verberg leuk-knop
   Vind-ik-leuk-knop is verborgen
   Vind-ik-leuk-knop wordt weergegeven
@@ -947,20 +967,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Herstel oude UI lay-out
   
   
-  Startpagina instellen
-  Standaard
-  
-  Startpagina
-  Zoeken
-  
-  Abonnementen
-  Verken
-  
-  Uw tabblad
-  Video\'s leuk vinden
-  
-  Geschiedenis
-  Populair
+  Startpagina instellen
+  Standaard
+  Kanalen doorzoeken
+  Verken
+  Gaming
+  Geschiedenis
+  Bibliotheek
+  Video\'s leuk vinden
+  Zichtbaar
+  Films
+  Muziek
+  Zoeken
+  Sport
+  Abonnementen
+  Populair
+  Later bekijken
   
   
   Schakel het hervatten van Shorts-speler uit
@@ -983,15 +1005,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderne 1
   Moderne 2
   Moderne 3
-  Verberg knoppen voor uitvouwen en sluiten
-  Knoppen zijn verborgen\n(swipe miniplayer om uit te breiden of te sluiten)
-  Uitvouwen en sluiten knoppen worden weergegeven
+  Schakel afgeronde hoeken in
+  Hoeken zijn afgerond
+  Hoeken zijn vierkant
+  Dubbeltikken en knijpen om formaat aan te passen inschakelen
+  Dubbeltikken op actie en knijp om de grootte te wijzigen is ingeschakeld\n\n• Dubbel tikken om de miniplayer grootte te verhogen\n• Dubbel tikken om de originele grootte te herstellen
+  Dubbeltikken op actie en knijpen om formaat aan te passen is uitgeschakeld
+  Schakel slepen en neerzetten in
+  Slepen en neerzetten is ingeschakeld\n\nMiniplayer kan naar elke hoek van het scherm worden gesleept
+  Slepen en neerzetten is uitgeschakeld
+  Verberg sluit knop
+  Sluitknop is verborgen
+  Sluitknop wordt weergegeven
+  Verberg knoppen voor uitvouwen en sluiten
+  Knoppen zijn verborgen\n\nVeeg om uit te breiden of te sluiten
+  Uitvouwen en sluiten knoppen worden weergegeven
   Verberg subteksten
   Subteksten zijn verborgen
   Subteksten worden getoond
   Voor- en achterkant knoppen verbergen
   Vooruit en achterkant zijn verborgen
   Spring vooruit en achterkant worden weergegeven
+  Initiële grootte
+  Initiële grootte van het scherm, in pixels
+  Pixel grootte moet liggen tussen %1$s en %2$s
   Dekking van de overlay
   Transparantiewaarde tussen 0-100, waarbij 0 transparant is
   Minispeler overlay transparantie moet tussen de 0-100 zijn
@@ -1007,7 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Oorspronkelijke Zoekbalk kleur wordt weergegeven
   Aangepaste zoekbalk kleur
   De kleur van de zoekbalk
-  Ongeldige zoekbalk kleurwaarde. Standaardwaarde wordt gebruikt.
+  Ongeldige zoekbalk kleurwaarde
   
   
   Bypass afbeelding regio beperkingen
diff --git a/src/main/resources/addresources/values-or-rIN/strings.xml b/src/main/resources/addresources/values-or-rIN/strings.xml
index e8f1b1cb54..73e81d15b1 100644
--- a/src/main/resources/addresources/values-or-rIN/strings.xml
+++ b/src/main/resources/addresources/values-or-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  ଡିଫଲ୍ଟ
   
   
   
diff --git a/src/main/resources/addresources/values-pa-rIN/strings.xml b/src/main/resources/addresources/values-pa-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-pa-rIN/strings.xml
+++ b/src/main/resources/addresources/values-pa-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-pl-rPL/strings.xml b/src/main/resources/addresources/values-pl-rPL/strings.xml
index 4c78ead611..bb46bac4dc 100644
--- a/src/main/resources/addresources/values-pl-rPL/strings.xml
+++ b/src/main/resources/addresources/values-pl-rPL/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Sekcja transkryptu jest wyświetlana
   Opis wideo
   Ukryj lub pokaż elementy opisu wideo
+  
+  Ukryj Doodles YouTube
+  Pasek wyszukiwania jest ukryty
+  Pasek wyszukiwania jest wyświetlany
+  Doodles YouTube pojawia się co roku kilka dni.\n\nJeśli Doodle wyświetla się w Twoim regionie, a to ustawienie ukrycia jest włączone, następnie pasek filtru poniżej paska wyszukiwania będzie również ukryty.
   Własny filtr
   Ukryj komponenty za pomocą niestandardowych filtrów
   Włącz własny filtr
@@ -629,14 +634,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Etykieta lokalizacji jest ukryta
   Etykieta lokalizacji jest wyświetlana
   Ukryj przycisk zapisu muzyki
-  Zapisz muzykę ukrytą
-  Zapisz muzykę
+  Przycisk zapisu muzyki jest ukryty
+  Przycisk zapisu muzyki jest pokazany
+  Ukryj przycisk użyj szablonu
+  Przycisk \"Użyj szablonu\" jest ukryty
+  Przycisk szablonu jest pokazany
+  Ukryj nadchodzący przycisk
+  Przychodzący przycisk jest ukryty
+  Przychodzący przycisk jest pokazany
+  Ukryj zielony przycisk ekranu
+  Przycisk zielonego ekranu jest ukryty
+  Przycisk zielonego ekranu jest pokazany
+  Ukryj przycisk hasztaga
+  Przycisk Hashtag jest ukryty
+  Przycisk Hashtag jest pokazany
   Ukryj sugestie wyszukiwania
   Sugestie wyszukiwania są ukryte
   Sugestie wyszukiwania są wyświetlane
   Ukryj naklejki
   Naklejki są ukryte
   Naklejki są wyświetlane
+  Ukryj jak Fontanna
+  Animacja tworzenia przycisków polubienia jest ukryta
+  Pokazana jest animacja przycisku założycielskiego
   Ukryj przycisk polubień
   Przycisk polubienia jest ukryty
   Przycisk polubienia jest pokazany
@@ -698,7 +718,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
+  Łapki w dół są tymczasowo niedostępne (API nie reaguje)
   Brak polubień (status %d)
   Łapki w dół nie są dostępne (limit API użytkownika)
   Brak polubień (%s)
@@ -737,7 +757,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   %d połączenia sieciowe przekroczyły limit czasu
   Limity prędkości klienta API
   Nie napotkano limitów cenowych klienta
-  
   %d milisekund
   
   
@@ -947,21 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Przywróć stary układ interfejsu użytkownika
   
   
-  Ustaw stronę startową
-  Domyślnie
-  
-  Strona główna
-  Szukaj
-  
-  Subskrypcje
-  Przeglądaj
-  Spodnie
-  
-  Zakładka
-  Polubione filmy
-  
-  Historia
-  Popularne
+  Ustaw stronę startową
+  Domyślnie
+  Przeglądaj kanały
+  Przeglądaj
+  Gra
+  Historia
+  Biblioteka
+  Polubione filmy
+  Żywe
+  Filmy
+  Muzyka
+  Szukaj
+  Sport
+  Subskrypcje
+  Popularne
+  Obserwuj później
   
   
   Wyłącz wznawianie odtwarzacza Shorts
@@ -984,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Nowoczesny 1
   Nowoczesny 2
   Nowoczesny 3
-  Ukryj przyciski rozwijające i zamykające
-  Przyciski są ukryte\n(przesuń minigracza aby rozwinąć lub zamknąć)
-  Wyświetlane są przyciski rozwijane i zamykane
+  Włącz zaokrąglone narożniki
+  Narożniki są zaokrąglone
+  Narożniki są kwadratowe
+  Włącz dwukrotne dotknięcie i przypnij aby zmienić rozmiar
+  Akcja dwukrotnego dotknięcia i przypinanie aby zmienić rozmiar jest włączone\n\n• Dwukrotnie stuknij, aby zwiększyć rozmiar minigracza\n• Dwukrotnie stuknij ponownie, aby przywrócić oryginalny rozmiar
+  Akcja dwukrotnego dotknięcia i przypinanie aby zmienić rozmiar jest wyłączona
+  Włącz przeciągnij i upuść
+  Przeciągnij i upuść jest włączone\n\nMiniplayer może być przeciągnięty do dowolnego rogu ekranu
+  Przeciągnij i upuść jest wyłączona
+  Ukryj przycisk zamykania
+  Przycisk zamykający jest ukryty
+  Przycisk zamykający jest pokazany
+  Ukryj przyciski rozwijające i zamykające
+  Przyciski są ukryte\n\nPrzesuń, aby rozwinąć lub zamknąć
+  Wyświetlane są przyciski rozwijane i zamykane
   Ukryj napisy
   Podteksty są ukryte
   Podteksty są wyświetlane
   Ukryj przyciski przeskakujące do przodu i do tyłu
   Pomiń do przodu i z powrotem są ukryte
   Pomiń do przodu i do tyłu są wyświetlane
+  Rozmiar początkowy
+  Początkowy rozmiar ekranu, w pikselach
+  Rozmiar piksela musi być pomiędzy %1$s i %2$s
   Przezroczystość nakładki
   Wartość przezroczystości między 0-100, gdzie 0 jest przezroczysty
   Przezroczystość nakładki musi być pomiędzy 0-100
@@ -1008,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Oryginalny kolor paska nawigacji jest wyświetlany
   Niestandardowy kolor paska podglądu
   Kolor paska wyszukiwania
-  Nieprawidłowa wartość koloru paska szukania. Używana wartość domyślna.
+  Nieprawidłowa wartość koloru paska wyszukiwania
   
   
   Pomiń ograniczenia regionu obrazu
diff --git a/src/main/resources/addresources/values-pt-rBR/strings.xml b/src/main/resources/addresources/values-pt-rBR/strings.xml
index fa745219be..9d2eabc19b 100644
--- a/src/main/resources/addresources/values-pt-rBR/strings.xml
+++ b/src/main/resources/addresources/values-pt-rBR/strings.xml
@@ -231,6 +231,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Seção de transcrição não está oculta
   Descrição do vídeo
   Ocultar ou mostrar componentes de descrição do vídeo
+  
   Filtro personalizado
   Ocultar componentes usando filtros personalizados
   Ativar filtro personalizado
@@ -259,7 +260,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Home/Assinatura/Busca Resultados são filtrados para ocultar conteúdo que corresponde às palavras chaves\n\nLimitações\n• Shorts não podem ser ocultados pelo nome do canal\n• Alguns componentes do UI podem não ser ocultados\n• Procurar por uma palavra-chave pode não mostrar Resultados
   Corresponder palavras inteiras
   
-  Colocar uma palavra-chave/frase entre aspas duplas impedirá correspondências parciais de títulos de vídeos e nomes de canais<br><br>Por exemplo,<br><b>\"ia\"</b> ocultará o vídeo: <b>Como funciona a IA?</b><br>mas não ocultará: <b>Como detectar fraudes por e-mail?</b>
+  Colocar uma palavra-chave/frase entre aspas duplas impedirá correspondências parciais de títulos de vídeos e nomes de canais<br><br>Por exemplo,<br><b>\"ia\"</b> ocultará o vídeo: <b>Como funciona a IA?</b><br>mas não ocultará: <b>Como criar um canal do zero?</b>
   
   Impossível usar a palavra-chave: %s
   Adicionar aspas para usar a palavra-chave: %s
@@ -629,14 +630,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Rótulo de localização está oculto
   Rótulo de localização é mostrado
   Ocultar o botão de salvar música
-  Salvar música está oculto
-  Salvar música está visível
   Ocultar sugestões de busca
   Sugestões de pesquisa estão ocultas
   Sugestões de pesquisa são mostradas
   Ocultar adesivos
   Adesivos estão ocultos
   Adesivos estão visíveis
+  Ocultar botão curtir
+  Como a animação da fonte do botão está oculta
+  Como a animação da fonte do botão é mostrada
   Ocultar botão gostei
   Botão gostei está oculto
   Botão gostei não está oculto
@@ -947,21 +949,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Restaurar layout antigo da interface
   
   
-  Definir página inicial
-  Padrão
-  
-  Início
-  Procurar
-  
-  Inscrições
-  Explorar
-  Shorts
-  
-  Você
-  Videos curtidos
-  
-  Histórico
-  Em alta
+  Definir página inicial
+  Padrão
+  Explorar
+  Histórico
+  Videos curtidos
+  Procurar
+  Inscrições
+  Em alta
   
   
   Desativar continuar a reproduzir Shorts
@@ -984,9 +979,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderno 1
   Moderno 2
   Moderno 3
-  Ocultar botões de expansão e fechamento
-  Os botões estão ocultos\n(deslize o miniplayer para expandir ou fechar)
-  Botões de expansão e fechamento são mostrados
   Ocultar subtextos
   Subtextos estão ocultos
   Subtextos são exibidos
@@ -995,7 +987,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Pular para frente e para trás são mostrados
   Opacidade de sobreposição
   Valor de opacidade entre 0-100, onde 0 é transparente
-  Opacidade da sobreposição de minijogador deve estar entre 0-100
+  Opacidade da sobreposição de miniplayer deve estar entre 0-100
   
   
   Ativar tela de carregamento em gradiente
@@ -1008,7 +1000,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Mostrar cor original da barra de busca
   Cor personalizada da barra de busca
   Cor da barra de busca
-  Valor de cor inválido da barra. Usando o valor padrão.
+  Valor de cor da barra de busca inválido
   
   
   Ignorar restrições de região de imagem
diff --git a/src/main/resources/addresources/values-pt-rPT/strings.xml b/src/main/resources/addresources/values-pt-rPT/strings.xml
index 95c9a5b596..f19aefbf9b 100644
--- a/src/main/resources/addresources/values-pt-rPT/strings.xml
+++ b/src/main/resources/addresources/values-pt-rPT/strings.xml
@@ -229,6 +229,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Secção de transcrição exibida
   Descrição do vídeo
   Esconder ou mostrar componentes de descrição do vídeo
+  
+  Ocultar Doodles do YouTube
+  Doodles da barra de pesquisa estão escondidos
+  Doodles são mostrados na barra de pesquisa
+  O YouTube Doodles aparece alguns dias todos os anos.\n\nSe um Doodle está atualmente sendo exibido na sua região e esta configuração de ocultar está ativada, então a barra de filtro abaixo da barra de pesquisa também será ocultada.
   Filtro personalizado
   Esconder componentes usando filtros personalizados
   Ativar filtro personalizado
@@ -626,14 +631,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Rótulo de localização está oculto
   Rótulo de localização é mostrado
   Ocultar botão salvar música
-  Salvar música está oculta
-  Salvar música é mostrado
+  O botão salvar música está oculto
+  O botão salvar música é mostrado
+  Ocultar usar o botão do modelo
+  Usar o botão modelo está oculto
+  Usar botão do modelo é mostrado
+  Esconder o botão do próximo
+  O botão \"vir\" está oculto
+  O próximo botão será exibido
+  Ocultar botão de tela verde
+  O botão de tela verde está oculto
+  Botão de tela verde é mostrado
+  Ocultar botão de hashtag
+  O botão Hashtag está oculto
+  Botão Hashtag é mostrado
   Ocultar sugestões de busca
   Sugestões de pesquisa estão ocultas
   Sugestões de pesquisa são mostradas
   Ocultar stickers
   Adesivos estão ocultos
   Stickers são mostrados
+  Ocultar como a fonte
+  A animação da fonte do botão curtir está oculta
+  Animação de botão fonte é mostrada
   Esconder botão \"curtir\"
   O botão curtir está escondido
   O botão curtir está visível
@@ -944,20 +964,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Restaurar layout de interface antiga
   
   
-  Definir página inicial
-  Padrão
-  
-  Residencial
-  Pesquisa
-  
-  Inscrições
-  Explorar
-  
-  Aba você
-  Vídeos curtidos
-  
-  Histórico
-  Tendências
+  Definir página inicial
+  Padrão
+  Procurar canais
+  Explorar
+  Jogos
+  Histórico
+  Biblioteca
+  Vídeos curtidos
+  Publicado
+  Filmes
+  Música
+  Pesquisa
+  Esportes
+  Inscrições
+  Tendências
+  Assistir depois
   
   
   Desativar modo retomada do player
@@ -980,15 +1002,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderno 1
   Moderno 2
   Moderno 3
-  Ocultar botões de expansão e fechamento
-  Os botões são ocultos\n(swipe miniplayer para expandir ou fechar)
-  Botões de expansão e fechamento são mostrados
+  Ativar cantos arredondados
+  Bordas são arredondadas
+  Os cantos estão quadrados
+  Ativar toque duplo e pinch para redimensionar
+  Ação toque duplo e aperte para redimensionar está ativado\n\n• Toque duas vezes para aumentar o tamanho do miniplayer\n• Toque duas vezes novamente para restaurar o tamanho original
+  Ação de toque duplo e pinçar para redimensionar está desativado
+  Ativar arrastar e soltar
+  Arrastar e soltar é habilitado\n\nMiniplayer pode ser arrastado para qualquer canto da tela
+  Arrastar e soltar está desativado
+  Ocultar botão fechar
+  O botão fechar está oculto
+  Botão fechar é mostrado
+  Ocultar botões de expansão e fechamento
+  Botões são ocultos\n\nDeslize para expandir ou fechar
+  Botões de expansão e fechamento são mostrados
   Ocultar subtextos
   Subtextos estão ocultos
   Subtextos são exibidos
   Ocultar botões pular para frente e para trás
   Pular para frente e para trás estão escondidos
   Pular para frente e para trás são mostrados
+  Tamanho inicial
+  Inicial sobre o tamanho da tela, em pixels
+  O tamanho do pixel deve estar entre %1$s e %2$s
   Opacidade da sobreposição
   Valor de opacidade entre 0-100, onde 0 é transparente
   Opacidade da sobreposição de minijogador deve estar entre 0-100
@@ -1004,7 +1041,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Cor original da barra de busca é visível
   Cor personalizada da barra de busca
   A cor da barra de busca
-  Valor de cor inválido da barra. Usando o valor padrão.
+  Valor de cor de seekbar inválido
   
   
   Ignorar restrições de região de imagem
diff --git a/src/main/resources/addresources/values-ro-rRO/strings.xml b/src/main/resources/addresources/values-ro-rRO/strings.xml
index 54158b2af7..8283c58e24 100644
--- a/src/main/resources/addresources/values-ro-rRO/strings.xml
+++ b/src/main/resources/addresources/values-ro-rRO/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Secțiunea de Transcriere este afișată
   Descriere video
   Ascunde sau afișează componentele descrierii video
+  
+  Ascunde Doodle-urile YouTube
+  Doodles bară de căutare sunt ascunse
+  Doodles bară de căutare sunt afișate
+  Doodurile YouTube apar câteva zile în fiecare an.\n\nDacă un Doodle se afișează în regiunea ta și această setare de ascensiune este activată, apoi bara de filtre de sub bara de căutare va fi, de asemenea, ascunsă.
   Filtru personalizat
   Ascunde componentele folosind filtre personalizate
   Activează filtru personalizat
@@ -628,14 +633,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Eticheta locației este ascunsă
   Eticheta locației este afișată
   Ascunde butonul de salvare a muzicii
-  Salvarea muzicii este ascunsă
-  Salvarea muzicii este afișată
+  Butonul de salvare a muzicii este ascuns
+  Butonul de salvare a muzicii este afișat
+  Ascunde butonul de utilizare șablon
+  Butonul şablon este ascuns
+  Butonul șablon este afișat
+  Ascunde butonul următor
+  Butonul următor este ascuns
+  Următorul buton este afișat
+  Ascunde butonul verde de ecran
+  Butonul de ecran verde este ascuns
+  Butonul de ecran verde este afișat
+  Ascunde butonul hashtag
+  Butonul Hashtag este ascuns
+  Butonul Hashtag este afișat
   Ascunde sugestiile de căutare
   Sugestiile de căutare sunt ascunse
   Sugestiile de căutare sunt afișate
   Ascunde autocolante
   Stickerele sunt ascunse
   Stickerele sunt afișate
+  Ascunde fântâna
+  Animaţia fântânii butoanelor este ascunsă
+  Animația fântânii butoanelor este afișată
   Ascunde butonul similar
   Butonul Like este ascuns
   Butonul Like este afișat
@@ -946,21 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Restaurați aspectul vechi al interfeței
   
   
-  Setaţi pagina de start
-  Implicit
-  
-  Acasă
-  Caută
-  
-  Abonamente
-  Explorați
-  Scurtături
-  
-  Fila ta
-  Videoclipuri apreciate
-  
-  Istoric
-  Populare
+  Setaţi pagina de start
+  Implicit
+  Navigare canale
+  Explorați
+  Joc
+  Istoric
+  Bibliotecă
+  Videoclipuri apreciate
+  Live
+  Filme
+  Muzică
+  Caută
+  Sport
+  Abonamente
+  Populare
+  Urmărește mai târziu
   
   
   Dezactivează reluarea Jucător de scurtături
@@ -983,15 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
-  Ascunde extinderea și închiderea butoanelor
-  Butoanele sunt ascunse\n(glisați miniplayer pentru a extinde sau închide)
-  Afișarea și închiderea butoanelor sunt afișate
+  Activează colțurile rotunjite
+  Colţurile sunt rotunjite
+  Colţurile sunt pătrate
+  Activează dublu-click și prinde pentru a redimensiona
+  Acțiune cu dublă apăsare și redimensionare este activată\n\n• Apasă de două ori pentru a mări dimensiunea miniplayerului\n• Apasă de două ori din nou pentru a restaura dimensiunea originală
+  Atingeți de două ori și redimensionarea este dezactivată
+  Activează drag and drop
+  Drag and drop este activat\n\nMiniplayer poate fi mutat în orice colț al ecranului
+  Drag and drop este dezactivat
+  Ascunde butonul de închidere
+  Butonul de închidere este ascuns
+  Butonul de închidere este afișat
+  Ascunde extinderea și închiderea butoanelor
+  Butoanele sunt ascunse\n\nGlisați pentru a extinde sau închide
+  Afișarea și închiderea butoanelor sunt afișate
   Ascunde subtexte
   Subtexte sunt ascunse
   Subtexte sunt afișate
   Ascunde butoanele de omitere înainte şi înapoi
   Sari înainte și înapoi sunt ascunse
   Sari înainte și înapoi sunt afișate
+  Mărimea iniţială
+  Dimensiunea inițială a ecranului, în pixeli
+  Dimensiunea pixelului trebuie să fie între %1$s și %2$s
   Opacitatea suprapunerii
   Valoarea Opacității între 0-100, unde 0 este transparent
   Opacitatea miniplayer suprapusă trebuie să fie între 0-100
@@ -1007,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Culoarea bara de căutare originală este afișată
   Culoare personalizată bara de căutare
   Culoarea barei de căutare
-  Valoare nevalidă a culorii barei de căutare. Utilizarea valorii implicite.
+  Valoare culoare bară căutare nevalidă
   
   
   Ignoră restricțiile regiunii imaginii
diff --git a/src/main/resources/addresources/values-ru-rRU/strings.xml b/src/main/resources/addresources/values-ru-rRU/strings.xml
index 2af70696ac..55cf38401d 100644
--- a/src/main/resources/addresources/values-ru-rRU/strings.xml
+++ b/src/main/resources/addresources/values-ru-rRU/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Раздел расшифровки в описании видео отображен
   Описание видео
   Скрыть или отобразить компоненты описания видео
+  
+  YouTube Doodles
+  Doodles на панели поиска скрыты
+  Doodles на панели поиска отображены
+  YouTube Doodles появляются несколько дней в году.\n\nЕсли в Вашем регионе в настоящее время показывается Doodle, и этот параметр скрытия включен, то панель фильтров под панелью поиска будет также скрыта.
   Пользовательский фильтр
   Скрыть компоненты с помощью пользовательских фильтров
   Пользовательский фильтр
@@ -628,15 +633,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Метка местоположения
   Метка местоположения в Shorts скрыта
   Метка местоположения в Shorts отображена
-  Кнопка сохранения музыки
-  Кнопка сохранения музыки скрыта
-  Кнопка сохранения музыки отображена
+  Кнопка \"Сохранить музыку\"
+  Кнопка \"Сохранить музыку\" скрыта
+  Кнопка \"Сохранить музыку\" отображена
+  Кнопка \"Использовать шаблон\"
+  Кнопка \"Использовать шаблон\" скрыта
+  Кнопка \"Использовать шаблон\" отображена
+  Кнопка \"Предстоящие события\"
+  Кнопка \"Предстоящие события\" скрыта
+  Кнопка \"Предстоящие события\" отображена
+  Кнопка \"Зеленый экран\"
+  Кнопка \"Зеленый экран\" скрыта
+  Кнопка \"Зеленый экран\" отображена
+  Скрыть хэштег
+  Кнопка хэштега скрыта
+  Отображена кнопка хештега
   Поисковые подсказки
   Поисковые подсказки скрыты
   Поисковые подсказки отображены
   Стикеры
   Стикеры скрыты
   Стикеры отображены
+  Анимация кнопки \"Лайк\"
+  Анимация кнопки \"Лайк\" скрыта
+  Анимация кнопки \"Лайк\" отображена
   Кнопка \"Лайк\"
   Кнопка \"Лайк\" в Shorts скрыта
   Кнопка \"Лайк\" в Shorts отображена
@@ -947,20 +967,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Восстановление старого стиля пользовательского интерфейса
   
   
-  Начальная страница
-  По умолчанию
-  
-  Главная
-  Поиск
-  
-  Подписки
-  Навигатор
-  
-  Вкладка \"Вы\"
-  Понравившиеся видео
-  
-  История
-  Популярные
+  Начальная страница
+  По умолчанию
+  Просмотр каналов
+  Навигатор
+  Играть
+  История
+  Библиотека
+  Понравившиеся видео
+  Онлайн
+  Фильмы
+  Музыка
+  Поиск
+  Спорт
+  Подписки
+  Популярные
+  Смотреть позже
   
   
   Возобновление плеера Shorts
@@ -983,15 +1005,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Современный 1
   Современный 2
   Современный 3
-  Кнопки \"Развернуть\" и \"Закрыть\"
-  Кнопки \"Развернуть\" и \"Закрыть\" скрыты\n(разворачивание или сворачивание мини-плеера выполняются жестом)
-  Кнопки \"Развернуть\" и \"Закрыть\" отображены
+  Включить закругленные углы
+  Углы закруглены
+  Углы квадратны
+  Включить двойное нажатие и закрепление для изменения размера
+  Действие двойного нажатия и устройство для изменения размера включено\n\n• Двойное нажатие для увеличения размера мини-плеера\n• Двойное нажатие еще раз для восстановления исходного размера
+  Действие двойного нажатия и закрепление для изменения размера отключены
+  Включить перетаскивание
+  Перетаскивание включено\n\nМини-плеер можно перетащить в любой угол экрана
+  Перетаскивание отключено
+  Скрыть кнопку закрытия
+  Кнопка закрытия скрыта
+  Кнопка закрытия отображается
+  Кнопки \"Развернуть\" и \"Закрыть\"
+  Кнопки скрыты\n\nдля разворачивания или закрытия
+  Показывать кнопки разворачивания и закрытия
   Скрыть подтексты
   Субтексты скрыты
   Подтексты показаны
   Кнопки перемотки
   Кнопки перемотки вперед и назад скрыты
   Кнопки перемотки вперед и назад отображены
+  Начальный размер
+  Начальный размер экрана в пикселях
+  Размер пикселя должен быть между %1$s и %2$s
   Непрозрачность оверлея мини-плеера
   Значение непрозрачности в пределах 0-100, где 0 - это прозрачно
   Непрозрачность оверлея мини-плеера должна быть от 0 до 100
@@ -1007,7 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Оригинальный цвет прогресса воспроизведения отображен
   Пользовательский цвет
   Редактировать цвет прогресса воспроизведения
-  Недопустимое значение цвета
+  Неверное значение цвета прогресса воспроизведения
   
   
   Обход ограничений региона
diff --git a/src/main/resources/addresources/values-si-rLK/strings.xml b/src/main/resources/addresources/values-si-rLK/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-si-rLK/strings.xml
+++ b/src/main/resources/addresources/values-si-rLK/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-sk-rSK/strings.xml b/src/main/resources/addresources/values-sk-rSK/strings.xml
index d37346f242..9f11677c97 100644
--- a/src/main/resources/addresources/values-sk-rSK/strings.xml
+++ b/src/main/resources/addresources/values-sk-rSK/strings.xml
@@ -214,6 +214,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Zobrazí sa sekcia prepisu
   Popis videa
   Skryť alebo zobraziť komponenty popisu videa
+  
   Vlastný filter
   Skryť komponenty pomocou vlastných filtrov
   Povoliť vlastný filter
@@ -911,20 +912,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Obnovte staré rozloženie používateľského rozhrania
   
   
-  Nastaviť úvodnú stránku
-  Predvolené
-  
-  Domov
-  Vyhľadávanie
-  
-  Predplatné
-  Preskúmajte
-  
-  Ty tab
-  Videá, ktoré sa vám páčia
-  
-  História
-  Trendy
+  Nastaviť úvodnú stránku
+  Predvolené
+  Preskúmajte
+  História
+  Videá, ktoré sa vám páčia
+  Vyhľadávanie
+  Predplatné
+  Trendy
   
   
   Zakázať obnovenie prehrávača Shorts
@@ -946,9 +941,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderné 1
   Moderné 2
   Moderné 3
-  Skryť tlačidlá rozbalenia a zatvorenia
-  Tlačidlá sú skryté\n(potiahnutím miniprehrávača rozbalíte alebo zatvoríte)
-  Zobrazia sa tlačidlá rozbalenia a zatvorenia
+  Skryť tlačidlá rozbalenia a zatvorenia
+  Zobrazia sa tlačidlá rozbalenia a zatvorenia
   Skryť podtexty
   Podtexty sú skryté
   Zobrazia sa podtexty
@@ -970,7 +964,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Zobrazí sa pôvodná farba vyhľadávacieho panela
   Vlastná farba vyhľadávacieho panela
   Farba vyhľadávacieho panela
-  Neplatná hodnota farby panela vyhľadávania. Použitie predvolenej hodnoty.
   
   
   
diff --git a/src/main/resources/addresources/values-sl-rSI/strings.xml b/src/main/resources/addresources/values-sl-rSI/strings.xml
index a63b472124..091492c518 100644
--- a/src/main/resources/addresources/values-sl-rSI/strings.xml
+++ b/src/main/resources/addresources/values-sl-rSI/strings.xml
@@ -62,6 +62,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -192,11 +193,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  Privzeto
-  
-  
-  
-  
+  Privzeto
   
   
   
diff --git a/src/main/resources/addresources/values-sq-rAL/strings.xml b/src/main/resources/addresources/values-sq-rAL/strings.xml
index ba79c2847c..48859b4567 100644
--- a/src/main/resources/addresources/values-sq-rAL/strings.xml
+++ b/src/main/resources/addresources/values-sq-rAL/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-sr-rCS/strings.xml b/src/main/resources/addresources/values-sr-rCS/strings.xml
index 0bebe923ec..36e95ccb1b 100644
--- a/src/main/resources/addresources/values-sr-rCS/strings.xml
+++ b/src/main/resources/addresources/values-sr-rCS/strings.xml
@@ -107,9 +107,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Onemogući sjaj dugmadi „Sviđanje” / „Zaprati”
   Dugmad „Sviđanje” i „Zaprati” neće svetleti kada se pritisnu
   Dugmad „Sviđanje” i „Zaprati” će svetleti kada se pritisnu
-  Sakrij sivi separator
-  Sivi separatori su skriveni
-  Sivi separatori su prikazani
+  Sakrij sive razdelnike
+  Sivi razdelnici su skriveni
+  Sivi razdelnici su prikazani
   Sakrij vodeni žig kanala
   Vodeni žig kanala je skriven
   Vodeni žig kanala je prikazan
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Odeljak za transkripciju je prikazan
   Opis videa
   Sakrijte ili prikažite komponente opisa videa
+  
+  Sakrij YouTube Doodles
+  YouTube Doodles u traci za pretragu su skriveni
+  YouTube Doodles u traci za pretragu su prikazani
+  YouTube Doodles se pojavljuje nekoliko dana svake godine.\n\nAko se Doodle trenutno prikazuje u vašem regionu i ovo podešavanje skrivanja je uključeno, traka za filtriranje ispod trake za pretragu takođe će biti skrivena.
   Prilagođeni filter
   Sakrijte komponente koristeći prilagođene filtere
   Omogući prilagođeni filter
@@ -628,9 +633,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Sakrij oznaku lokacije
   Oznaka lokacije je skrivena
   Oznaka lokacije je prikazana
+  Sakrij dugme „Sačuvaj zvuk”
+  Dugme „Sačuvaj zvuk” je skriveno
+  Dugme „Sačuvaj zvuk” je prikazano
+  Sakrij dugme „Koristi šablon”
+  Dugme „Koristi šablon” je skriveno
+  Dugme „Koristi šablon” je prikazano
+  Sakrij dugme „Predstojeće”
+  Dugme „Predstojeće” je skriveno
+  Dugme „Predstojeće” je prikazano
+  Sakrij dugme „Green Screen”
+  Dugme „Green Screen” je skriveno
+  Dugme „Green Screen” je prikazano
   Sakrij predloge za pretragu
   Predlozi za pretragu su skriveni
   Predlozi za pretragu su prikazani
+  Sakrij nalepnice
+  Nalepnice su skrivene
+  Nalepnice su prikazane
+  Sakrij animaciju dugmeta „Sviđanje”
+  Animacija dugmeta „Sviđanje” je skrivena
+  Animacija dugmeta „Sviđanje” je prikazana
   Sakrij dugme „Sviđanje”
   Dugme „Sviđanje” je skriveno
   Dugme „Sviđanje” je prikazano
@@ -941,21 +964,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Vraća stari izgled korisničkog interfejsa
   
   
-  Podešavanje početne stranice
-  Podrazumevana
-  
-  Početna
-  Pretraga
-  
-  Praćenja
-  Istraži
-  Shorts
-  
-  Kartica „Vi”
-  Lajkovani videi
-  
-  Istorija
-  U trendu
+  Podešavanje početne stranice
+  Podrazumevana
+  Istraži
+  Istorija
+  Zbirka
+  Lajkovani videi
+  Pretraga
+  Praćenja
+  U trendu
   
   
   Onemogući nastavak reprodukcije Shorts plejera
@@ -978,9 +995,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderan 1
   Moderan 2
   Moderan 3
-  Sakrij dugmad za proširivanje i zatvaranje
-  Dugmad za proširivanje i zatvaranje su skrivena\n(prevucite mini-plejer da biste ga proširili ili zatvorili)
-  Dugmad za proširivanje i zatvaranje su prikazana
+  Sakrij dugmad za proširivanje i zatvaranje
   Sakrij podtekstove
   Podtekstovi su skriveni
   Podtekstovi su prikazani
@@ -1002,7 +1017,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Originalna boja trake za premotavanje je prikazana
   Prilagođena boja trake za premotavanje
   Boja trake za premotavanje
-  Nevažeća vrednost boje trake za premotavanje. Korišćenje podrazumevane vrednosti.
+  Nevažeća vrednost boje trake za premotavanje
   
   
   Zaobiđi ograničenja regiona slike
diff --git a/src/main/resources/addresources/values-sr-rSP/strings.xml b/src/main/resources/addresources/values-sr-rSP/strings.xml
index 698d8ad287..5620851ffa 100644
--- a/src/main/resources/addresources/values-sr-rSP/strings.xml
+++ b/src/main/resources/addresources/values-sr-rSP/strings.xml
@@ -107,9 +107,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Онемогући сјај дугмади „Свиђање” / „Запрати”
   Дугмад „Свиђање” и „Запрати” неће светлети када се притисну
   Дугмад „Свиђање” и „Запрати” ће светлети када се притисну
-  Сакриј сиви сепаратор
-  Сиви сепаратори су скривени
-  Сиви сепаратори су приказани
+  Сакриј сиве разделнике
+  Сиви разделници су скривени
+  Сиви разделници су приказани
   Сакриј водени жиг канала
   Водени жиг канала је скривен
   Водени жиг канала је приказан
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Одељак за транскрипцију је скривен
   Опис видеа
   Сакријте или прикажите компоненте описа видеа
+  
+  Сакриј YouTube Doodles
+  YouTube Doodles у траци за претрагу су скривени
+  YouTube Doodles у траци за претрагу су приказани
+  YouTube Doodles се појављује неколико дана сваке године.\n\nАко се Doodle тренутно приказује у вашем региону и ово подешавање скривања је укључено, трака за филтрирање испод траке за претрагу такође ће бити скривена.
   Прилагођени филтер
   Сакријте компоненте користећи прилагођене филтере
   Омогући прилагођени филтер
@@ -628,9 +633,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Сакриј ознаку локације
   Ознака локације је скривена
   Ознака локације је приказана
+  Сакриј дугме „Сачувај звук”
+  Дугме „Сачувај звук” је скривено
+  Дугме „Сачувај звук” је приказано
+  Сакриј дугме „Користи шаблон”
+  Дугме „Користи шаблон” је скривено
+  Дугме „Користи шаблон” је приказано
+  Сакриј дугме „Предстојеће”
+  Дугме „Предстојеће” је скривено
+  Дугме „Предстојеће” је приказано
+  Сакриј дугме „Green Screen”
+  Дугме „Green Screen” је скривено
+  Дугме „Green Screen” је приказано
   Сакриј предлоге за претрагу
   Предлози за претрагу су скривени
   Предлози за претрагу су приказани
+  Сакриј налепнице
+  Налепнице су скривене
+  Налепнице су приказане
+  Сакриј анимацију дугмета „Свиђање”
+  Анимација дугмета „Свиђање” је скривена
+  Анимација дугмета „Свиђање” је приказана
   Сакриј дугме „Свиђање”
   Дугме „Свиђање” је скривено
   Дугме „Свиђање” је приказано
@@ -941,21 +964,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Враћа стари изглед корисничког интерфејса
   
   
-  Подешавање почетне странице
-  Подразумевана
-  
-  Почетна
-  Претрага
-  
-  Праћења
-  Истражи
-  Shorts
-  
-  Картица „Ви”
-  Лајковани видеи
-  
-  Историја
-  У тренду
+  Подешавање почетне странице
+  Подразумевана
+  Истражи
+  Историја
+  Збирка
+  Лајковани видеи
+  Претрага
+  Праћења
+  У тренду
   
   
   Онемогући наставак репродукције Shorts плејера
@@ -978,9 +995,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Модеран 1
   Модеран 2
   Модеран 3
-  Сакриј дугмад за проширивање и затварање
-  Дугмад за проширивање и затварање су скривена\n(превуците мини-плејер да бисте га проширили или затворили)
-  Дугмад за проширивање и затварање су приказана
+  Сакриј дугмад за проширивање и затварање
   Сакриј подтекстове
   Подтекстови су скривени
   Подтекстови су приказани
@@ -1002,7 +1017,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Оригинална боја траке за премотавање је приказана
   Прилагођена боја траке за премотавање
   Боја траке за премотавање
-  Неважећа вредност боје траке за премотавање. Коришћење подразумеване вредности.
+  Неважећа вредност боје траке за премотавање
   
   
   Заобиђи ограничења региона слике
diff --git a/src/main/resources/addresources/values-sv-rSE/strings.xml b/src/main/resources/addresources/values-sv-rSE/strings.xml
index 30f07225a3..bee30b259e 100644
--- a/src/main/resources/addresources/values-sv-rSE/strings.xml
+++ b/src/main/resources/addresources/values-sv-rSE/strings.xml
@@ -231,6 +231,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Transkriptsektionen är synlig
   Videobeskrivning
   Dölj eller visa videobeskrivningskomponenter
+  
+  Dölj YouTube Doodles
+  Sökfältet Doodles är dolda
+  Sökfältet Doodles visas
+  YouTube Doodles dyker upp några dagar varje år.\n\nOm en Doodle för närvarande visas i din region och denna gömma inställning är på, sedan filterfältet nedanför sökfältet kommer också att döljas.
   Anpassat filter
   Dölj komponenter med anpassade filter
   Aktivera anpassat filter
@@ -629,14 +634,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Platsetiketten är dold
   Platsetikett är synlig
   Dölj spara musikknappen
-  Spara musik är dold
-  Spara musik visas
+  Spara musikknappen är dold
+  Spara musikknappen visas
+  Dölj användning av mallknapp
+  Använd mallknappen är dold
+  Använd mallknappen visas
+  Dölj kommande knapp
+  Kommande knapp är dold
+  Kommande knapp visas
+  Dölj grön skärmknapp
+  Grön skärm-knappen är dold
+  Grön skärmknapp visas
+  Dölj hashtag-knapp
+  Hashtag-knappen är dold
+  Hashtag-knappen visas
   Dölj sökförslag
   Sökförslag är dolda
   Sökförslag är synliga
   Dölj klistermärken
   Klistermärken är dolda
   Klistermärken visas
+  Dölj som fontän
+  Som knappen fontän animering är dold
+  Som knappen fontän animering visas
   Dölj knappen gilla
   Knappen gilla är dold
   Knappen gilla är synlig
@@ -947,20 +967,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Återställ gamla användargränssnitt
   
   
-  Ställ in startsida
-  Standard
-  
-  Hem
-  Sök
-  
-  Prenumerationer
-  Utforska
-  
-  Du flik
-  Gillade videor
-  
-  Historik
-  Trendande
+  Ställ in startsida
+  Standard
+  Bläddra bland kanaler
+  Utforska
+  Spel
+  Historik
+  Bibliotek
+  Gillade videor
+  Live
+  Filmer
+  Musik
+  Sök
+  Sport
+  Prenumerationer
+  Trendande
+  Titta senare
   
   
   Inaktivera återupptagande av Shorts spelare
@@ -983,15 +1005,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
-  Dölj expandera och stäng knappar
-  Knappar är dolda\n(svep minispelare för att expandera eller stänga)
-  Expandera och stäng knappar visas
+  Aktivera rundade hörn
+  Hörnen är rundade
+  Hörnen är kvadratiska
+  Aktivera dubbeltryck och nypa för att ändra storlek
+  Dubbeltryck på åtgärder och nypa för att ändra storlek är aktiverat\n\n• Dubbeltryck för att öka minispelarstorlek\n• Dubbeltryck igen för att återställa originalstorleken
+  Dubbeltryck åtgärd och nypa för att ändra storlek är inaktiverad
+  Aktivera dra och släpp
+  Dra och släpp är aktiverat\n\nMiniplayer kan dras till valfritt hörn av skärmen
+  Dra och släpp är inaktiverat
+  Dölj stängningsknappen
+  Stäng knappen är dold
+  Stäng knappen visas
+  Dölj expandera och stäng knappar
+  Knapparna är dolda\n\nSvep för att expandera eller stänga
+  Expandera och stäng knappar visas
   Dölj undertexter
   Undertexter är dolda
   Undertexter visas
   Dölj hoppa över framåt- och bakknapparna
   Hoppa framåt och tillbaka är dolda
   Hoppa framåt och tillbaka visas
+  Ursprunglig storlek
+  Inledande på skärmstorlek, i pixlar
+  Pixelstorlek måste vara mellan %1$s och %2$s
   Överlager opacitet
   Opacitetsvärde mellan 0-100, där 0 är transparent
   Miniplayer overlay opacitet måste vara mellan 0-100
@@ -1007,7 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Original sökfält färg visas
   Anpassad sökfält färg
   Färgen på sökfältet
-  Ogiltigt sökfältets färgvärde. Använder standardvärde.
+  Ogiltigt sökfältets färgvärde
   
   
   Begränsningar för förbipassering av bildregionen
diff --git a/src/main/resources/addresources/values-sw-rKE/strings.xml b/src/main/resources/addresources/values-sw-rKE/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-sw-rKE/strings.xml
+++ b/src/main/resources/addresources/values-sw-rKE/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-ta-rIN/strings.xml b/src/main/resources/addresources/values-ta-rIN/strings.xml
index 00e52a858b..6305be548e 100644
--- a/src/main/resources/addresources/values-ta-rIN/strings.xml
+++ b/src/main/resources/addresources/values-ta-rIN/strings.xml
@@ -62,6 +62,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -192,11 +193,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  இயல்புநிலை
-  
-  
-  
-  
+  இயல்புநிலை
   
   
   
diff --git a/src/main/resources/addresources/values-te-rIN/strings.xml b/src/main/resources/addresources/values-te-rIN/strings.xml
index 43a184f3a6..be82d6b2fd 100644
--- a/src/main/resources/addresources/values-te-rIN/strings.xml
+++ b/src/main/resources/addresources/values-te-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-th-rTH/strings.xml b/src/main/resources/addresources/values-th-rTH/strings.xml
index d4662bf482..58b62a7172 100644
--- a/src/main/resources/addresources/values-th-rTH/strings.xml
+++ b/src/main/resources/addresources/values-th-rTH/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -251,10 +252,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
+  ค่าเริ่มต้น
   
   
   
diff --git a/src/main/resources/addresources/values-tr-rTR/strings.xml b/src/main/resources/addresources/values-tr-rTR/strings.xml
index 16bd15082c..056dfbc3c3 100644
--- a/src/main/resources/addresources/values-tr-rTR/strings.xml
+++ b/src/main/resources/addresources/values-tr-rTR/strings.xml
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Transkript kısmı gösteriliyor
   Video açıklaması
   Video açıklamasındaki öğeleri gizle veya göster
+  
+  YouTube Doodle\'larını gizle
+  Arama çubuğu Doodle\'ları gizli
+  Arama çubuğu Doodle\'ları görünür
+  YouTube Doodle\'ları her yıl birkaç gün görünür.\n\nEğer bölgenizde bir Doodle görünüyorsa ve bu gizleme seçeneği açıksa, arama çubuğunun altındaki filtre barı da gizlenecektir.
   Özel filtre
   Özel filtre ile öğeleri gizle
   Özel filtreyi etkinleştir
@@ -630,12 +635,24 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Müziği kaydet düğmesini gizle
   Müziği kaydet düğmesi gizli
   Müziği kaydet düğmesi görünür
+  Şablonu kullan düğmesini gizle
+  Şablonu kullan düğmesi gizli
+  Şablonu kullan düğmesi görünür
+  \"Gelecek\" düğmesini gizle
+  \"Gelecek\" düğmesi gizli
+  \"Gelecek\" düğmesi görünür
+  Yeşil ekran düğmesini gizle
+  Yeşil ekran düğmesi gizli
+  Yeşil ekran düğmesi görünür
   Arama önerilerini gizle
   Arama önerileri gizleniyor 
   Arama önerileri gösteriliyor 
   Çıkartmaları gizle
   Çıkartmalar gizli
   Çıkartmalar görünür
+  Beğeni çeşmesini gizle
+  Beğeni düğmesi çeşme animasyonu gizli
+  Beğeni düğmesi çeşme animasyonu görünür
   \"Beğen\" butonunu gizle
   \"Beğen\" butonu gizleniyor
   \"Beğen\" butonu gösteriliyor
@@ -946,20 +963,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Eski arayüzü geri getir
   
   
-  Başlangıç sayfasını seç
-  Varsayılan
-  
-  Ana Sayfa
-  Arama
-  
-  Abonelikler
-  Keşfet
-  
-  Siz sekmesi
-  Beğenilen videolar
-  
-  Geçmiş
-  Trendler
+  Başlangıç sayfasını seç
+  Varsayılan
+  Keşfet
+  Geçmiş
+  Kitaplık
+  Beğenilen videolar
+  Arama
+  Abonelikler
+  Trendler
   
   
   Shorts oynatıcıya devam edilmesini devre dışı bırak
@@ -982,9 +994,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
-  Büyüt ve kapat düğmelerini gizle
-  Düğmeler gizli\n(büyütmek veya kapatmak için mini oynatıcıyı sürükleyin)
-  Büyüt ve kapat düğmeleri görünür
+  Büyüt ve kapat düğmelerini gizle
   Alt metinleri gizle
   Alt metinler gizli
   Alt metinler görünür
@@ -1006,7 +1016,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Orijinal zaman çubuğu rengi gösteriliyor
   Özel zaman çubuğu rengi
   Zaman çubuğunun rengi
-  Geçersiz renk değeri. Varsayılana sıfırlanıyor.
+  Geçersiz zaman çubuğu renk değeri
   
   
   Resimlerin bölge kısıtlamalarını atla
diff --git a/src/main/resources/addresources/values-uk-rUA/strings.xml b/src/main/resources/addresources/values-uk-rUA/strings.xml
index e6559c1a20..8ee8b86db0 100644
--- a/src/main/resources/addresources/values-uk-rUA/strings.xml
+++ b/src/main/resources/addresources/values-uk-rUA/strings.xml
@@ -117,7 +117,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Горизонтальні полиці показуються
   
-  Приховати кнопку \"Спонсорувати\"
+  Приховати \"Спонсорувати\"
   Кнопку \"Спонсорувати\" приховано
   Кнопка \"Спонсорувати\" показується
   
@@ -126,7 +126,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Полиця \"Для вас\" на сторінці каналу показується
   
-  Приховати кнопку \"Сповістити\"
+  Приховати \"Сповістити\"
   Кнопку \"Сповістити\" приховано
   Кнопка \"Сповістити\" показується
   
@@ -135,7 +135,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Рекомендації \"Люди також дивилися\" показуються
   
-  Приховати кнопку \"Показати більше\"
+  Приховати \"Показати більше\"
   Кнопку \"Показати більше\" приховано
   Кнопка \"Показати більше\" показується
   Приховати тимчасові реакції
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Секція \"Текст відео\" показується
   Опис відео
   Приховати або показувати компоненти опису відео
+  
+  Приховати YouTube Doodles
+  Doodles у пошуковій панелі приховано
+  Doodles у пошуковій панелі показуються
+  YouTube Doodles з’являються декілька днів на рік.\n\nЯкщо Doodle наразі відображається у Вашому регіоні й це налаштування приховування увімкнено, то панель фільтрів під панеллю пошуку також буде приховано.
   Користувацький фільтр
   Приховати компоненти за допомогою користувацьких фільтрів
   Увімкнути користувацький фільтр
@@ -289,7 +294,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Посилання на покупки в описі відео приховано
   Посилання на покупки в описі відео показуються
   
-  Приховати кнопку \"Відвідати магазин\"
+  Приховати \"Відвідати магазин\"
   Кнопку \"Відвідати магазин\" на сторінках каналів приховано
   Кнопка \"Відвідати магазин\" на сторінках каналів показується
   Приховати результати вебпошуку
@@ -422,18 +427,18 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Кнопка \"Зберегти\" показується
   
   
-  Приховати кнопку \"Автовідтворення\"
+  Приховати \"Автовідтворення\"
   Кнопку \"Автовідтворення\" у відеоплеєрі приховано
   Кнопка \"Автовідтворення\" у відеоплеєрі показується
   
   
   
-  Приховати кнопку \"Субтитри\"
+  Приховати \"Субтитри\"
   Кнопку \"Субтитри\" у відеоплеєрі приховано
   Кнопка \"Субтитри\" у відеоплеєрі показується
   
   
-  Приховати кнопку \"Трансляція\"
+  Приховати \"Трансляція\"
   Кнопку \"Трансляція\" у відеоплеєрі приховано
   Кнопка \"Трансляція\" у відеоплеєрі показується
   
@@ -534,7 +539,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Приховати прев\'ю коментар
   Прев\'ю коментар в секції коментарів приховано
   Прев\'ю коментар в секції коментарів показується
-  Приховати кнопку \"Дякую\"
+  Приховати \"Дякую\"
   Кнопку \"Дякую\" приховано
   Кнопка \"Дякую\" показується
   Приховати мітку часу та емодзі
@@ -605,11 +610,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Shorts у результатах пошуку приховано
   Shorts у результатах пошуку показуються
   
-  Приховати кнопку \"Спонсорувати\"
+  Приховати \"Спонсорувати\"
   Кнопку \"Спонсорувати\" приховано
   Кнопка \"Спонсорувати\" показується
   
-  Приховати кнопку \"Підписатися\"
+  Приховати \"Підписатися\"
   Кнопку \"Підписатися\" приховано
   Кнопка \"Підписатися\" показується
   Приховати кнопки на паузі
@@ -630,12 +635,27 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Приховати \"Зберегти музику\"
   Кнопку \"Зберегти музику\" приховано
   Кнопка \"Зберегти музику\" показується
+  Приховати \"Використати шаблон\"
+  Кнопку \"Використати шаблон\" приховано
+  Кнопка \"Використати шаблон\" показується
+  Приховати \"Запланована прем\'єра\"
+  Кнопки \"Запланована прем\'єра\" та \"Незабаром прямий ефір\" приховано
+  Кнопки \"Запланована прем\'єра\" та \"Незабаром прямий ефір\" показуються
+  Приховати \"Зелений екран\"
+  Кнопку \"Зелений екран\" приховано
+  Кнопка \"Зелений екран\" показується
+  Сховати кнопку хештегу
+  Кнопка хештегу прихована
+  Кнопка хештегу відображається
   Приховати пропозиції пошуку
   Пропозиції пошуку приховано
   Пропозиції пошуку показуються
   Приховати стікери
   Стікери приховано
   Стікери показуються
+  Приховати анімацію фонтану
+  Анімацію фонтану біля кнопки \"Подобається\" приховано
+  Анімація фонтану біля кнопки \"Подобається\" показується
   Приховати \"Подобається\"
   Кнопку \"Подобається\" приховано
   Кнопка \"Подобається\" показується
@@ -668,7 +688,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Приховати посилання на повне відео
   Мітка посилання на повне відео приховано
   Мітка посилання на повне відео показується
-  Приховати кнопку \"Зі звуком\"
+  Приховати \"Зі звуком\"
   Кнопку \"Зі звуком\" приховано
   Кнопка \"Зі звуком\" показується
   Приховати панель навігації
@@ -946,20 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Відновлення старого інтерфейсу
   
   
-  Встановити початкову сторінку
-  За замовчуванням
-  
-  Головна
-  Пошук
-  
-  Підписки
-  Що нового
-  
-  Вкладка \"Ви\"
-  Відео, які сподобалися
-  
-  Історія
-  Популярне
+  Встановити початкову сторінку
+  Типово
+  Перегляд каналів
+  Що нового
+  Ігри
+  17.33.42 - Відновлення старого інтерфейсу
+  Бібліотека
+  17.41.37 - Відновлення старого інтерфейсу плейлиста
+  Наживо
+  Фільми
+  Музика
+  Версія додатку підробиться на старішу версію YouTube.\n\nЦе змінить вигляд і функції додатку, можуть трапитися невідомі побічні ефекти.\n\nЯкщо пізніше вимкнути, рекомендується очистити дані додатку, щоб запобігти помилкам інтерфейсу.
+  Спортивні ігри
+  Підробити версію програми на
+  Популярне
+  Дивитися пізніше
   
   
   Вимкнути плеєр Shorts при запуску
@@ -982,15 +1004,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Новітній 1
   Новітній 2
   Новітній 3
-  Приховати кнопки розгортання та закриття
-  Кнопки розгортання та закриття в мініплеєрі приховано\n(проведіть по мініплеєру, щоб розгорнути чи закрити)
-  Кнопки розгортання та закриття в мініплеєрі показуються
+  Увімкнути округлені кути
+  Кути округлені
+  Квадратні кути
+  Увімкнути подвійне натискання та затиснення для зміни розміру
+  Подвійне натискання для дії та відновлення розміру вимкнуто
+  Увімкнути перетягування
+  Перетягніть увімкнену\n\nМінімальний плеєр можна перетягнути у будь-який кут екрану
+  Перетягування вимкнуто
+  Приховати кнопку закриття
+  Кнопка закриття прихована
+  Кнопка закриття відображається
+  Приховати кнопки розгортання та закриття
+  Кнопки приховані\n\nПроведіть щоб розгорнути або закрити
+  Розгорнути і закрити кнопки показано
   Приховати підтексти
   Підтексти в мініплеєрі приховано
   Підтексти в мініплеєрі показуються
   Приховати кнопки перемотування
   Кнопки перемотування вперед та назад в мініплеєрі приховано
   Кнопки перемотування вперед та назад в мініплеєрі показуються
+  Початковий розмір
+  Початковий розмір екрану в пікселях
+  Розмір у пікселях повинен бути від %1$s до %2$s
   Затемнення мініплеєра
   Значення затемнення при натисканні на мініплеєр в межах 0-100, де 0 це прозоро
   Значення затемнення мініплеєра має бути в межах 0-100
@@ -1006,7 +1042,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Показується оригінальний колір панелі прогресу відтворення
   Користувацький колір панелі прогресу
   Редагувати колір панелі прогресу відтворення
-  Недійсне значення кольору панелі прогресу відтворення. Скинуто до значення за умовчанням.
+  Недійсне значення кольору панелі прогресу відтворення
   
   
   Змінити хост зображень
diff --git a/src/main/resources/addresources/values-ur-rIN/strings.xml b/src/main/resources/addresources/values-ur-rIN/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-ur-rIN/strings.xml
+++ b/src/main/resources/addresources/values-ur-rIN/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-uz-rUZ/strings.xml b/src/main/resources/addresources/values-uz-rUZ/strings.xml
index 1c1b555ec9..cf161c4f4b 100644
--- a/src/main/resources/addresources/values-uz-rUZ/strings.xml
+++ b/src/main/resources/addresources/values-uz-rUZ/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   
diff --git a/src/main/resources/addresources/values-vi-rVN/strings.xml b/src/main/resources/addresources/values-vi-rVN/strings.xml
index c05368d0f2..86064038c2 100644
--- a/src/main/resources/addresources/values-vi-rVN/strings.xml
+++ b/src/main/resources/addresources/values-vi-rVN/strings.xml
@@ -230,6 +230,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Phần bản chép lời được hiện
   Mô tả video
   Ẩn hoặc hiện các thành phần mô tả video
+  
   Bộ lọc tùy chỉnh
   Ẩn các thành phần dùng bộ lọc tùy chỉnh
   Bật bộ lọc tùy chỉnh
@@ -627,9 +628,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Ẩn nhãn vị trí
   Nhãn vị trí được ẩn
   Nhãn vị trí được hiện
+  Ẩn nút lưu nhạc
   Ẩn đề xuất tìm kiếm
   Đề xuất tìm kiếm được ẩn
   Đề xuất tìm kiếm được hiện
+  Ẩn nhãn dán
+  Nhãn dán được ẩn
+  Nhãn dán được hiện
+  Ẩn đài phun thích
+  Đài phun thích được ẩn
+  Đài phun thích được hiện
   Ẩn nút thích
   Nút thích được ẩn
   Nút thích được hiện
@@ -940,20 +948,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Khôi phục bố cục giao diện cũ
   
   
-  Đặt trang bắt đầu
-  Mặc định
-  
-  Trang chủ
-  Tìm kiếm
-  
-  Đăng ký
-  Khám phá
-  
-  Thẻ Bạn
-  Video đã thích
-  
-  Lịch sử
-  Xu hướng
+  Đặt trang bắt đầu
+  Mặc định
+  Khám phá
+  Lịch sử
+  Video đã thích
+  Tìm kiếm
+  Đăng ký
+  Xu hướng
   
   
   Tắt tiếp tục trình phát Shorts
@@ -976,9 +978,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Hiện đại 1
   Hiện đại 2
   Hiện đại 3
-  Ẩn các nút mở rộng và đóng
-  Các nút được ẩn\n(vuốt trình phát thu nhỏ để mở rộng hoặc đóng)
-  Các nút mở rộng và đóng được hiện
+  Ẩn các nút mở rộng và đóng
   Ẩn văn bản phụ
   Văn bản phụ được ẩn
   Văn bản phụ được hiện
@@ -1000,7 +1000,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Màu gốc thanh tiến trình được hiện 
   Màu tùy chỉnh thanh tiến trình
   Màu của thanh tiến trình
-  Màu thanh tiến trình không hợp lệ.
   
   
   Vượt qua hạn chế khu vực cho hình ảnh
diff --git a/src/main/resources/addresources/values-zh-rCN/strings.xml b/src/main/resources/addresources/values-zh-rCN/strings.xml
index 559a9e9423..72f5244119 100644
--- a/src/main/resources/addresources/values-zh-rCN/strings.xml
+++ b/src/main/resources/addresources/values-zh-rCN/strings.xml
@@ -229,6 +229,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   显示字幕部分
   视频描述
   隐藏或显示视频描述组件
+  
+  隐藏 YouTube Doodles
+  搜索栏门框已隐藏
+  显示搜索栏门框
+  YouTube Doodles 每年显示几天。\n\n如果您所在区域正在显示一个Doodle且此隐藏设置已开启。 然后搜索栏下方的过滤栏也将被隐藏。
   自定义过滤器
   使用自定义过滤器隐藏组件
   启用自定义过滤器
@@ -627,14 +632,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   位置标签已隐藏
   显示位置标签
   隐藏保存音乐按钮
-  保存音乐已隐藏
-  保存音乐已显示
+  保存音乐按钮已隐藏
+  保存音乐按钮已显示
+  隐藏使用模板按钮
+  使用模板按钮隐藏
+  显示模板按钮
+  隐藏即将到来的按钮
+  即将到来的按钮被隐藏
+  显示即将到来的按钮
+  隐藏绿色屏幕按钮
+  绿色屏幕按钮已隐藏
+  显示绿色屏幕按钮
+  隐藏标签按钮
+  标签按钮已隐藏
+  显示标签按钮
   隐藏搜索建议
   搜索建议已隐藏
   显示搜索建议
   隐藏貼圖
   貼圖已隐藏
   显示貼圖
+  隐藏像喷射那样的
+  像按钮喷发动画一样隐藏
+  像按钮喷射动画
   隐藏像按钮
   喜欢按钮已隐藏
   显示喜欢按钮
@@ -944,20 +964,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - 还原旧界面布局
   
   
-  设置起始页
-  默认
-  
-  首页
-  搜索
-  
-  订阅
-  浏览
-  
-  您的标签
-  喜欢的视频
-  
-  历史记录
-  热门主题
+  设置起始页
+  默认
+  浏览频道
+  浏览
+  游戏中
+  历史记录
+  书库
+  喜欢的视频
+  实时模式
+  电影
+  音乐
+  搜索
+  运动
+  订阅
+  热门主题
+  稍后查看
   
   
   禁用恢复快捷播放器
@@ -980,15 +1002,29 @@ This is because Crowdin requires temporarily flattening this file and removing t
   现代1
   现代2
   现代3
-  隐藏展开和关闭按钮
-  按钮是隐藏的\n(滑动微播放器以展开或关闭)
-  展开和关闭按钮显示
+  启用圆角
+  四角四舍五入
+  角是方形
+  启用双击并固定以调整大小
+  双击动作和缩放以调整大小已启用\n\n• 双击以增加小玩家大小\n再次双击以恢复原始大小
+  双击动作和固定以调整大小已禁用
+  启用拖放功能
+  拖放已启用\n\n迷你播放器可以拖动到屏幕的任何角
+  拖放已禁用
+  隐藏关闭按钮
+  关闭按钮已隐藏
+  显示关闭按钮
+  隐藏展开和关闭按钮
+  展开和关闭按钮显示
   隐藏子文本
   隐藏子文本
   显示子文本
   隐藏跳过后退按钮
   向前跳过并隐藏
   向前跳过并显示
+  初始大小
+  初始屏幕大小,以像素
+  像素大小必须介于 %1$s 和 %2$s 之间
   覆盖层不透明度
   0-100之间的不透明度值, 其中0是透明的
   最小播放器覆盖不透明度必须介于 0-100 之间
@@ -1004,7 +1040,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   显示原始搜索栏颜色
   自定义搜索栏颜色
   搜索栏的颜色
-  无效的搜索栏颜色值。使用默认值。
+  无效的搜索栏颜色值
   
   
   旁路图像区域限制
diff --git a/src/main/resources/addresources/values-zh-rTW/strings.xml b/src/main/resources/addresources/values-zh-rTW/strings.xml
index 4210ab297e..ab380a4eb3 100644
--- a/src/main/resources/addresources/values-zh-rTW/strings.xml
+++ b/src/main/resources/addresources/values-zh-rTW/strings.xml
@@ -80,7 +80,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   動態消息
   播放器
   通用版面
-  拖拽欄
+  進度列
   滑動控制
   其他
   影片
@@ -121,9 +121,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   已隱藏按鈕
   已顯示按鈕
   
-  在頻道頁面中隱藏「為你推薦」櫃
-  已隱藏櫃子
-  已顯示櫃子
+  在頻道頁面中隱藏「為你推薦」匣
+  已隱藏「為你推薦」匣
+  已顯示「為你推薦」匣
   
   隱藏「通知我」按鈕
@@ -141,15 +141,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
   隱藏直播即時反應
   已隱藏直播即時反應
   已顯示直播即時反應
-  隱藏搜尋結果標頭櫃
-  已隱藏標頭櫃
-  已顯示標頭櫃
+  隱藏位於搜尋結果中的 [標頭匣]
+  已隱藏 [標頭匣]
+  已顯示 [標頭匣]
   隱藏頻道規範
   已隱藏頻道規範
   已顯示頻道規範
-  隱藏章節櫃
-  已隱藏章節櫃
-  已顯示章節櫃
+  隱藏 [章節匣]
+  已隱藏 [章節匣]
+  已顯示 [章節匣]
   隱藏影片下方的章節選擇欄
   已隱藏影片下方的章節選擇欄
   已顯示影片下方的章節選擇欄
@@ -174,9 +174,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   隱藏訂閱者《社群規範》
   已隱藏《訂閱者社群規範》
   已顯示《訂閱者社群規範》
-  隱藏頻道會員櫃
-  已隱藏頻道會員櫃
-  已顯示頻道會員櫃
+  隱藏 [頻道會員匣]
+  已隱藏 [頻道會員匣]
+  已顯示 [頻道會員匣]
   隱藏影片警告提醒
   已隱藏影片警告提醒
   已顯示影片警告提醒
@@ -198,9 +198,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   隱藏快捷功能欄相關影片
   已隱藏相關影片
   已顯示相關影片
-  在搜尋結果中隱藏圖片櫃
-  已隱藏圖片櫃
-  已顯示圖片櫃
+  在搜尋結果中隱藏 [圖片匣]
+  已隱藏 [圖片匣]
+  已顯示 [圖片匣]
   隱藏最新貼文
   已隱藏最新貼文
   已顯示最新貼文
@@ -230,6 +230,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   已顯示字幕記錄區
   影片描述欄
   隱藏或顯示影片描述欄內容
+  
+  隱藏 YouTube Doodles
+  已隱藏位於搜尋欄的 Doodles 
+  已顯示位於搜尋欄的 Doodles 
+  YouTube Doodles 會在一年裡不定期顯現。\n\n如果您的 Doodles 目前正在您的地區中提供,且本設定為啟用,則位於搜尋攔下方的篩選器也會隱藏。
   自訂篩選器
   使用自訂篩選器隱藏欄位
   啟用自訂篩選器
@@ -347,9 +352,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   已啟用手勢
   
   
-  啟用進度條點擊
-  已啟用進度條點擊
-  已停用進度條點擊
+  啟用進度列點擊
+  已啟用進度列點擊
+  已停用進度列點擊
   
   
   啟用亮度手勢
@@ -585,12 +590,12 @@ This is because Crowdin requires temporarily flattening this file and removing t
   動畫滾動數字
   
   
-  隱藏影片播放器進度條
-  已隱藏影片播放器進度條
-  已顯示影片播放器進度條
-  在縮圖中隱藏進度條
-  已隱藏縮圖進度條
-  已顯示縮圖進度條
+  隱藏影片播放器進度列
+  已隱藏影片播放器進度列
+  已顯示影片播放器進度列
+  在縮圖中隱藏進度列
+  已隱藏縮圖進度列
+  已顯示縮圖進度列
   
   
   
@@ -630,12 +635,24 @@ This is because Crowdin requires temporarily flattening this file and removing t
   隱藏 [儲存音樂] 按鈕
   已隱藏 [儲存音樂] 按鈕
   已顯示 [顯示音樂] 按鈕
+  隱藏 [使用範本] 按鈕
+  已隱藏 [使用範本] 按鈕
+  已顯示 [使用範本] 按鈕
+  隱藏 [即將到來] 按鈕
+  已隱藏 [即將到來] 按鈕
+  已顯示 [即將到來] 按鈕
+  隱藏 [綠色畫面] 按鈕
+  已隱藏 [綠色畫面] 按鈕
+  已顯示 [綠色畫面] 按鈕
   隱藏搜尋建議
   已隱藏搜尋建議
   已顯示搜尋建議
   隱藏「Stickers」
   已隱藏「Stickers」
   已顯示「Stickers」
+  隱藏 [喜歡] 按鈕的動畫
+  已隱藏 [喜歡] 按鈕的動畫
+  已顯示 [喜歡] 按鈕的動畫
   隱藏「喜歡」按鈕
   已隱藏「喜歡」按鈕
   已顯示「喜歡」按鈕
@@ -745,9 +762,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   已停用寬搜尋列
   
   
-  還原舊版進度條縮圖
-  進度條縮圖將出現在進度條上
-  進度條縮圖將出現在全螢幕畫面
+  還原舊版進度列縮圖
+  進度列縮圖將出現在進度列上
+  進度列縮圖將出現在全螢幕畫面
   
   
   啟用 SponsorBlock
@@ -862,7 +879,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   自動跳過
   自動跳過一次
   顯示跳過按鈕
-  在進度條顯示
+  在進度列顯示
   停用
   無法提交片段:%s
   SponsorBlock 暫時離線
@@ -942,24 +959,18 @@ This is because Crowdin requires temporarily flattening this file and removing t
   18.33.40 - 在 Shorts 無痕模式中還原 RYD
   18.20.39 - 還原寬影片速度 & 畫質選單
   18.09.39 - 還原庫標籤
-  17.41.37 - 還原舊版播放清單櫃
+  17.41.37 - 還原舊版播放清單匣
   17.33.42 - 還原舊版 UI 介面
   
   
-  設定啟動頁面
-  預設
-  
-  首頁
-  搜尋
-  
-  訂閱
-  探索
-  
-  個人中心
-  喜歡的影片
-  
-  歷史記錄
-  發燒影片
+  設定啟動頁面
+  預設
+  探索
+  歷史記錄
+  喜歡的影片
+  搜尋
+  訂閱
+  發燒影片
   
   
   停用自動復原 Shorts 播放器
@@ -982,9 +993,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   現代樣式 1
   現代樣式 2
   現代樣式 3
-  隱藏擴展和關閉按鈕
-  已隱藏按鈕\n(滑動迷你播放器以擴展或關閉)
-  已顯示擴展和關閉按鈕
+  隱藏擴展和關閉按鈕
+  已顯示擴展和關閉按鈕
   隱藏副標
   副標已隱藏
   副標已顯示
@@ -1001,12 +1011,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
   載入畫面將有純色背景
   
   
-  啟用自訂進度條顏色
-  已顯示自訂進度條顏色
-  已顯示原版進度條顏色
-  自訂進度條顏色
-  進度條顏色
-  無效的進度條顏色。已重設為預設值。
+  啟用自訂進度列顏色
+  已顯示自訂進度列顏色
+  已顯示原版進度列顏色
+  自訂進度列顏色
+  進度列顏色
   
   
   繞過圖片區域限制
diff --git a/src/main/resources/addresources/values-zu-rZA/strings.xml b/src/main/resources/addresources/values-zu-rZA/strings.xml
index e8f1b1cb54..4281ce7a40 100644
--- a/src/main/resources/addresources/values-zu-rZA/strings.xml
+++ b/src/main/resources/addresources/values-zu-rZA/strings.xml
@@ -55,6 +55,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
+  
   
   
@@ -180,10 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  
-  
-  
-  
   
   
   

From ece86f217b40cba5441be431365d9f5738af12f8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Sat, 19 Oct 2024 09:37:58 -0400
Subject: [PATCH 33/39] chore: Sync translations (#3790)

---
 .../addresources/values-ca-rES/strings.xml    |  1 -
 .../addresources/values-fa-rIR/strings.xml    |  1 -
 .../addresources/values-hi-rIN/strings.xml    |  1 -
 .../addresources/values-hr-rHR/strings.xml    |  1 -
 .../addresources/values-is-rIS/strings.xml    |  1 -
 .../addresources/values-iw-rIL/strings.xml    |  1 -
 .../addresources/values-or-rIN/strings.xml    |  1 -
 .../addresources/values-uk-rUA/strings.xml    | 39 ++++++++++---------
 8 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/src/main/resources/addresources/values-ca-rES/strings.xml b/src/main/resources/addresources/values-ca-rES/strings.xml
index 5cac830d10..4620263fed 100644
--- a/src/main/resources/addresources/values-ca-rES/strings.xml
+++ b/src/main/resources/addresources/values-ca-rES/strings.xml
@@ -188,7 +188,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  Per defecte
   
   
   
diff --git a/src/main/resources/addresources/values-fa-rIR/strings.xml b/src/main/resources/addresources/values-fa-rIR/strings.xml
index d8ff921581..1dee473f21 100644
--- a/src/main/resources/addresources/values-fa-rIR/strings.xml
+++ b/src/main/resources/addresources/values-fa-rIR/strings.xml
@@ -181,7 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  پیشفرض
   
   
   
diff --git a/src/main/resources/addresources/values-hi-rIN/strings.xml b/src/main/resources/addresources/values-hi-rIN/strings.xml
index 7eaeff1eb9..93a6ba1f37 100644
--- a/src/main/resources/addresources/values-hi-rIN/strings.xml
+++ b/src/main/resources/addresources/values-hi-rIN/strings.xml
@@ -188,7 +188,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  डिफॉल्ट
   
   
   
diff --git a/src/main/resources/addresources/values-hr-rHR/strings.xml b/src/main/resources/addresources/values-hr-rHR/strings.xml
index acfdbda832..30ad42f16e 100644
--- a/src/main/resources/addresources/values-hr-rHR/strings.xml
+++ b/src/main/resources/addresources/values-hr-rHR/strings.xml
@@ -181,7 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  Zadano
   
   
   
diff --git a/src/main/resources/addresources/values-is-rIS/strings.xml b/src/main/resources/addresources/values-is-rIS/strings.xml
index b8bbba97c4..2d7cfe1e72 100644
--- a/src/main/resources/addresources/values-is-rIS/strings.xml
+++ b/src/main/resources/addresources/values-is-rIS/strings.xml
@@ -181,7 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  Sjálfgefinn
   
   
   
diff --git a/src/main/resources/addresources/values-iw-rIL/strings.xml b/src/main/resources/addresources/values-iw-rIL/strings.xml
index f740352bbf..58ee6e5df9 100644
--- a/src/main/resources/addresources/values-iw-rIL/strings.xml
+++ b/src/main/resources/addresources/values-iw-rIL/strings.xml
@@ -241,7 +241,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  ברירת מחדל
   
   
   
diff --git a/src/main/resources/addresources/values-or-rIN/strings.xml b/src/main/resources/addresources/values-or-rIN/strings.xml
index 73e81d15b1..4281ce7a40 100644
--- a/src/main/resources/addresources/values-or-rIN/strings.xml
+++ b/src/main/resources/addresources/values-or-rIN/strings.xml
@@ -181,7 +181,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
-  ଡିଫଲ୍ଟ
   
   
   
diff --git a/src/main/resources/addresources/values-uk-rUA/strings.xml b/src/main/resources/addresources/values-uk-rUA/strings.xml
index 8ee8b86db0..8068eca7a8 100644
--- a/src/main/resources/addresources/values-uk-rUA/strings.xml
+++ b/src/main/resources/addresources/values-uk-rUA/strings.xml
@@ -644,9 +644,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Приховати \"Зелений екран\"
   Кнопку \"Зелений екран\" приховано
   Кнопка \"Зелений екран\" показується
-  Сховати кнопку хештегу
-  Кнопка хештегу прихована
-  Кнопка хештегу відображається
+  Приховати кнопку хештегу
+  Кнопку хештегу приховано
+  Кнопка хештегу показується
   Приховати пропозиції пошуку
   Пропозиції пошуку приховано
   Пропозиції пошуку показуються
@@ -966,22 +966,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - Відновлення старого інтерфейсу
   
   
-  Встановити початкову сторінку
-  Типово
-  Перегляд каналів
-  Що нового
+  Початкова сторінка
+  За замовчуванням
+  Усі підписки
+  Навігатор
   Ігри
-  17.33.42 - Відновлення старого інтерфейсу
+  Історія
   Бібліотека
-  17.41.37 - Відновлення старого інтерфейсу плейлиста
-  Наживо
+  Відео, які сподобалися
+  Прямі трансляції
   Фільми
   Музика
-  Версія додатку підробиться на старішу версію YouTube.\n\nЦе змінить вигляд і функції додатку, можуть трапитися невідомі побічні ефекти.\n\nЯкщо пізніше вимкнути, рекомендується очистити дані додатку, щоб запобігти помилкам інтерфейсу.
-  Спортивні ігри
-  Підробити версію програми на
+  Пошук на YouTube
+  Спорт
+  Підписки
   Популярне
-  Дивитися пізніше
+  Переглянути пізніше
   
   
   Вимкнути плеєр Shorts при запуску
@@ -1004,11 +1004,12 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Новітній 1
   Новітній 2
   Новітній 3
-  Увімкнути округлені кути
-  Кути округлені
-  Квадратні кути
-  Увімкнути подвійне натискання та затиснення для зміни розміру
-  Подвійне натискання для дії та відновлення розміру вимкнуто
+  Увімкнути закруглені кути
+  Кути закруглені
+  Кути квадратні
+  Подвійне натискання та зміна розміру щипком
+  Подвійне натискання та зміну розміру щипком увімкнено\n\n• Двічі торкніться, щоб збільшити розмір мініплеєра\n• Двічі торкніться ще раз, щоб відновити початковий розмір
+  Подвійне натискання та зміну розміру щипком вимкнуто
   Увімкнути перетягування
   Перетягніть увімкнену\n\nМінімальний плеєр можна перетягнути у будь-який кут екрану
   Перетягування вимкнуто

From 2c5d390fb1275dc3da5a3b912e221b7d594a1561 Mon Sep 17 00:00:00 2001
From: oSumAtrIX 
Date: Wed, 16 Oct 2024 00:27:52 +0200
Subject: [PATCH 34/39] perf(YouTube - GmsCore support): Improve performance by
 using hashsets

---
 .../patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt      | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
index 5969d2c29a..2d15a85be5 100644
--- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
@@ -249,7 +249,7 @@ abstract class BaseGmsCoreSupportPatch(
         /**
          * A list of all permissions.
          */
-        val PERMISSIONS = listOf(
+        val PERMISSIONS = setOf(
             // C2DM / GCM
             "com.google.android.c2dm.permission.RECEIVE",
             "com.google.android.c2dm.permission.SEND",
@@ -266,7 +266,7 @@ abstract class BaseGmsCoreSupportPatch(
         /**
          * All intent actions.
          */
-        val ACTIONS = listOf(
+        val ACTIONS = setOf(
             // location
             "com.google.android.gms.location.places.ui.PICK_PLACE",
             "com.google.android.gms.location.places.GeoDataApi",
@@ -345,7 +345,7 @@ abstract class BaseGmsCoreSupportPatch(
         /**
          * All content provider authorities.
          */
-        val AUTHORITIES = listOf(
+        val AUTHORITIES = setOf(
             // gsf
             "com.google.android.gsf.gservices",
             "com.google.settings",

From 4d39770602b39b6cb399eb0d8c52947b6ebafbb0 Mon Sep 17 00:00:00 2001
From: oSumAtrIX 
Date: Wed, 16 Oct 2024 00:40:20 +0200
Subject: [PATCH 35/39] fix(YouTube - GmsCore support): Add more replacements

---
 .../misc/gms/BaseGmsCoreSupportPatch.kt       | 305 +++++++++++++-----
 1 file changed, 221 insertions(+), 84 deletions(-)

diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
index 2d15a85be5..064bad9a44 100644
--- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
@@ -236,131 +236,268 @@ abstract class BaseGmsCoreSupportPatch(
     /**
      * A collection of permissions, intents and content provider authorities
      * that are present in GmsCore which need to be transformed.
-     *
-     * NOTE: The following were present, but it seems like they are not needed to be transformed:
-     * - com.google.android.gms.chimera.GmsIntentOperationService
-     * - com.google.android.gms.phenotype.internal.IPhenotypeCallbacks
-     * - com.google.android.gms.phenotype.internal.IPhenotypeService
-     * - com.google.android.gms.phenotype.PACKAGE_NAME
-     * - com.google.android.gms.phenotype.UPDATE
-     * - com.google.android.gms.phenotype
      */
     private object Constants {
         /**
-         * A list of all permissions.
+         * All permissions.
          */
         val PERMISSIONS = setOf(
-            // C2DM / GCM
             "com.google.android.c2dm.permission.RECEIVE",
             "com.google.android.c2dm.permission.SEND",
-            "com.google.android.gtalkservice.permission.GTALK_SERVICE",
-
-            // GAuth
+            "com.google.android.gms.auth.api.phone.permission.SEND",
+            "com.google.android.gms.permission.AD_ID",
+            "com.google.android.gms.permission.AD_ID_NOTIFICATION",
+            "com.google.android.gms.permission.CAR_FUEL",
+            "com.google.android.gms.permission.CAR_INFORMATION",
+            "com.google.android.gms.permission.CAR_MILEAGE",
+            "com.google.android.gms.permission.CAR_SPEED",
+            "com.google.android.gms.permission.CAR_VENDOR_EXTENSION",
             "com.google.android.googleapps.permission.GOOGLE_AUTH",
             "com.google.android.googleapps.permission.GOOGLE_AUTH.cp",
             "com.google.android.googleapps.permission.GOOGLE_AUTH.local",
             "com.google.android.googleapps.permission.GOOGLE_AUTH.mail",
             "com.google.android.googleapps.permission.GOOGLE_AUTH.writely",
+            "com.google.android.gtalkservice.permission.GTALK_SERVICE",
+            "com.google.android.providers.gsf.permission.READ_GSERVICES",
         )
 
         /**
          * All intent actions.
          */
         val ACTIONS = setOf(
-            // location
-            "com.google.android.gms.location.places.ui.PICK_PLACE",
-            "com.google.android.gms.location.places.GeoDataApi",
-            "com.google.android.gms.location.places.PlacesApi",
-            "com.google.android.gms.location.places.PlaceDetectionApi",
-            "com.google.android.gms.wearable.MESSAGE_RECEIVED",
-
-            // C2DM / GCM
+            "com.google.android.c2dm.intent.RECEIVE",
             "com.google.android.c2dm.intent.REGISTER",
             "com.google.android.c2dm.intent.REGISTRATION",
             "com.google.android.c2dm.intent.UNREGISTER",
-            "com.google.android.c2dm.intent.RECEIVE",
-            "com.google.iid.TOKEN_REQUEST",
+            "com.google.android.contextmanager.service.ContextManagerService.START",
             "com.google.android.gcm.intent.SEND",
-
-            // car
-            "com.google.android.gms.car.service.START",
-
-            // people
-            "com.google.android.gms.people.service.START",
-
-            // wearable
-            "com.google.android.gms.wearable.BIND",
-
-            // auth
-            "com.google.android.gsf.login",
-            "com.google.android.gsf.action.GET_GLS",
-            "com.google.android.gms.common.account.CHOOSE_ACCOUNT",
-            "com.google.android.gms.auth.login.LOGIN",
+            "com.google.android.gms.accounts.ACCOUNT_SERVICE",
+            "com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS",
+            "com.google.android.gms.accountsettings.action.BROWSE_SETTINGS",
+            "com.google.android.gms.accountsettings.action.VIEW_SETTINGS",
+            "com.google.android.gms.accountsettings.MY_ACCOUNT",
+            "com.google.android.gms.accountsettings.PRIVACY_SETTINGS",
+            "com.google.android.gms.accountsettings.SECURITY_SETTINGS",
+            "com.google.android.gms.ads.gservice.START",
+            "com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION",
+            "com.google.android.gms.ads.service.CACHE",
+            "com.google.android.gms.ads.service.CONSENT_LOOKUP",
+            "com.google.android.gms.ads.service.HTTP",
+            "com.google.android.gms.analytics.service.START",
+            "com.google.android.gms.app.settings.GoogleSettingsLink",
+            "com.google.android.gms.appstate.service.START",
+            "com.google.android.gms.appusage.service.START",
+            "com.google.android.gms.asterism.service.START",
+            "com.google.android.gms.audiomodem.service.AudioModemService.START",
+            "com.google.android.gms.audit.service.START",
+            "com.google.android.gms.auth.account.authapi.START",
+            "com.google.android.gms.auth.account.authenticator.auto.service.START",
+            "com.google.android.gms.auth.account.authenticator.chromeos.START",
+            "com.google.android.gms.auth.account.authenticator.tv.service.START",
+            "com.google.android.gms.auth.account.data.service.START",
             "com.google.android.gms.auth.api.credentials.PICKER",
             "com.google.android.gms.auth.api.credentials.service.START",
-            "com.google.android.gms.auth.service.START",
-            "com.google.firebase.auth.api.gms.service.START",
+            "com.google.android.gms.auth.api.identity.service.authorization.START",
+            "com.google.android.gms.auth.api.identity.service.credentialsaving.START",
+            "com.google.android.gms.auth.api.identity.service.signin.START",
+            "com.google.android.gms.auth.api.phone.service.InternalService.START",
+            "com.google.android.gms.auth.api.signin.service.START",
             "com.google.android.gms.auth.be.appcert.AppCertService",
-
-            // fido
+            "com.google.android.gms.auth.blockstore.service.START",
+            "com.google.android.gms.auth.config.service.START",
+            "com.google.android.gms.auth.cryptauth.cryptauthservice.START",
+            "com.google.android.gms.auth.GOOGLE_SIGN_IN",
+            "com.google.android.gms.auth.login.LOGIN",
+            "com.google.android.gms.auth.proximity.devicesyncservice.START",
+            "com.google.android.gms.auth.proximity.securechannelservice.START",
+            "com.google.android.gms.auth.proximity.START",
+            "com.google.android.gms.auth.service.START",
+            "com.google.android.gms.backup.ACTION_BACKUP_SETTINGS",
+            "com.google.android.gms.backup.G1_BACKUP",
+            "com.google.android.gms.backup.G1_RESTORE",
+            "com.google.android.gms.backup.GMS_MODULE_RESTORE",
+            "com.google.android.gms.beacon.internal.IBleService.START",
+            "com.google.android.gms.car.service.START",
+            "com.google.android.gms.carrierauth.service.START",
+            "com.google.android.gms.cast.firstparty.START",
+            "com.google.android.gms.cast.remote_display.service.START",
+            "com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE",
+            "com.google.android.gms.cast_mirroring.service.START",
+            "com.google.android.gms.checkin.BIND_TO_SERVICE",
+            "com.google.android.gms.chromesync.service.START",
+            "com.google.android.gms.clearcut.service.START",
+            "com.google.android.gms.common.account.CHOOSE_ACCOUNT",
+            "com.google.android.gms.common.download.START",
+            "com.google.android.gms.common.service.START",
+            "com.google.android.gms.common.telemetry.service.START",
+            "com.google.android.gms.config.START",
+            "com.google.android.gms.constellation.service.START",
+            "com.google.android.gms.credential.manager.service.firstparty.START",
+            "com.google.android.gms.deviceconnection.service.START",
+            "com.google.android.gms.drive.ApiService.RESET_AFTER_BOOT",
+            "com.google.android.gms.drive.ApiService.START",
+            "com.google.android.gms.drive.ApiService.STOP",
+            "com.google.android.gms.droidguard.service.INIT",
+            "com.google.android.gms.droidguard.service.PING",
+            "com.google.android.gms.droidguard.service.START",
+            "com.google.android.gms.enterprise.loader.service.START",
+            "com.google.android.gms.facs.cache.service.START",
+            "com.google.android.gms.facs.internal.service.START",
+            "com.google.android.gms.feedback.internal.IFeedbackService",
+            "com.google.android.gms.fido.credentialstore.internal_service.START",
             "com.google.android.gms.fido.fido2.privileged.START",
-
-            // gass
-            "com.google.android.gms.gass.START",
-
-            // games
-            "com.google.android.gms.games.service.START",
+            "com.google.android.gms.fido.fido2.regular.START",
+            "com.google.android.gms.fido.fido2.zeroparty.START",
+            "com.google.android.gms.fido.sourcedevice.service.START",
+            "com.google.android.gms.fido.targetdevice.internal_service.START",
+            "com.google.android.gms.fido.u2f.privileged.START",
+            "com.google.android.gms.fido.u2f.thirdparty.START",
+            "com.google.android.gms.fido.u2f.zeroparty.START",
+            "com.google.android.gms.fitness.BleApi",
+            "com.google.android.gms.fitness.ConfigApi",
+            "com.google.android.gms.fitness.GoalsApi",
+            "com.google.android.gms.fitness.GoogleFitnessService.START",
+            "com.google.android.gms.fitness.HistoryApi",
+            "com.google.android.gms.fitness.InternalApi",
+            "com.google.android.gms.fitness.RecordingApi",
+            "com.google.android.gms.fitness.SensorsApi",
+            "com.google.android.gms.fitness.SessionsApi",
+            "com.google.android.gms.fonts.service.START",
+            "com.google.android.gms.freighter.service.START",
+            "com.google.android.gms.games.internal.connect.service.START",
             "com.google.android.gms.games.PLAY_GAMES_UPGRADE",
-
-            // chimera
-            "com.google.android.gms.chimera",
-
-            // fonts
-            "com.google.android.gms.fonts",
-
-            // phenotype
-            "com.google.android.gms.phenotype.service.START",
-
-            // location
-            "com.google.android.gms.location.reporting.service.START",
-
-            // misc
+            "com.google.android.gms.games.service.START",
+            "com.google.android.gms.gass.START",
             "com.google.android.gms.gmscompliance.service.START",
-            "com.google.android.gms.oss.licenses.service.START",
-            "com.google.android.gms.tapandpay.service.BIND",
-            "com.google.android.gms.measurement.START",
-            "com.google.android.gms.languageprofile.service.START",
-            "com.google.android.gms.clearcut.service.START",
+            "com.google.android.gms.googlehelp.HELP",
+            "com.google.android.gms.googlehelp.service.GoogleHelpService.START",
+            "com.google.android.gms.growth.service.START",
+            "com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START",
+            "com.google.android.gms.icing.INDEX_SERVICE",
             "com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE",
-            "com.google.android.gms.accountsettings.action.VIEW_SETTINGS",
-
-            // potoken
+            "com.google.android.gms.identity.service.BIND",
+            "com.google.android.gms.inappreach.service.START",
+            "com.google.android.gms.instantapps.START",
+            "com.google.android.gms.kids.service.START",
+            "com.google.android.gms.languageprofile.service.START",
+            "com.google.android.gms.learning.internal.dynamitesupport.START",
+            "com.google.android.gms.learning.intservice.START",
+            "com.google.android.gms.learning.predictor.START",
+            "com.google.android.gms.learning.trainer.START",
+            "com.google.android.gms.learning.training.background.START",
+            "com.google.android.gms.location.places.GeoDataApi",
+            "com.google.android.gms.location.places.PlaceDetectionApi",
+            "com.google.android.gms.location.places.PlacesApi",
+            "com.google.android.gms.location.reporting.service.START",
+            "com.google.android.gms.location.settings.LOCATION_HISTORY",
+            "com.google.android.gms.location.settings.LOCATION_REPORTING_SETTINGS",
+            "com.google.android.gms.locationsharing.api.START",
+            "com.google.android.gms.locationsharingreporter.service.START",
+            "com.google.android.gms.lockbox.service.START",
+            "com.google.android.gms.matchstick.lighter.service.START",
+            "com.google.android.gms.mdm.services.DeviceManagerApiService.START",
+            "com.google.android.gms.mdm.services.START",
+            "com.google.android.gms.mdns.service.START",
+            "com.google.android.gms.measurement.START",
+            "com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START",
+            "com.google.android.gms.nearby.connection.service.START",
+            "com.google.android.gms.nearby.fastpair.START",
+            "com.google.android.gms.nearby.messages.service.NearbyMessagesService.START",
+            "com.google.android.gms.nearby.sharing.service.NearbySharingService.START",
+            "com.google.android.gms.nearby.sharing.START_SERVICE",
+            "com.google.android.gms.notifications.service.START",
+            "com.google.android.gms.ocr.service.internal.START",
+            "com.google.android.gms.ocr.service.START",
+            "com.google.android.gms.oss.licenses.service.START",
+            "com.google.android.gms.payse.service.BIND",
+            "com.google.android.gms.people.contactssync.service.START",
+            "com.google.android.gms.people.service.START",
+            "com.google.android.gms.phenotype.service.START",
+            "com.google.android.gms.photos.autobackup.service.START",
+            "com.google.android.gms.playlog.service.START",
+            "com.google.android.gms.plus.service.default.INTENT",
+            "com.google.android.gms.plus.service.image.INTENT",
+            "com.google.android.gms.plus.service.internal.START",
+            "com.google.android.gms.plus.service.START",
             "com.google.android.gms.potokens.service.START",
-
-            // droidguard/ safetynet
-            "com.google.android.gms.droidguard.service.START",
+            "com.google.android.gms.pseudonymous.service.START",
+            "com.google.android.gms.rcs.START",
+            "com.google.android.gms.reminders.service.START",
+            "com.google.android.gms.romanesco.MODULE_BACKUP_AGENT",
+            "com.google.android.gms.romanesco.service.START",
             "com.google.android.gms.safetynet.service.START",
+            "com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE",
+            "com.google.android.gms.search.service.SEARCH_AUTH_START",
+            "com.google.android.gms.semanticlocation.service.START_ODLH",
+            "com.google.android.gms.sesame.service.BIND",
+            "com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS",
+            "com.google.android.gms.setup.auth.SecondDeviceAuth.START",
+            "com.google.android.gms.signin.service.START",
+            "com.google.android.gms.smartdevice.d2d.SourceDeviceService.START",
+            "com.google.android.gms.smartdevice.d2d.TargetDeviceService.START",
+            "com.google.android.gms.smartdevice.directtransfer.SourceDirectTransferService.START",
+            "com.google.android.gms.smartdevice.directtransfer.TargetDirectTransferService.START",
+            "com.google.android.gms.smartdevice.postsetup.PostSetupService.START",
+            "com.google.android.gms.smartdevice.setup.accounts.AccountsService.START",
+            "com.google.android.gms.smartdevice.wifi.START_WIFI_HELPER_SERVICE",
+            "com.google.android.gms.social.location.activity.service.START",
+            "com.google.android.gms.speech.service.START",
+            "com.google.android.gms.statementservice.EXECUTE",
+            "com.google.android.gms.stats.ACTION_UPLOAD_DROPBOX_ENTRIES",
+            "com.google.android.gms.tapandpay.service.BIND",
+            "com.google.android.gms.telephonyspam.service.START",
+            "com.google.android.gms.testsupport.service.START",
+            "com.google.android.gms.thunderbird.service.START",
+            "com.google.android.gms.trustagent.BridgeApi.START",
+            "com.google.android.gms.trustagent.StateApi.START",
+            "com.google.android.gms.trustagent.trustlet.trustletmanagerservice.BIND",
+            "com.google.android.gms.trustlet.bluetooth.service.BIND",
+            "com.google.android.gms.trustlet.connectionlessble.service.BIND",
+            "com.google.android.gms.trustlet.face.service.BIND",
+            "com.google.android.gms.trustlet.nfc.service.BIND",
+            "com.google.android.gms.trustlet.onbody.service.BIND",
+            "com.google.android.gms.trustlet.place.service.BIND",
+            "com.google.android.gms.trustlet.voiceunlock.service.BIND",
+            "com.google.android.gms.udc.service.START",
+            "com.google.android.gms.update.START_API_SERVICE",
+            "com.google.android.gms.update.START_SERVICE",
+            "com.google.android.gms.update.START_SINGLE_USER_API_SERVICE",
+            "com.google.android.gms.update.START_TV_API_SERVICE",
+            "com.google.android.gms.usagereporting.service.START",
+            "com.google.android.gms.userlocation.service.START",
+            "com.google.android.gms.vehicle.cabin.service.START",
+            "com.google.android.gms.vehicle.climate.service.START",
+            "com.google.android.gms.vehicle.info.service.START",
+            "com.google.android.gms.wallet.service.BIND",
+            "com.google.android.gms.walletp2p.service.firstparty.BIND",
+            "com.google.android.gms.walletp2p.service.zeroparty.BIND",
+            "com.google.android.gms.wearable.BIND",
+            "com.google.android.gms.wearable.BIND_LISTENER",
+            "com.google.android.gms.wearable.DATA_CHANGED",
+            "com.google.android.gms.wearable.MESSAGE_RECEIVED",
+            "com.google.android.gms.wearable.NODE_CHANGED",
+            "com.google.android.gsf.action.GET_GLS",
+            "com.google.android.location.settings.LOCATION_REPORTING_SETTINGS",
+            "com.google.android.mdd.service.START",
+            "com.google.android.mdh.service.listener.START",
+            "com.google.android.mdh.service.START",
+            "com.google.android.mobstore.service.START",
+            "com.google.firebase.auth.api.gms.service.START",
+            "com.google.firebase.dynamiclinks.service.START",
+            "com.google.iid.TOKEN_REQUEST",
+            "com.google.android.gms.location.places.ui.PICK_PLACE",
         )
 
         /**
          * All content provider authorities.
          */
         val AUTHORITIES = setOf(
-            // gsf
-            "com.google.android.gsf.gservices",
-            "com.google.settings",
-
-            // auth
             "com.google.android.gms.auth.accounts",
-
-            // chimera
             "com.google.android.gms.chimera",
-
-            // fonts
             "com.google.android.gms.fonts",
-
-            // phenotype
             "com.google.android.gms.phenotype",
+            "com.google.android.gsf.gservices",
+            "com.google.settings",
         )
     }
 

From 021d8584a7f5a6d1a028c5d18dc91a3b988b2884 Mon Sep 17 00:00:00 2001
From: oSumAtrIX 
Date: Wed, 16 Oct 2024 01:39:59 +0200
Subject: [PATCH 36/39] fix(YouTube - GmsCore support): Remove unclear patch
 changes

---
 .../patches/music/misc/gms/GmsCoreSupportPatch.kt         | 3 ---
 .../gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt   | 8 --------
 .../patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt    | 7 +------
 .../gms/fingerprints/CastDynamiteModuleFingerprint.kt     | 8 --------
 .../patches/youtube/misc/gms/GmsCoreSupportPatch.kt       | 4 +---
 .../gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt   | 8 --------
 6 files changed, 2 insertions(+), 36 deletions(-)
 delete mode 100644 src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt
 delete mode 100644 src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/CastDynamiteModuleFingerprint.kt
 delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt

diff --git a/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt
index 1b6a7a6ec8..28c9353710 100644
--- a/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt
@@ -3,7 +3,6 @@ package app.revanced.patches.music.misc.gms
 import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
 import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
 import app.revanced.patches.music.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
-import app.revanced.patches.music.misc.gms.fingerprints.CastDynamiteModuleV2Fingerprint
 import app.revanced.patches.music.misc.gms.fingerprints.MusicActivityOnCreateFingerprint
 import app.revanced.patches.music.misc.gms.fingerprints.PrimeMethodFingerprint
 import app.revanced.patches.music.misc.integrations.IntegrationsPatch
@@ -16,7 +15,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
     toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
     primeMethodFingerprint = PrimeMethodFingerprint,
     earlyReturnFingerprints = setOf(
-        CastDynamiteModuleV2Fingerprint,
         CastContextFetchFingerprint,
     ),
     mainActivityOnCreateFingerprint = MusicActivityOnCreateFingerprint,
@@ -26,7 +24,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
         CompatiblePackage("com.google.android.apps.youtube.music"),
     ),
     fingerprints = setOf(
-        CastDynamiteModuleV2Fingerprint,
         CastContextFetchFingerprint,
         PrimeMethodFingerprint,
     ),
diff --git a/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt
deleted file mode 100644
index 0249a98136..0000000000
--- a/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.music.misc.gms.fingerprints
-
-
-import app.revanced.patcher.fingerprint.MethodFingerprint
-
-internal object CastDynamiteModuleV2Fingerprint : MethodFingerprint(
-    strings = listOf("Failed to load module via V2: ")
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
index 064bad9a44..6d2d6427b7 100644
--- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt
@@ -11,7 +11,6 @@ import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch
 import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.ACTIONS
 import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.AUTHORITIES
 import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.PERMISSIONS
-import app.revanced.patches.shared.misc.gms.fingerprints.CastDynamiteModuleFingerprint
 import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint
 import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint.GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME
 import app.revanced.patches.shared.misc.gms.fingerprints.GooglePlayUtilityFingerprint
@@ -69,7 +68,6 @@ abstract class BaseGmsCoreSupportPatch(
         GmsCoreSupportFingerprint,
         GooglePlayUtilityFingerprint,
         ServiceCheckFingerprint,
-        CastDynamiteModuleFingerprint,
         mainActivityOnCreateFingerprint,
     ) + fingerprints,
     requiresIntegrations = true,
@@ -104,10 +102,7 @@ abstract class BaseGmsCoreSupportPatch(
         // Return these methods early to prevent the app from crashing.
         earlyReturnFingerprints.returnEarly()
         ServiceCheckFingerprint.returnEarly()
-        // Not all apps have CastDynamiteModule, so we need to check if it's present.
-        if (CastDynamiteModuleFingerprint.result != null) {
-            CastDynamiteModuleFingerprint.returnEarly()
-        }
+
         // Google Play Utility is not present in all apps, so we need to check if it's present.
         if (GooglePlayUtilityFingerprint.result != null) {
             GooglePlayUtilityFingerprint.returnEarly()
diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/CastDynamiteModuleFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/CastDynamiteModuleFingerprint.kt
deleted file mode 100644
index 7773e378d5..0000000000
--- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/CastDynamiteModuleFingerprint.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.shared.misc.gms.fingerprints
-
-
-import app.revanced.patcher.fingerprint.MethodFingerprint
-
-internal object CastDynamiteModuleFingerprint : MethodFingerprint(
-    strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl")
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt
index e66efc9c60..5ecd694f8d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt
@@ -7,7 +7,6 @@ import app.revanced.patches.youtube.misc.fix.playback.SpoofVideoStreamsPatch
 import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME
 import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
 import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
-import app.revanced.patches.youtube.misc.gms.fingerprints.CastDynamiteModuleV2Fingerprint
 import app.revanced.patches.youtube.misc.gms.fingerprints.PrimeMethodFingerprint
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.shared.fingerprints.MainActivityOnCreateFingerprint
@@ -18,7 +17,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
     toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME,
     primeMethodFingerprint = PrimeMethodFingerprint,
     earlyReturnFingerprints = setOf(
-        CastDynamiteModuleV2Fingerprint,
         CastContextFetchFingerprint,
     ),
     mainActivityOnCreateFingerprint = MainActivityOnCreateFingerprint,
@@ -41,7 +39,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
         ),
     ),
     fingerprints = setOf(
-        CastDynamiteModuleV2Fingerprint,
+
         CastContextFetchFingerprint,
         PrimeMethodFingerprint,
     ),
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt
deleted file mode 100644
index d0a4631766..0000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/fingerprints/CastDynamiteModuleV2Fingerprint.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.youtube.misc.gms.fingerprints
-
-
-import app.revanced.patcher.fingerprint.MethodFingerprint
-
-internal object CastDynamiteModuleV2Fingerprint : MethodFingerprint(
-    strings = listOf("Failed to load module via V2: ")
-)
\ No newline at end of file

From a371631972cef238a272e92e726ec7e80895c219 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Sat, 19 Oct 2024 10:27:11 -0400
Subject: [PATCH 37/39] chore: Sync translations (#3791)

---
 .../addresources/values-ar-rSA/strings.xml    | 30 +++++++++----------
 .../addresources/values-ko-rKR/strings.xml    | 27 +++++++++++++++++
 .../addresources/values-uk-rUA/strings.xml    | 16 +++++-----
 3 files changed, 50 insertions(+), 23 deletions(-)

diff --git a/src/main/resources/addresources/values-ar-rSA/strings.xml b/src/main/resources/addresources/values-ar-rSA/strings.xml
index 9ec87c816b..a396e2bb49 100644
--- a/src/main/resources/addresources/values-ar-rSA/strings.xml
+++ b/src/main/resources/addresources/values-ar-rSA/strings.xml
@@ -644,9 +644,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   إخفاء زر الشاشة الخضراء
   تم إخفاء زر الشاشة الخضراء
   يتم عرض زر الشاشة الخضراء
-  إخفاء زر Hashg
-  زر علامة هاشج مخفي
-  يتم عرض زر الوسم
+  إخفاء زر الهاشتاج
+  تم إخفاء زر الهاشتاج
+  يتم عرض زر الهاشتاج
   إخفاء اقتراحات البحث
   تم إخفاء اقتراحات البحث
   يتم عرض اقتراحات البحث
@@ -981,7 +981,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   الرياضة
   الاشتراكات
   المحتوى الرائج
-  شاهد لاحقاً
+  شاهد لاحقًا
   
   
   تعطيل استئناف مشغل Shorts
@@ -1004,21 +1004,21 @@ This is because Crowdin requires temporarily flattening this file and removing t
   حديث 1
   حديث 2
   حديث 3
-  تمكين زوايا مستديرة
-  يتم تدوير الزوايا
+  تمكين الزوايا المستديرة
+  الزوايا مستديرة
   الزوايا مربعة
-  تمكين النقر المزدوج و الدبوس لتغيير الحجم
-  تم تمكين إجراء الضغط المزدوج والدبوس لتغيير الحجم\n\n• النقر المزدوج لزيادة حجم اللاعب الصغير\n• النقر المزدوج مرة أخرى لاستعادة الحجم الأصلي
-  إجراء النقر المزدوج والدبوس لتغيير الحجم معطل
+  تمكين النقر المزدوج والضغط لتغيير الحجم
+  تم تمكين إجراء الضغط المزدوج والضغط لتغيير الحجم\n\n• النقر المزدوج لزيادة حجم المشغل المصغر\n• النقر المزدوج مرة أخرى لاستعادة الحجم الأصلي
+  إجراء النقر المزدوج والضغط لتغيير الحجم معطل
   تمكين السحب والإفلات
-  السحب والإسقاط مفعلان\n\nيمكن سحب اللاعب الصغير إلى أي زاوية من الشاشة
-  تم تعطيل السحب والإسقاط
+  السحب والإفلات مفعلان\n\nيمكن سحب المشغل المصغر إلى أي زاوية من الشاشة
+  تم تعطيل السحب والإفلات
   إخفاء زر الإغلاق
-  زر الإغلاق مخفي
+  تم إخفاء زر الإغلاق
   يتم عرض زر الإغلاق
   إخفاء أزرار التوسيع والإغلاق
-  الأزرار مخفية\n\nمرر للتوسع أو الإغلاق
-  تظهر أزرار التمديد والإغلاق
+  تم إخفاء الأزرار\n\nمرر للتوسيع أو الإغلاق
+  يتم عرض أزرار التوسيع والإغلاق
   إخفاء النصوص الفرعية
   تم إخفاء النصوص الفرعية
   يتم عرض النصوص الفرعية
@@ -1026,7 +1026,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   تم إخفاء تخطي للأمام والخلف
   يتم عرض تخطي للأمام والخلف
   الحجم الأولي
-  المبدئي على حجم الشاشة، بالبكسل
+  الحجم الأولي على الشاشة، بالبكسل
   حجم البكسل يجب أن يكون بين %1$s و %2$s
   شفافية الواجهة
   قيمة الشفافية بين 0-100، حيث يكون 0 شفاف
diff --git a/src/main/resources/addresources/values-ko-rKR/strings.xml b/src/main/resources/addresources/values-ko-rKR/strings.xml
index def0e58229..2626309635 100644
--- a/src/main/resources/addresources/values-ko-rKR/strings.xml
+++ b/src/main/resources/addresources/values-ko-rKR/strings.xml
@@ -645,6 +645,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   그린 스크린 버튼 숨기기
   그린 스크린 버튼이 숨겨집니다
   그린 스크린 버튼이 표시됩니다
+  해시 태그 숨기기
+  해시 태그가 숨겨집니다
+  해시 태그가 표시됩니다
   검색 추천 숨기기
   검색 추천이 숨겨집니다
   검색 추천이 표시됩니다
@@ -966,13 +969,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   앱 시작 페이지 변경하기
   SponsorBlock 활성화
+  채널 둘러보기
   플레이어에서 구간 투표 버튼을 표시합니다
+  게임
   일반적인 건너뛰기 버튼을 표시합니다
   나 (보관함)
   최소화된 건너뛰기 버튼을 표시합니다
+  실시간
+  영화
+  음악
   외관
+  스포츠
   투표 버튼 표시하기
   자동으로 건너뛰기 버튼 숨기기
+  나중에 볼 동영상
   
   
   앱을 시작할 때, Shorts 플레이어 비활성화하기
@@ -995,7 +1005,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   최신 스타일 1
   최신 스타일 2
   최신 스타일 3
+  둥근 모서리 활성화하기
+  모서리를 둥글게 활성화합니다
+  모서리를 각지게 활성화합니다
+  두 번 탭하고 핀치하여 크기 조정 활성화하기
+  두 번 누르기 동작 및 핀치하여 크기 조정을 활성화합니다\n\n• 두 번 눌러서 미니 플레이어 크기를 확대합니다\n• 다시 두 번 눌러서 원래 크기로 복원합니다
+  두 번 누르기 동작 및 핀치하여 크기 조정을 비활성화합니다
+  드래그 & 드롭 활성화하기
+  드래그 & 드롭이 활성화합니다\n\n미니 플레이어를 화면의 어느 곳이든 드래그할 수 있습니다
+  드래그 & 드롭을 비활성화합니다
+  닫기 버튼 숨기기
+  닫기 버튼이 숨겨집니다
+  닫기 버튼이 표시됩니다
   \'펼치기\' & \'닫기\' 버튼 숨기기
+  버튼들이 숨겨집니다\n\n미니 플레이어를 펼치거나 닫을 수 있습니다
   \'펼치기\' & \'닫기\' 버튼이 표시됩니다
   서브텍스트 숨기기
   서브텍스트가 숨겨집니다\n• 왼쪽 하단에서 표시되는 \'유료 광고 포함\'과 같은 라벨
@@ -1003,6 +1026,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   \'되감기\' & \'빨리 감기\' 버튼 숨기기
   \'되감기\' & \'빨리 감기\' 버튼이 숨겨집니다
   \'되감기\' & \'빨리 감기\' 버튼이 표시됩니다
+  크기 초기화하기
+  화면 크기의 이니셜, 픽셀 단위을 초기화합니다
+  픽셀 크기는 %1$s-%2$s 사이어야 합니다
   미니 플레이어 오버레이 불투명도
   불투명도 값은 0-100 사이이며, 0은 투명입니다
   미니 플레이어 오버레이 불투명도는 0-100 사이여야 합니다
@@ -1018,6 +1044,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   기본 재생바 색상을 활성화합니다
   사용자 정의 재생바 색상 설정
   재생바 색상
+  잘못된 재생바 색상값입니다
   
   
   이미지 표시 제한 국가 우회하기
diff --git a/src/main/resources/addresources/values-uk-rUA/strings.xml b/src/main/resources/addresources/values-uk-rUA/strings.xml
index 8068eca7a8..b5bba6597d 100644
--- a/src/main/resources/addresources/values-uk-rUA/strings.xml
+++ b/src/main/resources/addresources/values-uk-rUA/strings.xml
@@ -1011,14 +1011,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Подвійне натискання та зміну розміру щипком увімкнено\n\n• Двічі торкніться, щоб збільшити розмір мініплеєра\n• Двічі торкніться ще раз, щоб відновити початковий розмір
   Подвійне натискання та зміну розміру щипком вимкнуто
   Увімкнути перетягування
-  Перетягніть увімкнену\n\nМінімальний плеєр можна перетягнути у будь-який кут екрану
+  Перетягування увімкнено\n\nМініплеєр можна перетягнути в будь-який кут екрану
   Перетягування вимкнуто
   Приховати кнопку закриття
-  Кнопка закриття прихована
-  Кнопка закриття відображається
-  Приховати кнопки розгортання та закриття
-  Кнопки приховані\n\nПроведіть щоб розгорнути або закрити
-  Розгорнути і закрити кнопки показано
+  Кнопку закриття мініплеєру приховано
+  Кнопка закриття мініплеєру показується
+  Кнопки розгортання та закриття
+  Кнопки розгортання та закриття приховано\n\nПроведіть по мініплеєру, щоб розгорнути чи закрити
+  Кнопки розгортання та закриття показуються
   Приховати підтексти
   Підтексти в мініплеєрі приховано
   Підтексти в мініплеєрі показуються
@@ -1026,7 +1026,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Кнопки перемотування вперед та назад в мініплеєрі приховано
   Кнопки перемотування вперед та назад в мініплеєрі показуються
   Початковий розмір
-  Початковий розмір екрану в пікселях
+  Початковий розмір мініплеєра на екрані, в пікселях
   Розмір у пікселях повинен бути від %1$s до %2$s
   Затемнення мініплеєра
   Значення затемнення при натисканні на мініплеєр в межах 0-100, де 0 це прозоро
@@ -1043,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Показується оригінальний колір панелі прогресу відтворення
   Користувацький колір панелі прогресу
   Редагувати колір панелі прогресу відтворення
-  Недійсне значення кольору панелі прогресу відтворення
+  Недійсне значення кольору панелі прогресу
   
   
   Змінити хост зображень

From c69a41041bed310db869ec7bcde5f8717bb4856f Mon Sep 17 00:00:00 2001
From: semantic-release-bot 
Date: Sat, 19 Oct 2024 14:50:26 +0000
Subject: [PATCH 38/39] chore: Release v4.17.0-dev.13 [skip ci]

# [4.17.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.12...v4.17.0-dev.13) (2024-10-19)

### Bug Fixes

* **YouTube - GmsCore support:** Add more replacements ([4d39770](https://github.com/ReVanced/revanced-patches/commit/4d39770602b39b6cb399eb0d8c52947b6ebafbb0))
* **YouTube - GmsCore support:** Remove unclear patch changes ([021d858](https://github.com/ReVanced/revanced-patches/commit/021d8584a7f5a6d1a028c5d18dc91a3b988b2884))

### Performance Improvements

* **YouTube - GmsCore support:** Improve performance by using hashsets ([2c5d390](https://github.com/ReVanced/revanced-patches/commit/2c5d390fb1275dc3da5a3b912e221b7d594a1561))
---
 CHANGELOG.md      | 13 +++++++++++++
 gradle.properties |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5aaba89536..88b6348ba5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+# [4.17.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.12...v4.17.0-dev.13) (2024-10-19)
+
+
+### Bug Fixes
+
+* **YouTube - GmsCore support:** Add more replacements ([4d39770](https://github.com/ReVanced/revanced-patches/commit/4d39770602b39b6cb399eb0d8c52947b6ebafbb0))
+* **YouTube - GmsCore support:** Remove unclear patch changes ([021d858](https://github.com/ReVanced/revanced-patches/commit/021d8584a7f5a6d1a028c5d18dc91a3b988b2884))
+
+
+### Performance Improvements
+
+* **YouTube - GmsCore support:** Improve performance by using hashsets ([2c5d390](https://github.com/ReVanced/revanced-patches/commit/2c5d390fb1275dc3da5a3b912e221b7d594a1561))
+
 # [4.17.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.17.0-dev.11...v4.17.0-dev.12) (2024-10-19)
 
 
diff --git a/gradle.properties b/gradle.properties
index 5214f0d447..e6c56c8a53 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
 org.gradle.parallel = true
 org.gradle.caching = true
 kotlin.code.style = official
-version = 4.17.0-dev.12
+version = 4.17.0-dev.13

From 99862facce2c11da0f4c062852451b6291574ef3 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Sat, 19 Oct 2024 21:29:04 -0400
Subject: [PATCH 39/39] chore: Sync translations (#3792)

---
 .../addresources/values-az-rAZ/strings.xml    | 30 +++++++++++-
 .../addresources/values-el-rGR/strings.xml    | 48 +++++++++----------
 .../addresources/values-hu-rHU/strings.xml    | 29 +++++++++++
 .../addresources/values-ko-rKR/strings.xml    | 16 +++----
 .../addresources/values-lt-rLT/strings.xml    |  3 ++
 .../addresources/values-sr-rCS/strings.xml    | 37 ++++++++++++--
 .../addresources/values-sr-rSP/strings.xml    | 37 ++++++++++++--
 .../addresources/values-zh-rTW/strings.xml    | 32 +++++++++++--
 8 files changed, 185 insertions(+), 47 deletions(-)

diff --git a/src/main/resources/addresources/values-az-rAZ/strings.xml b/src/main/resources/addresources/values-az-rAZ/strings.xml
index e3141b5075..e76bb708de 100644
--- a/src/main/resources/addresources/values-az-rAZ/strings.xml
+++ b/src/main/resources/addresources/values-az-rAZ/strings.xml
@@ -644,6 +644,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   \"Yaşıl ekran\" düyməsini gizlət
   \"Yaşıl ekran\" düyməsi gizlidir
   \"Yaşıl ekran\" düyməsi göstərilir
+  Hashtag düyməsini gizlət
+  Hashtag düyməsi gizlidir
+  Hashtag düyməsi göstərilir
   Axtarış təkliflərini gizlət
   Axtarış təklifləri gizlədilib
   Axtarış təklifləri göstərilir
@@ -965,13 +968,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   Başlanğıc səhifəsini tənzimlə
   İlkin
+  Kəşf edilən kanallar
   Kəşf et
+  Oyun
   Tarixçə
   Kitabxana
   Bəyənilən videolar
-  Axtar
+  Canlı
+  Filmlər
+  Musiqi
+  Axtarış
+  İdman
   Abunəliklər
   Trenddə olan
+  Sonra izlə
   
   
   Shorts oynadıcı başladıcını bağla
@@ -994,7 +1004,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Müasir 1
   Müasir 2
   Müasir 3
+  Dairəvi küncləri aktivləşdir
+  Künclər dövrələnir
+  Künclər kvadratdır
+  Ölçüsünü dəyişmək üçün iki dəfə toxun və çimdiklə
+  İki dəfə kliklə fəaliyyəti və ölçüsünü dəyişmək üçün çimdiklə, aktivdir\n\n• Kiçik oynadıcı ölçüsün artırmaq üçün iki dəfə toxunun\n• Əsl ölçüsün bərpa etmək üçün təkrar iki dəfə toxun
+  Ölçüsün dəyişmək üçün cüt kliklə və çimdiklə bağlıdır
+  Çəkmə və buraxma funksiyasın aktivləşdir
+  Çəkmə və buraxma aktivdir\n\nMinipleyeri ekranın istənilən küncünə çəkmək olar
+  Çəkmə və buraxma bağlıdır
+  Bağlama düyməsin gizlət
+  Bağlama düyməsi gizlidir
+  Bağlama düyməsi göstərilir
   Genişləndir və bağla düymələrini gizlət
+  Düymələr gizlədilib\n\nGenişləndirmək və ya bağlamaq üçün sürüşdür
   Genişləndirmə və bağlama düymələri göstərilir
   Alt mətnləri gizlət
   Alt mətnlər gizlədilir
@@ -1002,6 +1025,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   İrəli və geri ötür düymələrini gizlət
   İrəli və geri ötürücülər gizlidir
   İrəli və geri ötürücülər göstərilir
+  İlkin ölçü
+  Ekran ölçüsündə, piksellərdə ilkin ölçü
+  Piksel ölçüsü %1$s və %2$s arası olmalıdır
   Örtük qeyri-şəffaflığı
   0-100 arasında qeyri-şəffaflıq dəyəri, burada 0 şəffafdır
   Kiçik Oynadıcı örtük qeyri-şəffaflığı 0-100 arası olmalıdır
@@ -1017,7 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Orijinal axtarma çubuğu rəngi göstərilir
   Fərdi axtarma çubuğu rəngi
   Axtarma çubuğu rəngi
-  Yararsız zaman çubuğu rəng dəyəri
+  Etibarsız axtarış çubuğu rəng dəyəri
   
   
   Təsvir bölgə məhdudiyyətlərini ötür
diff --git a/src/main/resources/addresources/values-el-rGR/strings.xml b/src/main/resources/addresources/values-el-rGR/strings.xml
index faa10a1c66..be889d110d 100644
--- a/src/main/resources/addresources/values-el-rGR/strings.xml
+++ b/src/main/resources/addresources/values-el-rGR/strings.xml
@@ -641,12 +641,12 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Κουμπί επερχόμενης πρεμιέρας/ζωντανής ροής
   Κρυμμένο
   Εμφανίζεται
-  Κουμπί «Πράσινη οθόνη»
+  Κουμπί «Green screen»
   Κρυμμένο
   Εμφανίζεται
-  Απόκρυψη κουμπιού hashtag
-  Το κουμπί Hashtag είναι κρυμμένο
-  Εμφανίζεται το κουμπί Hashtag
+  Κουμπί hashtag
+  Κρυμμένο
+  Εμφανίζεται
   Προτάσεις αναζήτησης
   Κρυμμένες
   Εμφανίζονται
@@ -967,21 +967,21 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   Αλλαγή της αρχικής σελίδας
-  Προεπιλογές
-  Αναζήτηση καναλιών
+  Προεπιλογή
+  Περιήγηση καναλιών
   Εξερεύνηση
-  Παιχνίδι
+  Παιχνίδια
   Ιστορικό
   Βιβλιοθήκη
   Βίντεο που σας αρέσουν
-  Ζωντανά
+  Live
   Ταινίες
   Μουσική
   Αναζήτηση
-  Αθλητισμός
+  Αθλητικά
   Εγγραφές
   Τάσεις
-  Δείτε αργότερα
+  Παρακολούθηση αργότερα
   
   
   Απενεργοποίηση συνέχισης των Shorts
@@ -1004,21 +1004,21 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Μοντέρνος 1
   Μοντέρνος 2
   Μοντέρνος 3
-  Ενεργοποίηση στρογγυλεμένων γωνιών
+  Στρογγυλεμένες γωνίες
   Οι γωνίες είναι στρογγυλεμένες
   Οι γωνίες είναι τετράγωνες
-  Ενεργοποίηση διπλού πατήματος και πρέζας για αλλαγή μεγέθους
-  Ενέργεια διπλού πατήματος και πρέζα για αλλαγή μεγέθους είναι ενεργοποιημένη η λειτουργία\n\n• Διπλό πάτημα για αύξηση μεγέθους miniplayer\n• Διπλό πάτημα ξανά για επαναφορά του αρχικού μεγέθους
-  Ενέργεια διπλού πατήματος και πρέζα για αλλαγή μεγέθους είναι απενεργοποιημένη
-  Ενεργοποίηση μεταφοράς και απόθεσης
-  Drag and drop is enabled\n\nMiniplayer can be dragged to any corner of the screen
-  Το σύρσιμο και η απόθεση είναι απενεργοποιημένη
-  Απόκρυψη κουμπιού κλεισίματος
-  Το κουμπί κλεισίματος είναι κρυμμένο
-  Το κουμπί κλεισίματος εμφανίζεται
+  Διπλό πάτημα & τσίμπημα για αλλαγή μεγέθους
+  Η λειτουργία διπλού πατήματος και τσιμπήματος για αλλαγή μεγέθους είναι ενεργοποιημένη\n\n• Πατήστε δύο φορές για να αυξήσετε το μέγεθος της ελαχιστοποιημένης οθόνης\n• Πατήστε ξανά δύο φορές για επαναφορά στο αρχικό της μέγεθος
+  Η λειτουργία διπλού πατήματος και τσιμπήματος για αλλαγή μεγέθους είναι απενεργοποιημένη
+  Λειτουργία μεταφοράς και απόθεσης
+  Η λειτουργία μεταφοράς και απόθεσης είναι ενεργοποιημένη\n\nΗ ελαχιστοποιημένη οθόνη αναπαραγωγής μπορεί να μετακινηθεί σε οποιαδήποτε γωνία της οθόνης
+  Η λειτουργία μεταφοράς και απόθεσης είναι απενεργοποιημένη
+  Κουμπί κλεισίματος
+  Κρυμμένο
+  Εμφανίζεται
   Κουμπιά επέκτασης και κλεισίματος
-  Τα κουμπιά είναι κρυμμένα\n\nΣύρετε για επέκταση ή κλείσιμο
-  Εμφανίζονται τα κουμπιά επέκτασης και κλεισίματος
+  Κρυμμένα\n\nΣύρετε για επέκταση ή κλείσιμο
+  Εμφανίζονται
   Κείμενα στην οθόνη αναπαραγωγής
   Κρυμμένα
   Εμφανίζονται
@@ -1026,8 +1026,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Κρυμμένα
   Εμφανίζονται
   Αρχικό μέγεθος
-  Αρχικό μέγεθος οθόνης, σε εικονοστοιχεία
-  Το μέγεθος του Pixel πρέπει να είναι μεταξύ %1$s και %2$s
+  Αρχικό μέγεθος οθόνης, σε pixel
+  Τα pixel πρέπει να είναι μεταξύ %1$s και %2$s
   Αδιαφάνεια επικάλυψης
   Τιμή αδιαφάνειας μεταξύ 0-100, όπου το 0 είναι διαφανές
   Η αδιαφάνεια φόντου οθόνης αναπαραγωγής πρέπει να είναι μεταξύ 0-100
diff --git a/src/main/resources/addresources/values-hu-rHU/strings.xml b/src/main/resources/addresources/values-hu-rHU/strings.xml
index 31624d45c2..cc414016f2 100644
--- a/src/main/resources/addresources/values-hu-rHU/strings.xml
+++ b/src/main/resources/addresources/values-hu-rHU/strings.xml
@@ -644,6 +644,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   A zöld képernyőgomb elrejtése
   A zöld képernyő gomb el van rejtve
   A zöld képernyő gomb látható
+  A hashtag gomb elrejtése
+  A Hashtag gomb el van rejtve
+  A Hashtag gomb látható
   Keresési javaslatok elrejtése
   A keresési javaslatok el vannak rejtve
   A keresési javaslatok megjelennek
@@ -965,12 +968,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   Kezdőlap beállítása
   Alapértelmezett
+  Csatornák böngészése
   Felfedezés
+  Játék
   Előzmények
+  Könyvtár
   Kedvelt videók
+  Élő
+  Filmek
+  Zene
   Keresés
+  Sportok
   Feliratkozások
   Felkapott
+  Megnézem később
   
   
   A Shorts lejátszás folytatásának kikapcsolása
@@ -993,13 +1004,30 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Modern 1
   Modern 2
   Modern 3
+  Lekerekített sarkok engedélyezése
+  A sarkok lekerekítettek
+  A sarkok négyzet alakúak
+  Az átméretezéshez engedélyezze a dupla koppintást és az összehúzást
+  A művelet duplán koppintva és az átméretezéshez csípéssel engedélyezve van\n\n• Koppintson duplán a minilejátszó méretének növeléséhez\n• Koppintson duplán az eredeti méret visszaállításához
+  A dupla koppintás művelet és az átméretezéshez csípés le van tiltva
+  Fogd és vidd engedélyezése
+  A fogd és vidd be van kapcsolva\n\nA minilejátszó a képernyő bármely sarkába húzható
+  A Fogd és vidd letiltva
+  Bezárás gomb elrejtése
+  A Bezárás gomb el van rejtve
+  A Bezárás gomb látható
   Kibontás és bezárás gombok elrejtése
+  A gombok el vannak rejtve\n\nCsúsztassa ujját a kibontáshoz vagy bezáráshoz
+  A Kibontás és Bezárás gombok láthatók
   Alszövegek elrejtése
   Az alszövegek el vannak rejtve
   Alszövegek megjelennek
   Az előre és vissza ugrás gombok elrejtése
   Az előre és hátra ugrás rejtve van
   Az előre és hátra ugrás látható
+  Kezdeti méret
+  Kezdeti méret a képernyőn, pixelben
+  A képpont méretének %1$s és %2$s között kell lennie
   Átfedés átlátszósága
   Az átlátszatlanság értéke 0 és 100 között van, ahol a 0 átlátszó
   A minilejátszó fedvény átlátszatlanságának 0 és 100 között kell lennie
@@ -1015,6 +1043,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Az egyéni keresősáv szín nem jelenik meg
   Egyéni keresősáv színe
   A keresősáv színe
+  Érvénytelen keresősáv színértéke
   
   
   Területi kép-korlátozások megkerülése
diff --git a/src/main/resources/addresources/values-ko-rKR/strings.xml b/src/main/resources/addresources/values-ko-rKR/strings.xml
index 2626309635..3fdc87c402 100644
--- a/src/main/resources/addresources/values-ko-rKR/strings.xml
+++ b/src/main/resources/addresources/values-ko-rKR/strings.xml
@@ -384,7 +384,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   오버레이 투명도
   오버레이 투명도 값을 지정할 수 있습니다 (0–255)
   스와이프 한계치
-  제스처 인식을 위해 얼마나 스와이프를 해야 할지를 설정할 수 있으며, 원하지 않은 제스처 인식을 방지할 수 있습니다
+  제스처 인식을 위해 얼마나 스와이프를 해야 할지를 지정할 수 있으며, 원하지 않은 제스처 인식을 방지할 수 있습니다
   
   
   자동 자막 비활성화하기
@@ -645,9 +645,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   그린 스크린 버튼 숨기기
   그린 스크린 버튼이 숨겨집니다
   그린 스크린 버튼이 표시됩니다
-  해시 태그 숨기기
-  해시 태그가 숨겨집니다
-  해시 태그가 표시됩니다
+  해시태그 버튼 숨기기
+  해시태그 버튼이 숨겨집니다
+  해시태그 벼튼이 표시됩니다
   검색 추천 숨기기
   검색 추천이 숨겨집니다
   검색 추천이 표시됩니다
@@ -1008,7 +1008,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   둥근 모서리 활성화하기
   모서리를 둥글게 활성화합니다
   모서리를 각지게 활성화합니다
-  두 번 탭하고 핀치하여 크기 조정 활성화하기
+  두 번 누르기 및 핀치하여 크기 조정 활성화하기
   두 번 누르기 동작 및 핀치하여 크기 조정을 활성화합니다\n\n• 두 번 눌러서 미니 플레이어 크기를 확대합니다\n• 다시 두 번 눌러서 원래 크기로 복원합니다
   두 번 누르기 동작 및 핀치하여 크기 조정을 비활성화합니다
   드래그 & 드롭 활성화하기
@@ -1018,7 +1018,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   닫기 버튼이 숨겨집니다
   닫기 버튼이 표시됩니다
   \'펼치기\' & \'닫기\' 버튼 숨기기
-  버튼들이 숨겨집니다\n\n미니 플레이어를 펼치거나 닫을 수 있습니다
+  버튼들이 숨겨집니다\n\n스와이프하여 미니 플레이어를 펼치거나 닫을 수 있습니다
   \'펼치기\' & \'닫기\' 버튼이 표시됩니다
   서브텍스트 숨기기
   서브텍스트가 숨겨집니다\n• 왼쪽 하단에서 표시되는 \'유료 광고 포함\'과 같은 라벨
@@ -1026,8 +1026,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   \'되감기\' & \'빨리 감기\' 버튼 숨기기
   \'되감기\' & \'빨리 감기\' 버튼이 숨겨집니다
   \'되감기\' & \'빨리 감기\' 버튼이 표시됩니다
-  크기 초기화하기
-  화면 크기의 이니셜, 픽셀 단위을 초기화합니다
+  화면 크기 초기값
+  화면 크기 초기값을 지정할 수 있습니다 (픽셀)
   픽셀 크기는 %1$s-%2$s 사이어야 합니다
   미니 플레이어 오버레이 불투명도
   불투명도 값은 0-100 사이이며, 0은 투명입니다
diff --git a/src/main/resources/addresources/values-lt-rLT/strings.xml b/src/main/resources/addresources/values-lt-rLT/strings.xml
index 413b708cb8..4f75f9866d 100644
--- a/src/main/resources/addresources/values-lt-rLT/strings.xml
+++ b/src/main/resources/addresources/values-lt-rLT/strings.xml
@@ -149,6 +149,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   
+  Slėpti saitažodžio mygtuką
+  Paslėptas saitažodžio mygtukas
+  Rodomas saitažodžio mygtukas
   
   
   
diff --git a/src/main/resources/addresources/values-sr-rCS/strings.xml b/src/main/resources/addresources/values-sr-rCS/strings.xml
index 36e95ccb1b..6f1832d5d0 100644
--- a/src/main/resources/addresources/values-sr-rCS/strings.xml
+++ b/src/main/resources/addresources/values-sr-rCS/strings.xml
@@ -645,6 +645,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Sakrij dugme „Green Screen”
   Dugme „Green Screen” je skriveno
   Dugme „Green Screen” je prikazano
+  Sakrij dugme heš-oznake
+  Dugme heš-oznake je skriveno
+  Dugme heš-oznake je prikazano
   Sakrij predloge za pretragu
   Predlozi za pretragu su skriveni
   Predlozi za pretragu su prikazani
@@ -710,8 +713,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   Neprozirnost preklopa plejera
-  Vrednost neprozirnosti između 0-100, gde je 0 prozirno
-  Prozirnost preklopa plejera mora biti između 0-100
+  Vrednost neprozirnosti između 0 i 100, gde je 0 prozirno
+  Neprozirnost preklopa plejera mora biti između 0 i 100
   
   
   
@@ -966,13 +969,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   Podešavanje početne stranice
   Podrazumevana
+  Pretraga kanala
   Istraži
+  Video igre
   Istorija
   Zbirka
   Lajkovani videi
+  Uživo
+  Filmovi
+  Muzika
   Pretraga
+  Sport
   Praćenja
   U trendu
+  Gledaj kasnije
   
   
   Onemogući nastavak reprodukcije Shorts plejera
@@ -995,16 +1005,33 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Moderan 1
   Moderan 2
   Moderan 3
+  Omogući zaobljene uglove
+  Uglovi su zaobljeni
+  Uglovi nisu zaobljeni
+  Omogući dvostruki dodir i štipanje za promenu veličine
+  Radnja dvostrukog dodira i štipanja za promenu veličine je omogućena\n\n• Dvaput dodirnite da biste povećali veličinu mini-plejera\n• Dvaput dodirnite ponovo da biste vratili originalnu veličinu
+  Radnja dvostrukog dodira i štipanja za promenu veličine je onemogućena
+  Omogući prevlačenje i otpuštanje
+  Prevlačenje i otpuštanje je omogućeno\n\nMini-plejer može da se prevuče u bilo koji ugao ekrana
+  Prevlačenje i otpuštanje je onemogućeno
+  Sakrij dugme za zatvaranje
+  Dugme za zatvaranje je skriveno
+  Dugme za zatvaranje je prikazano
   Sakrij dugmad za proširivanje i zatvaranje
+  Dugmad su skrivena\n\nPrevucite da biste proširili ili zatvorili
+  Dugmad za proširivanje i zatvaranje su prikazana
   Sakrij podtekstove
   Podtekstovi su skriveni
   Podtekstovi su prikazani
   Sakrij dugmad za premotavanje unapred i unazad
   Dugmad za premotavanje unapred i unazad su skrivena
   Dugmad za premotavanje unapred i unazad su prikazana
-  Prozirnost preklopa
-  Vrednost neprozirnosti između 0-100, gde je 0 prozirno
-  Prozirnost preklopa mini-plejera mora biti između 0-100
+  Početna veličina
+  Početna veličina ekrana, u pikselima
+  Veličina piksela mora biti između %1$s i %2$s
+  Neprozirnost preklopa
+  Vrednost neprozirnosti između 0 i 100, gde je 0 prozirno
+  Neprozirnost preklopa mini-plejera mora biti između 0 i 100
   
   
   Omogući ekran učitavanja s gradijentom
diff --git a/src/main/resources/addresources/values-sr-rSP/strings.xml b/src/main/resources/addresources/values-sr-rSP/strings.xml
index 5620851ffa..1448611836 100644
--- a/src/main/resources/addresources/values-sr-rSP/strings.xml
+++ b/src/main/resources/addresources/values-sr-rSP/strings.xml
@@ -645,6 +645,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Сакриј дугме „Green Screen”
   Дугме „Green Screen” је скривено
   Дугме „Green Screen” је приказано
+  Сакриј дугме хеш-ознаке
+  Дугме хеш-ознаке је скривено
+  Дугме хеш-ознаке је приказано
   Сакриј предлоге за претрагу
   Предлози за претрагу су скривени
   Предлози за претрагу су приказани
@@ -710,8 +713,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   
   Непрозирност преклопа плејера
-  Вредност непрозирности између 0-100, где је 0 прозирно
-  Прозирност преклопа плејера мора бити између 0-100
+  Вредност непрозирности између 0 и 100, где је 0 прозирно
+  Непрозирност преклопа плејера мора бити између 0 и 100
   
   
   
@@ -966,13 +969,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
   
   Подешавање почетне странице
   Подразумевана
+  Претрага канала
   Истражи
+  Видео игре
   Историја
   Збирка
   Лајковани видеи
+  Уживо
+  Филмови
+  Музика
   Претрага
+  Спорт
   Праћења
   У тренду
+  Гледај касније
   
   
   Онемогући наставак репродукције Shorts плејера
@@ -995,16 +1005,33 @@ This is because Crowdin requires temporarily flattening this file and removing t
   Модеран 1
   Модеран 2
   Модеран 3
+  Омогући заобљене углове
+  Углови су заобљени
+  Углови нису заобљени
+  Омогући двоструки додир и штипање за промену величине
+  Радња двоструког додира и штипања за промену величине је омогућена\n\n• Двапут додирните да бисте повећали величину мини-плејера\n• Двапут додирните поново да бисте вратили оригиналну величину
+  Радња двоструког додира и штипање за промену величине су онемогућени
+  Омогући превлачење и отпуштање
+  Превлачење и отпуштање је омогућено\n\nМини-плејер може да се превуче у било који угао екрана
+  Превлачење и отпуштање је онемогућено
+  Сакриј дугме за затварање
+  Дугме за затварање је скривено
+  Дугме за затварање је приказано
   Сакриј дугмад за проширивање и затварање
+  Дугмад су скривена\n\nПревуците да бисте проширили или затворили
+  Дугмад за проширивање и затварање су приказана
   Сакриј подтекстове
   Подтекстови су скривени
   Подтекстови су приказани
   Сакриј дугмад за премотавање унапред и уназад
   Дугмад за премотавање унапред и уназад су скривена
   Дугмад за премотавање унапред и уназад су приказана
-  Прозирност преклопа
-  Вредност непрозирности између 0-100, где је 0 прозирно
-  Прозирност преклопа мини-плејера мора бити између 0-100
+  Почетна величина
+  Почетна величина екрана, у пикселима
+  Величина пиксела мора бити између %1$s и %2$s
+  Непрозирност преклопа
+  Вредност непрозирности између 0 и 100, где је 0 прозирно
+  Непрозирност преклопа мини-плејера мора бити између 0 и 100
   
   
   Омогући екран учитавања с градијентом
diff --git a/src/main/resources/addresources/values-zh-rTW/strings.xml b/src/main/resources/addresources/values-zh-rTW/strings.xml
index ab380a4eb3..c74f37b81c 100644
--- a/src/main/resources/addresources/values-zh-rTW/strings.xml
+++ b/src/main/resources/addresources/values-zh-rTW/strings.xml
@@ -963,14 +963,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
   17.33.42 - 還原舊版 UI 介面
   
   
-  設定啟動頁面
+  設定起始頁面
   預設
+  瀏覽頻道
   探索
+  遊戲
   歷史記錄
+  媒體庫
   喜歡的影片
+  直播
+  電影
+  音樂
   搜尋
+  運動
   訂閱
   發燒影片
+  稍後觀看
   
   
   停用自動復原 Shorts 播放器
@@ -993,14 +1001,31 @@ This is because Crowdin requires temporarily flattening this file and removing t
   現代樣式 1
   現代樣式 2
   現代樣式 3
-  隱藏擴展和關閉按鈕
-  已顯示擴展和關閉按鈕
+  啟用圓角角落
+  已設定角落為圓角
+  已設定角落為方形
+  啟用輕觸兩下和縮放手勢以調整大小
+  已啟用輕觸兩下和縮放手勢以調整大小。\n\n•
+輕觸兩下以放大迷你播放器的大小\n• 再次輕觸兩下以復原至原始大小
+  已停用輕觸兩下和縮放手勢以調整大小
+  啟用拖曳
+  已啟用拖曳\n\n現在迷你播放器可以拖曳至螢幕的任何角落
+  已停用拖曳
+  隱藏 [關閉] 按鈕
+  已隱藏 [關閉] 按鈕
+  已顯示 [關閉] 按鈕
+  隱藏 [展開] 和 [關閉] 按鈕
+  已隱藏按鈕\n\n撥動以 [展開] 或 [關閉]
+  已顯示 [展開] 和 [關閉] 按鈕
   隱藏副標
   副標已隱藏
   副標已顯示
   隱藏快轉和倒帶按鈕
   已隱藏快轉和倒帶按鈕
   已顯示快轉和倒帶按鈕
+  初始大小
+  螢幕初始大小 (像素)
+  像素大小必須介於 %1$s 和 %2$s 之間
   覆蓋層不透明度
   不透明度值介於 0-100 之間,0 為透明
   迷你播放器覆蓋層的不透明度必須在 0-100 之間
@@ -1016,6 +1041,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
   已顯示原版進度列顏色
   自訂進度列顏色
   進度列顏色
+  滑動桿色彩值無效
   
   
   繞過圖片區域限制