mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-25 02:14:09 +01:00
Compare commits
59 Commits
v5.37.0-de
...
v5.40.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
729997ec3e | ||
|
|
767f1e3695 | ||
|
|
7857876551 | ||
|
|
04057c6e56 | ||
|
|
8ba9a19ade | ||
|
|
6862200a28 | ||
|
|
dfff3d7c0a | ||
|
|
e6cce85541 | ||
|
|
8502eb8eac | ||
|
|
0652c56d0d | ||
|
|
b7026b7086 | ||
|
|
fa4f422a15 | ||
|
|
38e0cbd724 | ||
|
|
0bdebd927d | ||
|
|
3eac25cf7f | ||
|
|
c9f741e616 | ||
|
|
cba44ccfc8 | ||
|
|
a84db7be7f | ||
|
|
2520129ace | ||
|
|
7eeffd3392 | ||
|
|
6c3391164e | ||
|
|
0b8b46c73e | ||
|
|
cbe576bc38 | ||
|
|
3a29f2a805 | ||
|
|
50069c7e05 | ||
|
|
2e9c9dc244 | ||
|
|
56166896d9 | ||
|
|
b4c695b1d5 | ||
|
|
1475643f84 | ||
|
|
9a7179f9cf | ||
|
|
6fb94a7a41 | ||
|
|
3776dda710 | ||
|
|
f88b3a5162 | ||
|
|
0eeaf7ad67 | ||
|
|
2726231404 | ||
|
|
9f0558e494 | ||
|
|
01f7bc9f8d | ||
|
|
5e20bd80f1 | ||
|
|
f304c178e2 | ||
|
|
1d65887e01 | ||
|
|
6b6eea8414 | ||
|
|
1db131e90e | ||
|
|
abe3943f98 | ||
|
|
cb6d802de3 | ||
|
|
f11d1ef990 | ||
|
|
3d25da18bc | ||
|
|
fa04c8eecf | ||
|
|
105f6e0e97 | ||
|
|
7d59efe05d | ||
|
|
81ff5576b0 | ||
|
|
9a5c102c0d | ||
|
|
e6c79f1383 | ||
|
|
2a582eced8 | ||
|
|
2db0948bea | ||
|
|
a3ba92e742 | ||
|
|
2a85a3b290 | ||
|
|
eee72208dd | ||
|
|
dcd42454bd | ||
|
|
782353c18a |
188
CHANGELOG.md
188
CHANGELOG.md
@@ -1,3 +1,191 @@
|
||||
# [5.40.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.40.0-dev.2...v5.40.0-dev.3) (2025-09-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram - Limit feed to followed profiles:** Change patch to default off ([767f1e3](https://github.com/ReVanced/revanced-patches/commit/767f1e3695327bdbc4daea8b50a80d4c0a38456a))
|
||||
|
||||
# [5.40.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.40.0-dev.1...v5.40.0-dev.2) (2025-09-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Instagram:** Add `Limit feed to followed profiles` patch ([#5908](https://github.com/ReVanced/revanced-patches/issues/5908)) ([8ba9a19](https://github.com/ReVanced/revanced-patches/commit/8ba9a19ade24c5fe9bd6d4e49772b7663522780e))
|
||||
|
||||
# [5.40.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.39.1-dev.1...v5.40.0-dev.1) (2025-09-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Viber - Hide ads:** Support latest app target ([#5863](https://github.com/ReVanced/revanced-patches/issues/5863)) ([e6cce85](https://github.com/ReVanced/revanced-patches/commit/e6cce8554116df3c0ea6dbb7440c59c9e73d8334))
|
||||
|
||||
## [5.39.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.39.0...v5.39.1-dev.1) (2025-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Force original audio:** Show UI setting summary if spoofing to Android Studio ([b7026b7](https://github.com/ReVanced/revanced-patches/commit/b7026b70865bc44de07b30f84ba8b8b608930d5b))
|
||||
|
||||
# [5.39.0](https://github.com/ReVanced/revanced-patches/compare/v5.38.0...v5.39.0) (2025-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Do not use Android Creator for livestreams ([cbe576b](https://github.com/ReVanced/revanced-patches/commit/cbe576bc384ef5f5ee2fa341147925ed0dff568b))
|
||||
* **YouTube - Spoof video streams:** Show Android Studio in spoof stream menu ([c9f741e](https://github.com/ReVanced/revanced-patches/commit/c9f741e616c7acab0cd4558e02b0c4ec18392c10))
|
||||
* **YouTube Music - Spoof video streams:** Remove iPadOS client ([7eeffd3](https://github.com/ReVanced/revanced-patches/commit/7eeffd3392c57555342173103d3a417c038d0970))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide video action buttons:** Add "Hide Shop button" setting ([a84db7b](https://github.com/ReVanced/revanced-patches/commit/a84db7be7fde2e9bb3ac41aec709a1681e845fe1))
|
||||
|
||||
# [5.39.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.39.0-dev.1...v5.39.0-dev.2) (2025-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Show Android Studio in spoof stream menu ([c9f741e](https://github.com/ReVanced/revanced-patches/commit/c9f741e616c7acab0cd4558e02b0c4ec18392c10))
|
||||
|
||||
# [5.39.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.38.1-dev.2...v5.39.0-dev.1) (2025-09-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide video action buttons:** Add "Hide Shop button" setting ([a84db7b](https://github.com/ReVanced/revanced-patches/commit/a84db7be7fde2e9bb3ac41aec709a1681e845fe1))
|
||||
|
||||
## [5.38.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.38.1-dev.1...v5.38.1-dev.2) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - Spoof video streams:** Remove iPadOS client ([7eeffd3](https://github.com/ReVanced/revanced-patches/commit/7eeffd3392c57555342173103d3a417c038d0970))
|
||||
|
||||
## [5.38.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.38.0...v5.38.1-dev.1) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Do not use Android Creator for livestreams ([cbe576b](https://github.com/ReVanced/revanced-patches/commit/cbe576bc384ef5f5ee2fa341147925ed0dff568b))
|
||||
|
||||
# [5.38.0](https://github.com/ReVanced/revanced-patches/compare/v5.37.0...v5.38.0) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram - Hide navigation buttons:** Support v397.1.0.52.81 ([#5855](https://github.com/ReVanced/revanced-patches/issues/5855)) ([f11d1ef](https://github.com/ReVanced/revanced-patches/commit/f11d1ef9907082512f139d4ab0e2e9f707de7e48))
|
||||
* **Spoof video streams:** Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for `Force original audio` to work with any spoof client ([#5861](https://github.com/ReVanced/revanced-patches/issues/5861)) ([abe3943](https://github.com/ReVanced/revanced-patches/commit/abe3943f98fd86dcd74c7e07cf65d3c7fc24fef9))
|
||||
* **YouTube - Spoof video streams:** Show settings summary if `Force original audio` is enabled ([3776dda](https://github.com/ReVanced/revanced-patches/commit/3776dda710a7780717b7e6f2cdc1333ab67b92fc))
|
||||
* **YouTube Music - Spoof video streams:** Fix playback issues when using a cellular network ([fa04c8e](https://github.com/ReVanced/revanced-patches/commit/fa04c8eecfbdd0b6ed082b464ca9032536d71762))
|
||||
* **YouTube Music:** Use correct light/dark mode settings UI ([1475643](https://github.com/ReVanced/revanced-patches/commit/1475643f84e9ee4af2ba360a2274001ff1570dad))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Instagram:** Add `Hide explore feed` patch ([#5856](https://github.com/ReVanced/revanced-patches/issues/5856)) ([1d65887](https://github.com/ReVanced/revanced-patches/commit/1d65887e015a067196f5a84db486fff355c96596))
|
||||
* **YouTube - Spoof video streams:** Add iPadOS client ([2726231](https://github.com/ReVanced/revanced-patches/commit/2726231404384d87f101d825e10a17c944e8f1bd))
|
||||
* **YouTube Music:** Add `Settings` patch ([#5838](https://github.com/ReVanced/revanced-patches/issues/5838)) ([5e20bd8](https://github.com/ReVanced/revanced-patches/commit/5e20bd80f138d7ca94f18857194c46e489c435dc))
|
||||
|
||||
# [5.38.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.4...v5.38.0-dev.5) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music:** Use correct light/dark mode settings UI ([1475643](https://github.com/ReVanced/revanced-patches/commit/1475643f84e9ee4af2ba360a2274001ff1570dad))
|
||||
|
||||
# [5.38.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.3...v5.38.0-dev.4) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Show settings summary if `Force original audio` is enabled ([3776dda](https://github.com/ReVanced/revanced-patches/commit/3776dda710a7780717b7e6f2cdc1333ab67b92fc))
|
||||
|
||||
# [5.38.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.2...v5.38.0-dev.3) (2025-09-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Spoof video streams:** Add iPadOS client ([2726231](https://github.com/ReVanced/revanced-patches/commit/2726231404384d87f101d825e10a17c944e8f1bd))
|
||||
|
||||
# [5.38.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.1...v5.38.0-dev.2) (2025-09-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube Music:** Add `Settings` patch ([#5838](https://github.com/ReVanced/revanced-patches/issues/5838)) ([5e20bd8](https://github.com/ReVanced/revanced-patches/commit/5e20bd80f138d7ca94f18857194c46e489c435dc))
|
||||
|
||||
# [5.38.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.3...v5.38.0-dev.1) (2025-09-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Instagram:** Add `Hide explore feed` patch ([#5856](https://github.com/ReVanced/revanced-patches/issues/5856)) ([1d65887](https://github.com/ReVanced/revanced-patches/commit/1d65887e015a067196f5a84db486fff355c96596))
|
||||
|
||||
## [5.37.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.2...v5.37.1-dev.3) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Spoof video streams:** Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for `Force original audio` to work with any spoof client ([#5861](https://github.com/ReVanced/revanced-patches/issues/5861)) ([abe3943](https://github.com/ReVanced/revanced-patches/commit/abe3943f98fd86dcd74c7e07cf65d3c7fc24fef9))
|
||||
|
||||
## [5.37.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.1...v5.37.1-dev.2) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram - Hide navigation buttons:** Support v397.1.0.52.81 ([#5855](https://github.com/ReVanced/revanced-patches/issues/5855)) ([f11d1ef](https://github.com/ReVanced/revanced-patches/commit/f11d1ef9907082512f139d4ab0e2e9f707de7e48))
|
||||
|
||||
## [5.37.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.37.0...v5.37.1-dev.1) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - Spoof video streams:** Fix playback issues when using a cellular network ([fa04c8e](https://github.com/ReVanced/revanced-patches/commit/fa04c8eecfbdd0b6ed082b464ca9032536d71762))
|
||||
|
||||
# [5.37.0](https://github.com/ReVanced/revanced-patches/compare/v5.36.0...v5.37.0) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram - Hide navigation buttons:** Add constrain to known working version ([e6c79f1](https://github.com/ReVanced/revanced-patches/commit/e6c79f13834c83fef04e4dee5e628cb0b9a27765))
|
||||
* Resolve patching with dev branch ([09b941a](https://github.com/ReVanced/revanced-patches/commit/09b941abf0e8029999565082b02a88b5de507ec4))
|
||||
* **Spotify:** Remove broken `Spoof client` patch ([#5833](https://github.com/ReVanced/revanced-patches/issues/5833)) ([dcd4245](https://github.com/ReVanced/revanced-patches/commit/dcd42454bd5f87dddd720534f6120c4ef90063a3))
|
||||
* **Viber - Hide ads:** Add constrain to known working version ([2db0948](https://github.com/ReVanced/revanced-patches/commit/2db0948beaf2b68391a1fe7f21e92d31c7df61e7))
|
||||
* **YouTube Music - Spoof streaming data:** Fix audio playback stuttering ([#5839](https://github.com/ReVanced/revanced-patches/issues/5839)) ([2a85a3b](https://github.com/ReVanced/revanced-patches/commit/2a85a3b29092729ae16d1fd93803634ce5f08e95))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Viber:** Add `Hide ads` patch ([#5826](https://github.com/ReVanced/revanced-patches/issues/5826)) ([0abfab7](https://github.com/ReVanced/revanced-patches/commit/0abfab79d7cda15bf17c53679fbfffb021662649))
|
||||
|
||||
# [5.37.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.5...v5.37.0-dev.6) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram - Hide navigation buttons:** Add constrain to known working version ([e6c79f1](https://github.com/ReVanced/revanced-patches/commit/e6c79f13834c83fef04e4dee5e628cb0b9a27765))
|
||||
|
||||
# [5.37.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.4...v5.37.0-dev.5) (2025-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Viber - Hide ads:** Add constrain to known working version ([2db0948](https://github.com/ReVanced/revanced-patches/commit/2db0948beaf2b68391a1fe7f21e92d31c7df61e7))
|
||||
|
||||
# [5.37.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.3...v5.37.0-dev.4) (2025-09-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - Spoof streaming data:** Fix audio playback stuttering ([#5839](https://github.com/ReVanced/revanced-patches/issues/5839)) ([2a85a3b](https://github.com/ReVanced/revanced-patches/commit/2a85a3b29092729ae16d1fd93803634ce5f08e95))
|
||||
|
||||
# [5.37.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.2...v5.37.0-dev.3) (2025-09-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Spotify:** Remove broken `Spoof client` patch ([#5833](https://github.com/ReVanced/revanced-patches/issues/5833)) ([dcd4245](https://github.com/ReVanced/revanced-patches/commit/dcd42454bd5f87dddd720534f6120c4ef90063a3))
|
||||
|
||||
# [5.37.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.1...v5.37.0-dev.2) (2025-09-14)
|
||||
|
||||
|
||||
|
||||
3
extensions/instagram/build.gradle.kts
Normal file
3
extensions/instagram/build.gradle.kts
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
}
|
||||
1
extensions/instagram/src/main/AndroidManifest.xml
Normal file
1
extensions/instagram/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,18 @@
|
||||
package app.revanced.extension.instagram.feed;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class LimitFeedToFollowedProfiles {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static Map<String, String> setFollowingHeader(Map<String, String> requestHeaderMap) {
|
||||
// Create new map as original is unmodifiable.
|
||||
Map<String, String> patchedRequestHeaderMap = new HashMap<>(requestHeaderMap);
|
||||
patchedRequestHeaderMap.put("pagination_source", "following");
|
||||
return patchedRequestHeaderMap;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:youtube:stub"))
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.extension.music.patches;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HideCategoryBarPatch {
|
||||
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean hideCategoryBar() {
|
||||
return Settings.HIDE_CATEGORY_BAR.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.extension.music.patches;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HideGetPremiumPatch {
|
||||
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean hideGetPremiumLabel() {
|
||||
return Settings.HIDE_GET_PREMIUM_LABEL.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.extension.music.patches;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HideUpgradeButtonPatch {
|
||||
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean hideUpgradeButton() {
|
||||
return Settings.HIDE_UPGRADE_BUTTON.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package app.revanced.extension.music.patches;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HideVideoAdsPatch {
|
||||
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean showVideoAds(boolean original) {
|
||||
if (Settings.HIDE_VIDEO_ADS.get()) {
|
||||
return false;
|
||||
}
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.extension.music.patches;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class PermanentRepeatPatch {
|
||||
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean permanentRepeat() {
|
||||
return Settings.PERMANENT_REPEAT.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package app.revanced.extension.music.patches.spoof;
|
||||
|
||||
import static app.revanced.extension.music.settings.Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofVideoStreamsPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setClientOrderToUse() {
|
||||
List<ClientType> availableClients = List.of(
|
||||
ANDROID_VR_1_43_32,
|
||||
ANDROID_VR_1_61_48,
|
||||
VISIONOS
|
||||
);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
availableClients, SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package app.revanced.extension.music.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.extension.music.settings.preference.ReVancedPreferenceFragment;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseActivityHook;
|
||||
|
||||
/**
|
||||
* Hooks GoogleApiActivity to inject a custom ReVancedPreferenceFragment with a toolbar.
|
||||
*/
|
||||
public class GoogleApiActivityHook extends BaseActivityHook {
|
||||
/**
|
||||
* Injection point
|
||||
* <p>
|
||||
* Creates an instance of GoogleApiActivityHook for use in static initialization.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static GoogleApiActivityHook createInstance() {
|
||||
// Must touch the Music settings to ensure the class is loaded and
|
||||
// the values can be found when setting the UI preferences.
|
||||
// Logging anything under non debug ensures this is set.
|
||||
Logger.printInfo(() -> "Permanent repeat enabled: " + Settings.PERMANENT_REPEAT.get());
|
||||
|
||||
// YT Music always uses dark mode.
|
||||
Utils.setIsDarkModeEnabled(true);
|
||||
|
||||
return new GoogleApiActivityHook();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fixed theme for the activity.
|
||||
*/
|
||||
@Override
|
||||
protected void customizeActivityTheme(Activity activity) {
|
||||
// Override the default YouTube Music theme to increase start padding of list items.
|
||||
// Custom style located in resources/music/values/style.xml
|
||||
activity.setTheme(Utils.getResourceIdentifier("Theme.ReVanced.YouTubeMusic.Settings", "style"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource ID for the YouTube Music settings layout.
|
||||
*/
|
||||
@Override
|
||||
protected int getContentViewResourceId() {
|
||||
return Utils.getResourceIdentifier("revanced_music_settings_with_toolbar", "layout");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fixed background color for the toolbar.
|
||||
*/
|
||||
@Override
|
||||
protected int getToolbarBackgroundColor() {
|
||||
return Utils.getResourceColor("ytm_color_black");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the navigation icon with a color filter applied.
|
||||
*/
|
||||
@Override
|
||||
protected Drawable getNavigationIcon() {
|
||||
Drawable navigationIcon = ReVancedPreferenceFragment.getBackButtonDrawable();
|
||||
navigationIcon.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN);
|
||||
return navigationIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the click listener that finishes the activity when the navigation icon is clicked.
|
||||
*/
|
||||
@Override
|
||||
protected View.OnClickListener getNavigationClickListener(Activity activity) {
|
||||
return view -> activity.finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ReVancedPreferenceFragment for the activity.
|
||||
*/
|
||||
@Override
|
||||
protected PreferenceFragment createPreferenceFragment() {
|
||||
return new ReVancedPreferenceFragment();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package app.revanced.extension.music.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||
import app.revanced.extension.shared.settings.EnumSetting;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
|
||||
public class Settings extends BaseSettings {
|
||||
|
||||
// Ads
|
||||
public static final BooleanSetting HIDE_VIDEO_ADS = new BooleanSetting("revanced_music_hide_video_ads", TRUE, true);
|
||||
public static final BooleanSetting HIDE_GET_PREMIUM_LABEL = new BooleanSetting("revanced_music_hide_get_premium_label", TRUE, true);
|
||||
public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true);
|
||||
|
||||
// General
|
||||
public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true);
|
||||
|
||||
// Player
|
||||
public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true);
|
||||
|
||||
// Miscellaneous
|
||||
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
|
||||
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package app.revanced.extension.music.settings.preference;
|
||||
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import app.revanced.extension.music.settings.GoogleApiActivityHook;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||
|
||||
/**
|
||||
* Preference fragment for ReVanced settings.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "NewApi"})
|
||||
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
|
||||
|
||||
/**
|
||||
* Initializes the preference fragment.
|
||||
*/
|
||||
@Override
|
||||
protected void initialize() {
|
||||
super.initialize();
|
||||
|
||||
try {
|
||||
Utils.sortPreferenceGroups(getPreferenceScreen());
|
||||
setPreferenceScreenToolbar(getPreferenceScreen());
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "initialize failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets toolbar for all nested preference screens.
|
||||
*/
|
||||
@Override
|
||||
protected void customizeToolbar(Toolbar toolbar) {
|
||||
GoogleApiActivityHook.setToolbarLayoutParams(toolbar);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
package app.revanced.extension.youtube;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
package app.revanced.extension.shared;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@@ -39,7 +37,7 @@ public final class ByteTrieSearch extends TrieSearch<byte[]> {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
public ByteTrieSearch(@NonNull byte[]... patterns) {
|
||||
public ByteTrieSearch(byte[]... patterns) {
|
||||
super(new ByteTrieNode(), patterns);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
package app.revanced.extension.youtube;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
package app.revanced.extension.shared;
|
||||
|
||||
/**
|
||||
* Text pattern searching using a prefix tree (trie).
|
||||
@@ -28,7 +26,7 @@ public final class StringTrieSearch extends TrieSearch<String> {
|
||||
}
|
||||
}
|
||||
|
||||
public StringTrieSearch(@NonNull String... patterns) {
|
||||
public StringTrieSearch(String... patterns) {
|
||||
super(new StringTrieNode(), patterns);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package app.revanced.extension.youtube;
|
||||
package app.revanced.extension.shared;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -57,11 +56,13 @@ public abstract class TrieSearch<T> {
|
||||
if (searchTextLength - searchTextIndex < patternLength - patternStartIndex) {
|
||||
return false; // Remaining search text is shorter than the remaining leaf pattern and they cannot match.
|
||||
}
|
||||
|
||||
for (int i = searchTextIndex, j = patternStartIndex; j < patternLength; i++, j++) {
|
||||
if (enclosingNode.getCharValue(searchText, i) != enclosingNode.getCharValue(pattern, j)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return callback == null || callback.patternMatched(searchText,
|
||||
searchTextIndex - patternStartIndex, patternLength, callbackParameter);
|
||||
}
|
||||
@@ -136,7 +137,7 @@ public abstract class TrieSearch<T> {
|
||||
* @param patternLength Length of the pattern.
|
||||
* @param callback Callback, where a value of NULL indicates to always accept a pattern match.
|
||||
*/
|
||||
private void addPattern(@NonNull T pattern, int patternIndex, int patternLength,
|
||||
private void addPattern(T pattern, int patternIndex, int patternLength,
|
||||
@Nullable TriePatternMatchedCallback<T> callback) {
|
||||
if (patternIndex == patternLength) { // Reached the end of the pattern.
|
||||
if (endOfPatternCallback == null) {
|
||||
@@ -145,6 +146,7 @@ public abstract class TrieSearch<T> {
|
||||
endOfPatternCallback.add(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (leaf != null) {
|
||||
// Reached end of the graph and a leaf exist.
|
||||
// Recursively call back into this method and push the existing leaf down 1 level.
|
||||
@@ -159,6 +161,7 @@ public abstract class TrieSearch<T> {
|
||||
leaf = new TrieCompressedPath<>(pattern, patternIndex, patternLength, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
final char character = getCharValue(pattern, patternIndex);
|
||||
final int arrayIndex = hashIndexForTableSize(children.length, character);
|
||||
TrieNode<T> child = children[arrayIndex];
|
||||
@@ -183,6 +186,7 @@ public abstract class TrieSearch<T> {
|
||||
//noinspection unchecked
|
||||
TrieNode<T>[] replacement = new TrieNode[replacementArraySize];
|
||||
addNodeToArray(replacement, child);
|
||||
|
||||
boolean collision = false;
|
||||
for (TrieNode<T> existingChild : children) {
|
||||
if (existingChild != null) {
|
||||
@@ -195,6 +199,7 @@ public abstract class TrieSearch<T> {
|
||||
if (collision) {
|
||||
continue;
|
||||
}
|
||||
|
||||
children = replacement;
|
||||
return;
|
||||
}
|
||||
@@ -234,6 +239,7 @@ public abstract class TrieSearch<T> {
|
||||
if (leaf != null && leaf.matches(startNode, searchText, searchTextEndIndex, searchTextIndex, callbackParameter)) {
|
||||
return true; // Leaf exists and it matched the search text.
|
||||
}
|
||||
|
||||
List<TriePatternMatchedCallback<T>> endOfPatternCallback = node.endOfPatternCallback;
|
||||
if (endOfPatternCallback != null) {
|
||||
final int matchStartIndex = searchTextIndex - currentMatchLength;
|
||||
@@ -246,6 +252,7 @@ public abstract class TrieSearch<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrieNode<T>[] children = node.children;
|
||||
if (children == null) {
|
||||
return false; // Reached a graph end point and there's no further patterns to search.
|
||||
@@ -278,9 +285,11 @@ public abstract class TrieSearch<T> {
|
||||
if (leaf != null) {
|
||||
numberOfPointers += 4; // Number of fields in leaf node.
|
||||
}
|
||||
|
||||
if (endOfPatternCallback != null) {
|
||||
numberOfPointers += endOfPatternCallback.size();
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
numberOfPointers += children.length;
|
||||
for (TrieNode<T> child : children) {
|
||||
@@ -308,13 +317,13 @@ public abstract class TrieSearch<T> {
|
||||
private final List<T> patterns = new ArrayList<>();
|
||||
|
||||
@SafeVarargs
|
||||
TrieSearch(@NonNull TrieNode<T> root, @NonNull T... patterns) {
|
||||
TrieSearch(TrieNode<T> root, T... patterns) {
|
||||
this.root = Objects.requireNonNull(root);
|
||||
addPatterns(patterns);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public final void addPatterns(@NonNull T... patterns) {
|
||||
public final void addPatterns(T... patterns) {
|
||||
for (T pattern : patterns) {
|
||||
addPattern(pattern);
|
||||
}
|
||||
@@ -325,7 +334,7 @@ public abstract class TrieSearch<T> {
|
||||
*
|
||||
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
|
||||
*/
|
||||
public void addPattern(@NonNull T pattern) {
|
||||
public void addPattern(T pattern) {
|
||||
addPattern(pattern, root.getTextLength(pattern), null);
|
||||
}
|
||||
|
||||
@@ -333,31 +342,31 @@ public abstract class TrieSearch<T> {
|
||||
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
|
||||
* @param callback Callback to determine if searching should halt when a match is found.
|
||||
*/
|
||||
public void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback<T> callback) {
|
||||
public void addPattern(T pattern, TriePatternMatchedCallback<T> callback) {
|
||||
addPattern(pattern, root.getTextLength(pattern), Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
void addPattern(@NonNull T pattern, int patternLength, @Nullable TriePatternMatchedCallback<T> callback) {
|
||||
void addPattern(T pattern, int patternLength, @Nullable TriePatternMatchedCallback<T> callback) {
|
||||
if (patternLength == 0) return; // Nothing to match
|
||||
|
||||
patterns.add(pattern);
|
||||
root.addPattern(pattern, 0, patternLength, callback);
|
||||
}
|
||||
|
||||
public final boolean matches(@NonNull T textToSearch) {
|
||||
public final boolean matches(T textToSearch) {
|
||||
return matches(textToSearch, 0);
|
||||
}
|
||||
|
||||
public boolean matches(@NonNull T textToSearch, @NonNull Object callbackParameter) {
|
||||
public boolean matches(T textToSearch, Object callbackParameter) {
|
||||
return matches(textToSearch, 0, root.getTextLength(textToSearch),
|
||||
Objects.requireNonNull(callbackParameter));
|
||||
}
|
||||
|
||||
public boolean matches(@NonNull T textToSearch, int startIndex) {
|
||||
public boolean matches(T textToSearch, int startIndex) {
|
||||
return matches(textToSearch, startIndex, root.getTextLength(textToSearch));
|
||||
}
|
||||
|
||||
public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) {
|
||||
public final boolean matches(T textToSearch, int startIndex, int endIndex) {
|
||||
return matches(textToSearch, startIndex, endIndex, null);
|
||||
}
|
||||
|
||||
@@ -370,11 +379,11 @@ public abstract class TrieSearch<T> {
|
||||
* @param callbackParameter Optional parameter passed to the callbacks.
|
||||
* @return If any pattern matched, and it's callback halted searching.
|
||||
*/
|
||||
public boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) {
|
||||
public boolean matches(T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) {
|
||||
return matches(textToSearch, root.getTextLength(textToSearch), startIndex, endIndex, callbackParameter);
|
||||
}
|
||||
|
||||
private boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex,
|
||||
private boolean matches(T textToSearch, int textToSearchLength, int startIndex, int endIndex,
|
||||
@Nullable Object callbackParameter) {
|
||||
if (endIndex > textToSearchLength) {
|
||||
throw new IllegalArgumentException("endIndex: " + endIndex
|
||||
@@ -0,0 +1,142 @@
|
||||
package app.revanced.extension.shared.settings;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||
|
||||
/**
|
||||
* Base class for hooking activities to inject a custom PreferenceFragment with a toolbar.
|
||||
* Provides common logic for initializing the activity and setting up the toolbar.
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "NewApi"})
|
||||
public abstract class BaseActivityHook extends Activity {
|
||||
|
||||
/**
|
||||
* Layout parameters for the toolbar, extracted from the dummy toolbar.
|
||||
*/
|
||||
protected static ViewGroup.LayoutParams toolbarLayoutParams;
|
||||
|
||||
/**
|
||||
* Sets the layout parameters for the toolbar.
|
||||
*/
|
||||
public static void setToolbarLayoutParams(Toolbar toolbar) {
|
||||
if (toolbarLayoutParams != null) {
|
||||
toolbar.setLayoutParams(toolbarLayoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the activity by setting the theme, content view and injecting a PreferenceFragment.
|
||||
*/
|
||||
public static void initialize(BaseActivityHook hook, Activity activity) {
|
||||
try {
|
||||
hook.customizeActivityTheme(activity);
|
||||
activity.setContentView(hook.getContentViewResourceId());
|
||||
|
||||
// Sanity check.
|
||||
String dataString = activity.getIntent().getDataString();
|
||||
if (!"revanced_settings_intent".equals(dataString)) {
|
||||
Logger.printException(() -> "Unknown intent: " + dataString);
|
||||
return;
|
||||
}
|
||||
|
||||
PreferenceFragment fragment = hook.createPreferenceFragment();
|
||||
hook.createToolbar(activity, fragment);
|
||||
|
||||
activity.getFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(Utils.getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
|
||||
.commit();
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "initialize failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a toolbar for the activity, replacing a dummy placeholder.
|
||||
*/
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
protected void createToolbar(Activity activity, PreferenceFragment fragment) {
|
||||
// Replace dummy placeholder toolbar.
|
||||
// This is required to fix submenu title alignment issue with Android ASOP 15+
|
||||
ViewGroup toolBarParent = activity.findViewById(
|
||||
Utils.getResourceIdentifier("revanced_toolbar_parent", "id"));
|
||||
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
|
||||
toolbarLayoutParams = dummyToolbar.getLayoutParams();
|
||||
toolBarParent.removeView(dummyToolbar);
|
||||
|
||||
// Sets appropriate system navigation bar color for the activity.
|
||||
ToolbarPreferenceFragment.setNavigationBarColor(activity.getWindow());
|
||||
|
||||
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
|
||||
toolbar.setBackgroundColor(getToolbarBackgroundColor());
|
||||
toolbar.setNavigationIcon(getNavigationIcon());
|
||||
toolbar.setNavigationOnClickListener(getNavigationClickListener(activity));
|
||||
toolbar.setTitle(Utils.getResourceIdentifier("revanced_settings_title", "string"));
|
||||
|
||||
final int margin = Utils.dipToPixels(16);
|
||||
toolbar.setTitleMarginStart(margin);
|
||||
toolbar.setTitleMarginEnd(margin);
|
||||
TextView toolbarTextView = Utils.getChildView(toolbar, false, view -> view instanceof TextView);
|
||||
if (toolbarTextView != null) {
|
||||
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
||||
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
}
|
||||
setToolbarLayoutParams(toolbar);
|
||||
|
||||
onPostToolbarSetup(activity, toolbar, fragment);
|
||||
|
||||
toolBarParent.addView(toolbar, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the activity's theme.
|
||||
*/
|
||||
protected abstract void customizeActivityTheme(Activity activity);
|
||||
|
||||
/**
|
||||
* Returns the resource ID for the content view layout.
|
||||
*/
|
||||
protected abstract int getContentViewResourceId();
|
||||
|
||||
/**
|
||||
* Returns the background color for the toolbar.
|
||||
*/
|
||||
protected abstract int getToolbarBackgroundColor();
|
||||
|
||||
/**
|
||||
* Returns the navigation icon drawable for the toolbar.
|
||||
*/
|
||||
protected abstract Drawable getNavigationIcon();
|
||||
|
||||
/**
|
||||
* Returns the click listener for the toolbar's navigation icon.
|
||||
*/
|
||||
protected abstract View.OnClickListener getNavigationClickListener(Activity activity);
|
||||
|
||||
/**
|
||||
* Creates the PreferenceFragment to be injected into the activity.
|
||||
*/
|
||||
protected PreferenceFragment createPreferenceFragment() {
|
||||
return new ToolbarPreferenceFragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs additional setup after the toolbar is configured.
|
||||
*
|
||||
* @param activity The activity hosting the toolbar.
|
||||
* @param toolbar The configured toolbar.
|
||||
* @param fragment The PreferenceFragment associated with the activity.
|
||||
*/
|
||||
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {}
|
||||
}
|
||||
@@ -4,9 +4,6 @@ import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
|
||||
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.SpoofiOSAvailability;
|
||||
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
|
||||
/**
|
||||
* Settings shared across multiple apps.
|
||||
@@ -31,9 +28,4 @@ public class BaseSettings {
|
||||
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
|
||||
public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
|
||||
public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true,
|
||||
"revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofiOSAvailability());
|
||||
// Client type must be last spoof setting due to cyclic references.
|
||||
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_NO_AUTH, true, parent(SPOOF_VIDEO_STREAMS));
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package app.revanced.extension.youtube.settings.preference;
|
||||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.preference.Preference;
|
||||
import app.revanced.extension.shared.settings.preference.LogBufferManager;
|
||||
|
||||
/**
|
||||
* A custom preference that clears the ReVanced debug log buffer when clicked.
|
||||
@@ -1,9 +1,8 @@
|
||||
package app.revanced.extension.youtube.settings.preference;
|
||||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.preference.Preference;
|
||||
import app.revanced.extension.shared.settings.preference.LogBufferManager;
|
||||
|
||||
/**
|
||||
* A custom preference that triggers exporting ReVanced debug logs to the clipboard when clicked.
|
||||
@@ -0,0 +1,150 @@
|
||||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseActivityHook;
|
||||
|
||||
@SuppressWarnings({"deprecation", "NewApi"})
|
||||
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
|
||||
/**
|
||||
* Sets toolbar for all nested preference screens.
|
||||
*/
|
||||
protected void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
|
||||
for (int i = 0, count = parentScreen.getPreferenceCount(); i < count; i++) {
|
||||
Preference childPreference = parentScreen.getPreference(i);
|
||||
if (childPreference instanceof PreferenceScreen) {
|
||||
// Recursively set sub preferences.
|
||||
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
|
||||
|
||||
childPreference.setOnPreferenceClickListener(
|
||||
childScreen -> {
|
||||
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
|
||||
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
|
||||
.findViewById(android.R.id.content)
|
||||
.getParent();
|
||||
|
||||
// Allow package-specific background customization.
|
||||
customizeDialogBackground(rootView);
|
||||
|
||||
// Fix the system navigation bar color for submenus.
|
||||
setNavigationBarColor(preferenceScreenDialog.getWindow());
|
||||
|
||||
// Fix edge-to-edge screen with Android 15 and YT 19.45+
|
||||
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
|
||||
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
|
||||
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
|
||||
|
||||
// Apply padding for display cutout in landscape.
|
||||
int leftPadding = cutoutInsets.left;
|
||||
int rightPadding = cutoutInsets.right;
|
||||
int topPadding = statusInsets.top;
|
||||
int bottomPadding = navInsets.bottom;
|
||||
|
||||
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
Toolbar toolbar = new Toolbar(childScreen.getContext());
|
||||
toolbar.setTitle(childScreen.getTitle());
|
||||
toolbar.setNavigationIcon(getBackButtonDrawable());
|
||||
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
|
||||
|
||||
final int margin = Utils.dipToPixels(16);
|
||||
toolbar.setTitleMargin(margin, 0, margin, 0);
|
||||
|
||||
TextView toolbarTextView = Utils.getChildView(toolbar,
|
||||
true, TextView.class::isInstance);
|
||||
if (toolbarTextView != null) {
|
||||
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
||||
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
}
|
||||
|
||||
// Allow package-specific toolbar customization.
|
||||
customizeToolbar(toolbar);
|
||||
|
||||
// Allow package-specific post-toolbar setup.
|
||||
onPostToolbarSetup(toolbar, preferenceScreenDialog);
|
||||
|
||||
rootView.addView(toolbar, 0);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system navigation bar color for the activity.
|
||||
* Applies the background color obtained from {@link Utils#getAppBackgroundColor()} to the navigation bar.
|
||||
* For Android 10 (API 29) and above, enforces navigation bar contrast to ensure visibility.
|
||||
*/
|
||||
public static void setNavigationBarColor(@Nullable Window window) {
|
||||
if (window == null) {
|
||||
Logger.printDebug(() -> "Cannot set navigation bar color, window is null");
|
||||
return;
|
||||
}
|
||||
|
||||
window.setNavigationBarColor(Utils.getAppBackgroundColor());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
window.setNavigationBarContrastEnforced(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawable for the back button.
|
||||
*/
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
public static Drawable getBackButtonDrawable() {
|
||||
final int backButtonResource = Utils.getResourceIdentifier(
|
||||
"revanced_settings_toolbar_arrow_left", "drawable");
|
||||
Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource);
|
||||
customizeBackButtonDrawable(drawable);
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the back button drawable.
|
||||
*/
|
||||
protected static void customizeBackButtonDrawable(Drawable drawable) {
|
||||
drawable.setTint(Utils.getAppForegroundColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to customize the dialog's root view background.
|
||||
*/
|
||||
protected void customizeDialogBackground(ViewGroup rootView) {
|
||||
rootView.setBackgroundColor(Utils.getAppBackgroundColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to customize the toolbar.
|
||||
*/
|
||||
protected void customizeToolbar(Toolbar toolbar) {
|
||||
BaseActivityHook.setToolbarLayoutParams(toolbar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to perform actions after toolbar setup.
|
||||
*/
|
||||
protected void onPostToolbarSetup(Toolbar toolbar, Dialog preferenceScreenDialog) {}
|
||||
}
|
||||
@@ -2,17 +2,22 @@ package app.revanced.extension.shared.spoof;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
|
||||
@SuppressWarnings("ConstantLocale")
|
||||
public enum ClientType {
|
||||
/**
|
||||
* Video not playable: Kids / Paid / Movie / Private / Age-restricted.
|
||||
* This client can only be used when logged out.
|
||||
*/
|
||||
// https://dumps.tadiphone.dev/dumps/oculus/eureka
|
||||
ANDROID_VR_NO_AUTH(
|
||||
ANDROID_VR_1_61_48(
|
||||
28,
|
||||
"ANDROID_VR",
|
||||
"com.google.android.apps.youtube.vr.oculus",
|
||||
@@ -26,30 +31,31 @@ public enum ClientType {
|
||||
"132.0.6808.3",
|
||||
"1.61.48",
|
||||
false,
|
||||
false,
|
||||
"Android VR No auth"
|
||||
"Android VR 1.61"
|
||||
),
|
||||
// Chromecast with Google TV 4K.
|
||||
// https://dumps.tadiphone.dev/dumps/google/kirkwood
|
||||
ANDROID_UNPLUGGED(
|
||||
29,
|
||||
"ANDROID_UNPLUGGED",
|
||||
"com.google.android.apps.youtube.unplugged",
|
||||
"Google",
|
||||
"Google TV Streamer",
|
||||
"Android",
|
||||
"14",
|
||||
"34",
|
||||
"UTT3.240625.001.K5",
|
||||
"132.0.6808.3",
|
||||
"8.49.0",
|
||||
true,
|
||||
true,
|
||||
"Android TV"
|
||||
/**
|
||||
* Uses non adaptive bitrate, which fixes audio stuttering with YT Music.
|
||||
* Does not use AV1.
|
||||
*/
|
||||
ANDROID_VR_1_43_32(
|
||||
ANDROID_VR_1_61_48.id,
|
||||
ANDROID_VR_1_61_48.clientName,
|
||||
Objects.requireNonNull(ANDROID_VR_1_61_48.packageName),
|
||||
ANDROID_VR_1_61_48.deviceMake,
|
||||
ANDROID_VR_1_61_48.deviceModel,
|
||||
ANDROID_VR_1_61_48.osName,
|
||||
ANDROID_VR_1_61_48.osVersion,
|
||||
Objects.requireNonNull(ANDROID_VR_1_61_48.androidSdkVersion),
|
||||
Objects.requireNonNull(ANDROID_VR_1_61_48.buildId),
|
||||
"107.0.5284.2",
|
||||
"1.43.32",
|
||||
ANDROID_VR_1_61_48.useAuth,
|
||||
"Android VR 1.43"
|
||||
),
|
||||
// Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children".
|
||||
// Google Pixel 9 Pro Fold
|
||||
// https://dumps.tadiphone.dev/dumps/google/barbet
|
||||
/**
|
||||
* Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children".
|
||||
* <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a>
|
||||
*/
|
||||
ANDROID_CREATOR(
|
||||
14,
|
||||
"ANDROID_CREATOR",
|
||||
@@ -63,45 +69,47 @@ public enum ClientType {
|
||||
"132.0.6779.0",
|
||||
"23.47.101",
|
||||
true,
|
||||
true,
|
||||
"Android Creator"
|
||||
"Android Studio"
|
||||
),
|
||||
IOS_UNPLUGGED(
|
||||
33,
|
||||
"IOS_UNPLUGGED",
|
||||
"com.google.ios.youtubeunplugged",
|
||||
/**
|
||||
* Internal YT client for an unreleased YT client. May stop working at any time.
|
||||
*/
|
||||
VISIONOS(101,
|
||||
"VISIONOS",
|
||||
"Apple",
|
||||
forceAVC()
|
||||
// 11 Pro Max (last device with iOS 13)
|
||||
? "iPhone12,5"
|
||||
// 15 Pro Max
|
||||
: "iPhone16,2",
|
||||
"iOS",
|
||||
forceAVC()
|
||||
// iOS 13 and earlier uses only AVC. 14+ adds VP9 and AV1.
|
||||
? "13.7.17H35"
|
||||
: "18.2.22C152",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
// Version number should be a valid iOS release.
|
||||
// https://www.ipa4fun.com/history/152043/
|
||||
forceAVC()
|
||||
// Some newer versions can also force AVC,
|
||||
// but 6.45 is the last version that supports iOS 13.
|
||||
? "6.45"
|
||||
: "8.49",
|
||||
true,
|
||||
true,
|
||||
forceAVC()
|
||||
? "iOS TV Force AVC"
|
||||
: "iOS TV"
|
||||
"RealityDevice14,1",
|
||||
"visionOS",
|
||||
"1.3.21O771",
|
||||
"0.1",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
|
||||
false,
|
||||
"visionOS"
|
||||
),
|
||||
/**
|
||||
* The device machine id for the iPad 6th Gen (iPad7,6).
|
||||
* AV1 hardware decoding is not supported.
|
||||
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
|
||||
*
|
||||
* Based on Google's actions to date, PoToken may not be required on devices with very low specs.
|
||||
* For example, suppose the User-Agent for a PlayStation 3 (with 256MB of RAM) is used.
|
||||
* Accessing 'Web' (https://www.youtube.com) will redirect to 'TV' (https://www.youtube.com/tv).
|
||||
* 'TV' target devices with very low specs, such as embedded devices, game consoles, and blu-ray players, so PoToken is not required.
|
||||
*
|
||||
* For this reason, the device machine id for the iPad 6th Gen (with 2GB of RAM),
|
||||
* the lowest spec device capable of running iPadOS 17, was used.
|
||||
*/
|
||||
IPADOS(5,
|
||||
"IOS",
|
||||
"Apple",
|
||||
"iPad7,6",
|
||||
"iPadOS",
|
||||
"17.7.10.21H450",
|
||||
"19.22.3",
|
||||
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
|
||||
false,
|
||||
"iPadOS"
|
||||
);
|
||||
|
||||
private static boolean forceAVC() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* YouTube
|
||||
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
|
||||
@@ -113,6 +121,7 @@ public enum ClientType {
|
||||
/**
|
||||
* App package name.
|
||||
*/
|
||||
@Nullable
|
||||
private final String packageName;
|
||||
|
||||
/**
|
||||
@@ -166,12 +175,6 @@ public enum ClientType {
|
||||
*/
|
||||
public final String clientVersion;
|
||||
|
||||
/**
|
||||
* If this client requires authentication and does not work
|
||||
* if logged out or in incognito mode.
|
||||
*/
|
||||
public final boolean requiresAuth;
|
||||
|
||||
/**
|
||||
* If the client should use authentication if available.
|
||||
*/
|
||||
@@ -182,19 +185,20 @@ public enum ClientType {
|
||||
*/
|
||||
public final String friendlyName;
|
||||
|
||||
@SuppressWarnings("ConstantLocale")
|
||||
/**
|
||||
* Android constructor.
|
||||
*/
|
||||
ClientType(int id,
|
||||
String clientName,
|
||||
String packageName,
|
||||
@NonNull String packageName,
|
||||
String deviceMake,
|
||||
String deviceModel,
|
||||
String osName,
|
||||
String osVersion,
|
||||
@Nullable String androidSdkVersion,
|
||||
@Nullable String buildId,
|
||||
@Nullable String cronetVersion,
|
||||
@NonNull String androidSdkVersion,
|
||||
@NonNull String buildId,
|
||||
@NonNull String cronetVersion,
|
||||
String clientVersion,
|
||||
boolean requiresAuth,
|
||||
boolean useAuth,
|
||||
String friendlyName) {
|
||||
this.id = id;
|
||||
@@ -208,36 +212,46 @@ public enum ClientType {
|
||||
this.buildId = buildId;
|
||||
this.cronetVersion = cronetVersion;
|
||||
this.clientVersion = clientVersion;
|
||||
this.requiresAuth = requiresAuth;
|
||||
this.useAuth = useAuth;
|
||||
this.friendlyName = friendlyName;
|
||||
|
||||
Locale defaultLocale = Locale.getDefault();
|
||||
if (androidSdkVersion == null) {
|
||||
// Convert version from '18.2.22C152' into '18_2_22'
|
||||
String userAgentOsVersion = osVersion
|
||||
.replaceAll("(\\d+\\.\\d+\\.\\d+).*", "$1")
|
||||
.replace(".", "_");
|
||||
// https://github.com/mitmproxy/mitmproxy/issues/4836
|
||||
this.userAgent = String.format("%s/%s (%s; U; CPU iOS %s like Mac OS X; %s)",
|
||||
packageName,
|
||||
clientVersion,
|
||||
deviceModel,
|
||||
userAgentOsVersion,
|
||||
defaultLocale
|
||||
);
|
||||
} else {
|
||||
this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s; %s; Build/%s; Cronet/%s)",
|
||||
packageName,
|
||||
clientVersion,
|
||||
osVersion,
|
||||
defaultLocale,
|
||||
deviceModel,
|
||||
Objects.requireNonNull(buildId),
|
||||
Objects.requireNonNull(cronetVersion)
|
||||
);
|
||||
}
|
||||
this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s; %s; Build/%s; Cronet/%s)",
|
||||
packageName,
|
||||
clientVersion,
|
||||
osVersion,
|
||||
defaultLocale,
|
||||
deviceModel,
|
||||
Objects.requireNonNull(buildId),
|
||||
Objects.requireNonNull(cronetVersion)
|
||||
);
|
||||
Logger.printDebug(() -> "userAgent: " + this.userAgent);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantLocale")
|
||||
ClientType(int id,
|
||||
String clientName,
|
||||
String deviceMake,
|
||||
String deviceModel,
|
||||
String osName,
|
||||
String osVersion,
|
||||
String clientVersion,
|
||||
String userAgent,
|
||||
boolean useAuth,
|
||||
String friendlyName) {
|
||||
this.id = id;
|
||||
this.clientName = clientName;
|
||||
this.deviceMake = deviceMake;
|
||||
this.deviceModel = deviceModel;
|
||||
this.osName = osName;
|
||||
this.osVersion = osVersion;
|
||||
this.clientVersion = clientVersion;
|
||||
this.userAgent = userAgent;
|
||||
this.useAuth = useAuth;
|
||||
this.friendlyName = friendlyName;
|
||||
this.packageName = null;
|
||||
this.androidSdkVersion = null;
|
||||
this.buildId = null;
|
||||
this.cronetVersion = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,38 +6,70 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.AppLanguage;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofVideoStreamsPatch {
|
||||
/**
|
||||
* Domain used for internet connectivity verification.
|
||||
* It has an empty response body and is only used to check for a 204 response code.
|
||||
* <p>
|
||||
* If an unreachable IP address (127.0.0.1) is used, no response code is provided.
|
||||
* <p>
|
||||
* YouTube handles unreachable IP addresses without issue.
|
||||
* YouTube Music has an issue with waiting for the Cronet connect timeout of 30s on mobile networks.
|
||||
* <p>
|
||||
* Using a VPN or DNS can temporarily resolve this issue,
|
||||
* But the ideal workaround is to avoid using an unreachable IP address.
|
||||
*/
|
||||
private static final String INTERNET_CONNECTION_CHECK_URI_STRING = "https://www.google.com/gen_204";
|
||||
private static final Uri INTERNET_CONNECTION_CHECK_URI = Uri.parse(INTERNET_CONNECTION_CHECK_URI_STRING);
|
||||
|
||||
private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_VIDEO_STREAMS.get();
|
||||
|
||||
private static final boolean FIX_HLS_CURRENT_TIME = SPOOF_STREAMING_DATA
|
||||
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED;
|
||||
@Nullable
|
||||
private static volatile AppLanguage languageOverride;
|
||||
|
||||
/**
|
||||
* Any unreachable ip address. Used to intentionally fail requests.
|
||||
*/
|
||||
private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0";
|
||||
private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING);
|
||||
private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_61_48;
|
||||
|
||||
/**
|
||||
* @return If this patch was included during patching.
|
||||
*/
|
||||
private static boolean isPatchIncluded() {
|
||||
public static boolean isPatchIncluded() {
|
||||
return false; // Modified during patching.
|
||||
}
|
||||
|
||||
public static boolean notSpoofingToAndroid() {
|
||||
return !isPatchIncluded()
|
||||
|| !BaseSettings.SPOOF_VIDEO_STREAMS.get()
|
||||
|| BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED;
|
||||
@Nullable
|
||||
public static AppLanguage getLanguageOverride() {
|
||||
return languageOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param language Language override for non-authenticated requests. If this is null then
|
||||
* {@link BaseSettings#SPOOF_VIDEO_STREAMS_LANGUAGE} is used.
|
||||
*/
|
||||
public static void setLanguageOverride(@Nullable AppLanguage language) {
|
||||
languageOverride = language;
|
||||
}
|
||||
|
||||
public static void setClientsToUse(List<ClientType> availableClients, ClientType client) {
|
||||
preferredClient = Objects.requireNonNull(client);
|
||||
StreamingDataRequest.setClientOrderToUse(availableClients, client);
|
||||
}
|
||||
|
||||
public static boolean spoofingToClientWithNoMultiAudioStreams() {
|
||||
return isPatchIncluded()
|
||||
&& SPOOF_STREAMING_DATA
|
||||
&& preferredClient != ClientType.IPADOS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,9 +85,9 @@ public class SpoofVideoStreamsPatch {
|
||||
String path = playerRequestUri.getPath();
|
||||
|
||||
if (path != null && path.contains("get_watch")) {
|
||||
Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri");
|
||||
Logger.printDebug(() -> "Blocking 'get_watch' by returning internet connection check uri");
|
||||
|
||||
return UNREACHABLE_HOST_URI;
|
||||
return INTERNET_CONNECTION_CHECK_URI;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "blockGetWatchRequest failure", ex);
|
||||
@@ -77,9 +109,9 @@ public class SpoofVideoStreamsPatch {
|
||||
String path = originalUri.getPath();
|
||||
|
||||
if (path != null && path.contains("initplayback")) {
|
||||
Logger.printDebug(() -> "Blocking 'initplayback' by clearing query");
|
||||
Logger.printDebug(() -> "Blocking 'initplayback' by returning internet connection check uri");
|
||||
|
||||
return originalUri.buildUpon().clearQuery().build().toString();
|
||||
return INTERNET_CONNECTION_CHECK_URI_STRING;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "blockInitPlaybackRequest failure", ex);
|
||||
@@ -252,16 +284,7 @@ public class SpoofVideoStreamsPatch {
|
||||
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get()
|
||||
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_NO_AUTH;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SpoofiOSAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get()
|
||||
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED;
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package app.revanced.extension.shared.spoof.requests;
|
||||
|
||||
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@@ -10,8 +12,10 @@ import java.util.Locale;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.requests.Requester;
|
||||
import app.revanced.extension.shared.requests.Route;
|
||||
import app.revanced.extension.shared.settings.AppLanguage;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||
|
||||
final class PlayerRoutes {
|
||||
static final Route.CompiledRoute GET_STREAMING_DATA = new Route(
|
||||
@@ -37,14 +41,16 @@ final class PlayerRoutes {
|
||||
try {
|
||||
JSONObject context = new JSONObject();
|
||||
|
||||
// Can override default language only if no login is used.
|
||||
// Could use preferred audio for all clients that do not login,
|
||||
// but if this is a fall over client it will set the language even though
|
||||
// the audio language is not selectable in the UI.
|
||||
ClientType userSelectedClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
Locale streamLocale = userSelectedClient == ClientType.ANDROID_VR_NO_AUTH
|
||||
? BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get().getLocale()
|
||||
: Locale.getDefault();
|
||||
AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride();
|
||||
if (language == null || clientType == ANDROID_VR_1_43_32) {
|
||||
// Force original audio has not overrode the language.
|
||||
// Or if YT has fallen over to the last unauthenticated client (VR 1.43), then
|
||||
// always use the app language because forcing an audio stream of specific languages
|
||||
// can sometimes fail so it's better to try and load something rather than nothing.
|
||||
language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get();
|
||||
}
|
||||
//noinspection ExtractMethodRecommender
|
||||
Locale streamLocale = language.getLocale();
|
||||
|
||||
JSONObject client = new JSONObject();
|
||||
client.put("deviceMake", clientType.deviceMake);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.revanced.extension.shared.spoof.requests;
|
||||
|
||||
import static app.revanced.extension.shared.ByteTrieSearch.convertStringsToBytes;
|
||||
import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -13,12 +14,18 @@ import java.net.HttpURLConnection;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import app.revanced.extension.shared.ByteTrieSearch;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
@@ -35,21 +42,27 @@ import app.revanced.extension.shared.spoof.ClientType;
|
||||
*/
|
||||
public class StreamingDataRequest {
|
||||
|
||||
private static final ClientType[] CLIENT_ORDER_TO_USE;
|
||||
private static volatile ClientType[] clientOrderToUse = ClientType.values();
|
||||
|
||||
static {
|
||||
ClientType[] allClientTypes = ClientType.values();
|
||||
ClientType preferredClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
public static void setClientOrderToUse(List<ClientType> availableClients, ClientType preferredClient) {
|
||||
Objects.requireNonNull(preferredClient);
|
||||
|
||||
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
|
||||
CLIENT_ORDER_TO_USE[0] = preferredClient;
|
||||
int availableClientSize = availableClients.size();
|
||||
if (!availableClients.contains(preferredClient)) {
|
||||
availableClientSize++;
|
||||
}
|
||||
|
||||
clientOrderToUse = new ClientType[availableClientSize];
|
||||
clientOrderToUse[0] = preferredClient;
|
||||
|
||||
int i = 1;
|
||||
for (ClientType c : allClientTypes) {
|
||||
for (ClientType c : availableClients) {
|
||||
if (c != preferredClient) {
|
||||
CLIENT_ORDER_TO_USE[i++] = c;
|
||||
clientOrderToUse[i++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.printDebug(() -> "Available spoof clients: " + Arrays.toString(clientOrderToUse));
|
||||
}
|
||||
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
@@ -87,6 +100,16 @@ public class StreamingDataRequest {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Strings found in the response if the video is a livestream.
|
||||
*/
|
||||
private static final ByteTrieSearch liveStreamBufferSearch = new ByteTrieSearch(
|
||||
convertStringsToBytes(
|
||||
"yt_live_broadcast",
|
||||
"yt_premiere_broadcast"
|
||||
)
|
||||
);
|
||||
|
||||
private static volatile ClientType lastSpoofedClientType;
|
||||
|
||||
public static String getLastSpoofedClientName() {
|
||||
@@ -154,7 +177,7 @@ public class StreamingDataRequest {
|
||||
}
|
||||
}
|
||||
|
||||
if (!authHeadersIncludes && clientType.requiresAuth) {
|
||||
if (!authHeadersIncludes && clientType.useAuth) {
|
||||
Logger.printDebug(() -> "Skipping client since user is not logged in: " + clientType
|
||||
+ " videoId: " + videoId);
|
||||
return null;
|
||||
@@ -193,9 +216,9 @@ public class StreamingDataRequest {
|
||||
|
||||
// Retry with different client if empty response body is received.
|
||||
int i = 0;
|
||||
for (ClientType clientType : CLIENT_ORDER_TO_USE) {
|
||||
for (ClientType clientType : clientOrderToUse) {
|
||||
// Show an error if the last client type fails, or if debug is enabled then show for all attempts.
|
||||
final boolean showErrorToast = (++i == CLIENT_ORDER_TO_USE.length) || debugEnabled;
|
||||
final boolean showErrorToast = (++i == clientOrderToUse.length) || debugEnabled;
|
||||
|
||||
HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast);
|
||||
if (connection != null) {
|
||||
@@ -215,9 +238,13 @@ public class StreamingDataRequest {
|
||||
while ((bytesRead = inputStream.read(buffer)) >= 0) {
|
||||
baos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
lastSpoofedClientType = clientType;
|
||||
if (clientType == ClientType.ANDROID_CREATOR && liveStreamBufferSearch.matches(buffer)) {
|
||||
Logger.printDebug(() -> "Skipping Android Studio as video is a livestream: " + videoId);
|
||||
} else {
|
||||
lastSpoofedClientType = clientType;
|
||||
|
||||
return ByteBuffer.wrap(baos.toByteArray());
|
||||
return ByteBuffer.wrap(baos.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package app.revanced.extension.youtube.patches;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.settings.AppLanguage;
|
||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@@ -11,16 +11,21 @@ public class ForceOriginalAudioPatch {
|
||||
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
|
||||
|
||||
/**
|
||||
* If the conditions to use this patch were present when the app launched.
|
||||
* Injection point.
|
||||
*/
|
||||
public static boolean PATCH_AVAILABLE = SpoofVideoStreamsPatch.notSpoofingToAndroid();
|
||||
|
||||
public static final class ForceOriginalAudioAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
// Check conditions of launch and now. Otherwise if spoofing is changed
|
||||
// without a restart the setting will show as available when it's not.
|
||||
return PATCH_AVAILABLE && SpoofVideoStreamsPatch.notSpoofingToAndroid();
|
||||
public static void setPreferredLanguage() {
|
||||
if (Settings.FORCE_ORIGINAL_AUDIO.get()
|
||||
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
|
||||
// If client spoofing does not use authentication and lacks multi-audio streams,
|
||||
// then can use any language code for the request and if that requested language is
|
||||
// not available YT uses the original audio language. Authenticated requests ignore
|
||||
// the language code and always use the account language. Use a language that is
|
||||
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
|
||||
// but the language is also supported natively by the Meta Quest device that
|
||||
// Android VR is spoofing.
|
||||
AppLanguage override = AppLanguage.SV;
|
||||
Logger.printDebug(() -> "Setting language override: " + override);
|
||||
SpoofVideoStreamsPatch.setLanguageOverride(override);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.shared.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -74,6 +74,10 @@ final class ButtonsFilter extends Filter {
|
||||
Settings.HIDE_ASK_BUTTON,
|
||||
"yt_fill_spark"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_SHOP_BUTTON,
|
||||
"yt_outline_bag"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_STOP_ADS_BUTTON,
|
||||
"yt_outline_slash_circle_left"
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.ByteTrieSearch;
|
||||
import app.revanced.extension.shared.ByteTrieSearch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package app.revanced.extension.youtube.patches.components;
|
||||
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.shared.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.shared.PlayerType;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||
import app.revanced.extension.youtube.ByteTrieSearch;
|
||||
import app.revanced.extension.shared.ByteTrieSearch;
|
||||
|
||||
abstract class FilterGroup<T> {
|
||||
final static class FilterGroupResult {
|
||||
|
||||
@@ -5,9 +5,9 @@ import androidx.annotation.NonNull;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import app.revanced.extension.youtube.ByteTrieSearch;
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.TrieSearch;
|
||||
import app.revanced.extension.shared.ByteTrieSearch;
|
||||
import app.revanced.extension.shared.StringTrieSearch;
|
||||
import app.revanced.extension.shared.TrieSearch;
|
||||
|
||||
abstract class FilterGroupList<V, T extends FilterGroup<V>> implements Iterable<T> {
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.ByteTrieSearch;
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.TrieSearch;
|
||||
import app.revanced.extension.shared.ByteTrieSearch;
|
||||
import app.revanced.extension.shared.StringTrieSearch;
|
||||
import app.revanced.extension.shared.TrieSearch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.shared.NavigationBar;
|
||||
import app.revanced.extension.youtube.shared.PlayerType;
|
||||
|
||||
@@ -10,7 +10,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.shared.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.patches.ChangeHeaderPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.shared.NavigationBar;
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.shared.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -9,13 +9,13 @@ import app.revanced.extension.youtube.shared.ShortsPlayerState;
|
||||
public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||
|
||||
public static final class HideAudioFlyoutMenuAvailability implements Setting.Availability {
|
||||
private static final boolean AVAILABLE_ON_LAUNCH = SpoofVideoStreamsPatch.notSpoofingToAndroid();
|
||||
private static final boolean AVAILABLE_ON_LAUNCH = !SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams();
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
// Check conditions of launch and now. Otherwise if spoofing is changed
|
||||
// without a restart the setting will show as available when it's not.
|
||||
return AVAILABLE_ON_LAUNCH && SpoofVideoStreamsPatch.notSpoofingToAndroid();
|
||||
return AVAILABLE_ON_LAUNCH && !SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch;
|
||||
import app.revanced.extension.youtube.patches.VideoInformation;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.youtube.TrieSearch;
|
||||
import app.revanced.extension.shared.TrieSearch;
|
||||
|
||||
/**
|
||||
* Searches for video id's in the proto buffer of Shorts dislike.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package app.revanced.extension.youtube.patches.spoof;
|
||||
|
||||
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.IPADOS;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofVideoStreamsPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setClientOrderToUse() {
|
||||
List<ClientType> availableClients = List.of(
|
||||
ANDROID_VR_1_61_48,
|
||||
VISIONOS,
|
||||
ANDROID_CREATOR,
|
||||
ANDROID_VR_1_43_32,
|
||||
IPADOS
|
||||
);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
availableClients, Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,120 @@
|
||||
package app.revanced.extension.youtube.settings;
|
||||
|
||||
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.view.View;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.AppLanguage;
|
||||
import app.revanced.extension.shared.settings.BaseActivityHook;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.youtube.patches.VersionCheckPatch;
|
||||
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
|
||||
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
|
||||
|
||||
/**
|
||||
* Hooks LicenseActivity.
|
||||
* <p>
|
||||
* This class is responsible for injecting our own fragment by replacing the LicenseActivity.
|
||||
* Hooks LicenseActivity to inject a custom ReVancedPreferenceFragment with a toolbar and search functionality.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LicenseActivityHook extends Activity {
|
||||
@SuppressWarnings("deprecation")
|
||||
public class LicenseActivityHook extends BaseActivityHook {
|
||||
|
||||
private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value.
|
||||
|
||||
private static ViewGroup.LayoutParams toolbarLayoutParams;
|
||||
|
||||
/**
|
||||
* Controller for managing search view components in the toolbar.
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public static SearchViewController searchViewController;
|
||||
|
||||
public static void setToolbarLayoutParams(Toolbar toolbar) {
|
||||
if (toolbarLayoutParams != null) {
|
||||
toolbar.setLayoutParams(toolbarLayoutParams);
|
||||
/**
|
||||
* Injection point
|
||||
* <p>
|
||||
* Creates an instance of LicenseActivityHook for use in static initialization.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static LicenseActivityHook createInstance() {
|
||||
return new LicenseActivityHook();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the activity theme based on dark/light mode.
|
||||
*/
|
||||
@Override
|
||||
protected void customizeActivityTheme(Activity activity) {
|
||||
final var theme = Utils.isDarkModeEnabled()
|
||||
? "Theme.YouTube.Settings.Dark"
|
||||
: "Theme.YouTube.Settings";
|
||||
activity.setTheme(Utils.getResourceIdentifier(theme, "style"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource ID for the YouTube settings layout.
|
||||
*/
|
||||
@Override
|
||||
protected int getContentViewResourceId() {
|
||||
return Utils.getResourceIdentifier("revanced_settings_with_toolbar", "layout");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the toolbar background color based on dark/light mode.
|
||||
*/
|
||||
@Override
|
||||
protected int getToolbarBackgroundColor() {
|
||||
final String colorName = Utils.isDarkModeEnabled()
|
||||
? "yt_black3"
|
||||
: "yt_white1";
|
||||
return Utils.getColorFromString(colorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the navigation icon drawable for the toolbar.
|
||||
*/
|
||||
@Override
|
||||
protected Drawable getNavigationIcon() {
|
||||
return ReVancedPreferenceFragment.getBackButtonDrawable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the click listener for the navigation icon.
|
||||
*/
|
||||
@Override
|
||||
protected View.OnClickListener getNavigationClickListener(Activity activity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds search view components to the toolbar for ReVancedPreferenceFragment.
|
||||
*
|
||||
* @param activity The activity hosting the toolbar.
|
||||
* @param toolbar The configured toolbar.
|
||||
* @param fragment The PreferenceFragment associated with the activity.
|
||||
*/
|
||||
@Override
|
||||
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {
|
||||
if (fragment instanceof ReVancedPreferenceFragment) {
|
||||
searchViewController = SearchViewController.addSearchViewComponents(
|
||||
activity, toolbar, (ReVancedPreferenceFragment) fragment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ReVancedPreferenceFragment for the activity.
|
||||
*/
|
||||
@Override
|
||||
protected PreferenceFragment createPreferenceFragment() {
|
||||
return new ReVancedPreferenceFragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Overrides the ReVanced settings language.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static Context getAttachBaseContext(Context original) {
|
||||
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
|
||||
if (language == AppLanguage.DEFAULT) {
|
||||
@@ -57,6 +127,7 @@ public class LicenseActivityHook extends Activity {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static boolean useCairoSettingsFragment(boolean original) {
|
||||
// Early targets have layout issues and it's better to always force off.
|
||||
if (!VersionCheckPatch.IS_19_34_OR_GREATER) {
|
||||
@@ -80,87 +151,6 @@ public class LicenseActivityHook extends Activity {
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Hooks LicenseActivity#onCreate in order to inject our own fragment.
|
||||
*/
|
||||
public static void initialize(Activity licenseActivity) {
|
||||
try {
|
||||
setActivityTheme(licenseActivity);
|
||||
ReVancedPreferenceFragment.setNavigationBarColor(licenseActivity.getWindow());
|
||||
licenseActivity.setContentView(getResourceIdentifier(
|
||||
"revanced_settings_with_toolbar", "layout"));
|
||||
|
||||
// Sanity check.
|
||||
String dataString = licenseActivity.getIntent().getDataString();
|
||||
if (!"revanced_settings_intent".equals(dataString)) {
|
||||
Logger.printException(() -> "Unknown intent: " + dataString);
|
||||
return;
|
||||
}
|
||||
|
||||
PreferenceFragment fragment = new ReVancedPreferenceFragment();
|
||||
createToolbar(licenseActivity, fragment);
|
||||
|
||||
//noinspection deprecation
|
||||
licenseActivity.getFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
|
||||
.commit();
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "initialize failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
private static void createToolbar(Activity activity, PreferenceFragment fragment) {
|
||||
// Replace dummy placeholder toolbar.
|
||||
// This is required to fix submenu title alignment issue with Android ASOP 15+
|
||||
ViewGroup toolBarParent = activity.findViewById(
|
||||
getResourceIdentifier("revanced_toolbar_parent", "id"));
|
||||
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
|
||||
toolbarLayoutParams = dummyToolbar.getLayoutParams();
|
||||
toolBarParent.removeView(dummyToolbar);
|
||||
|
||||
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
|
||||
toolbar.setBackgroundColor(getToolbarBackgroundColor());
|
||||
toolbar.setNavigationIcon(ReVancedPreferenceFragment.getBackButtonDrawable());
|
||||
toolbar.setTitle(getResourceIdentifier("revanced_settings_title", "string"));
|
||||
|
||||
final int margin = Utils.dipToPixels(16);
|
||||
toolbar.setTitleMarginStart(margin);
|
||||
toolbar.setTitleMarginEnd(margin);
|
||||
TextView toolbarTextView = Utils.getChildView(toolbar, false,
|
||||
view -> view instanceof TextView);
|
||||
if (toolbarTextView != null) {
|
||||
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
||||
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
}
|
||||
setToolbarLayoutParams(toolbar);
|
||||
|
||||
// Add Search bar only for ReVancedPreferenceFragment.
|
||||
if (fragment instanceof ReVancedPreferenceFragment) {
|
||||
searchViewController = SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
|
||||
}
|
||||
|
||||
toolBarParent.addView(toolbar, 0);
|
||||
}
|
||||
|
||||
public static void setActivityTheme(Activity activity) {
|
||||
final var theme = Utils.isDarkModeEnabled()
|
||||
? "Theme.YouTube.Settings.Dark"
|
||||
: "Theme.YouTube.Settings";
|
||||
activity.setTheme(getResourceIdentifier(theme, "style"));
|
||||
}
|
||||
|
||||
public static int getToolbarBackgroundColor() {
|
||||
final String colorName = Utils.isDarkModeEnabled()
|
||||
? "yt_black3"
|
||||
: "yt_white1";
|
||||
|
||||
return Utils.getColorFromString(colorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* Updates dark/light mode since YT settings can force light/dark mode
|
||||
* which can differ from the global device settings.
|
||||
*/
|
||||
@@ -173,6 +163,10 @@ public class LicenseActivityHook extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles configuration changes, such as orientation, to update the search view.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void handleConfigurationChanged(Activity activity, Configuration newConfig) {
|
||||
if (searchViewController != null) {
|
||||
searchViewController.handleOrientationChange(newConfig.orientation);
|
||||
|
||||
@@ -12,7 +12,6 @@ import static app.revanced.extension.youtube.patches.ChangeHeaderPatch.HeaderLog
|
||||
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.ChangeStartPageTypeAvailability;
|
||||
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
|
||||
import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode;
|
||||
import static app.revanced.extension.youtube.patches.ForceOriginalAudioPatch.ForceOriginalAudioAvailability;
|
||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
|
||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
|
||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
|
||||
@@ -42,6 +41,7 @@ import app.revanced.extension.shared.settings.LongSetting;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.settings.StringSetting;
|
||||
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
|
||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
|
||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
|
||||
@@ -75,7 +75,7 @@ public class Settings extends BaseSettings {
|
||||
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);
|
||||
|
||||
// Audio
|
||||
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, new ForceOriginalAudioAvailability());
|
||||
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
|
||||
|
||||
// Ads
|
||||
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
|
||||
@@ -230,6 +230,7 @@ public class Settings extends BaseSettings {
|
||||
public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE);
|
||||
public static final BooleanSetting HIDE_SAVE_BUTTON = new BooleanSetting("revanced_hide_save_button", FALSE);
|
||||
public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE);
|
||||
public static final BooleanSetting HIDE_SHOP_BUTTON = new BooleanSetting("revanced_hide_shop_button", FALSE);
|
||||
public static final BooleanSetting HIDE_STOP_ADS_BUTTON = new BooleanSetting("revanced_hide_stop_ads_button", TRUE);
|
||||
public static final BooleanSetting HIDE_THANKS_BUTTON = new BooleanSetting("revanced_hide_thanks_button", TRUE);
|
||||
|
||||
@@ -357,6 +358,7 @@ public class Settings extends BaseSettings {
|
||||
public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE);
|
||||
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
|
||||
"revanced_spoof_device_dimensions_user_dialog_message");
|
||||
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS));
|
||||
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
|
||||
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
|
||||
|
||||
|
||||
@@ -6,18 +6,26 @@ import android.content.Context;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import app.revanced.extension.youtube.patches.ForceOriginalAudioPatch;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings({"deprecation", "unused"})
|
||||
public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
|
||||
|
||||
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
|
||||
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|
||||
|| !(Settings.SPOOF_VIDEO_STREAMS.get()
|
||||
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR);
|
||||
|
||||
{
|
||||
if (!ForceOriginalAudioPatch.PATCH_AVAILABLE) {
|
||||
if (!available) {
|
||||
// Show why force audio is not available.
|
||||
String summary = str("revanced_force_original_audio_not_available");
|
||||
setSummary(summary);
|
||||
setSummaryOn(summary);
|
||||
setSummaryOff(summary);
|
||||
super.setSummary(summary);
|
||||
super.setSummaryOn(summary);
|
||||
super.setSummaryOff(summary);
|
||||
super.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +41,23 @@ public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
|
||||
public ForceOriginalAudioSwitchPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSummary(CharSequence summary) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.setSummary(summary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||
public class HideAudioFlyoutMenuPreference extends SwitchPreference {
|
||||
|
||||
{
|
||||
// Audio menu is not available if spoofing to Android client type.
|
||||
if (!SpoofVideoStreamsPatch.notSpoofingToAndroid()) {
|
||||
// Audio menu is not available if spoofing to most client types.
|
||||
if (SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
|
||||
String summary = str("revanced_hide_player_flyout_audio_track_not_available");
|
||||
setSummary(summary);
|
||||
setSummaryOn(summary);
|
||||
|
||||
@@ -3,11 +3,7 @@ package app.revanced.extension.youtube.settings.preference;
|
||||
import static app.revanced.extension.shared.StringRef.str;
|
||||
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceCategory;
|
||||
@@ -17,11 +13,6 @@ import android.preference.SwitchPreference;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
@@ -40,16 +31,16 @@ import java.util.regex.Pattern;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment;
|
||||
import app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory;
|
||||
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||
import app.revanced.extension.youtube.settings.LicenseActivityHook;
|
||||
import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup;
|
||||
|
||||
/**
|
||||
* Preference fragment for ReVanced settings.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
@SuppressWarnings({"deprecation", "NewApi"})
|
||||
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
|
||||
|
||||
/**
|
||||
* The main PreferenceScreen used to display the current set of preferences.
|
||||
@@ -70,31 +61,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
*/
|
||||
private final List<AbstractPreferenceSearchData<?>> allPreferences = new ArrayList<>();
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
public static Drawable getBackButtonDrawable() {
|
||||
final int backButtonResource = getResourceIdentifier("revanced_settings_toolbar_arrow_left", "drawable");
|
||||
Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource);
|
||||
drawable.setTint(Utils.getAppForegroundColor());
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system navigation bar color for the activity.
|
||||
* Applies the background color obtained from {@link Utils#getAppBackgroundColor()} to the navigation bar.
|
||||
* For Android 10 (API 29) and above, enforces navigation bar contrast to ensure visibility.
|
||||
*/
|
||||
public static void setNavigationBarColor(@Nullable Window window) {
|
||||
if (window == null) {
|
||||
Logger.printDebug(() -> "Cannot set navigation bar color, window is null");
|
||||
return;
|
||||
}
|
||||
|
||||
window.setNavigationBarColor(Utils.getAppBackgroundColor());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
window.setNavigationBarContrastEnforced(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the preference fragment, copying the original screen to allow full restoration.
|
||||
*/
|
||||
@@ -139,8 +105,28 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets toolbar for all nested preference screens.
|
||||
*/
|
||||
@Override
|
||||
protected void customizeToolbar(Toolbar toolbar) {
|
||||
LicenseActivityHook.setToolbarLayoutParams(toolbar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform actions after toolbar setup.
|
||||
*/
|
||||
@Override
|
||||
protected void onPostToolbarSetup(Toolbar toolbar, Dialog preferenceScreenDialog) {
|
||||
if (LicenseActivityHook.searchViewController != null
|
||||
&& LicenseActivityHook.searchViewController.isSearchActive()) {
|
||||
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively collects all preferences from the screen or group.
|
||||
*
|
||||
* @param includeDepth Menu depth to start including preferences.
|
||||
* A value of 0 adds all preferences.
|
||||
*/
|
||||
@@ -222,75 +208,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
preferenceScreen.addPreference(noResultsPreference);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets toolbar for all nested preference screens.
|
||||
*/
|
||||
private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
|
||||
for (int i = 0, count = parentScreen.getPreferenceCount(); i < count; i++) {
|
||||
Preference childPreference = parentScreen.getPreference(i);
|
||||
if (childPreference instanceof PreferenceScreen) {
|
||||
// Recursively set sub preferences.
|
||||
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
|
||||
|
||||
childPreference.setOnPreferenceClickListener(
|
||||
childScreen -> {
|
||||
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
|
||||
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
|
||||
.findViewById(android.R.id.content)
|
||||
.getParent();
|
||||
|
||||
// Fix the system navigation bar color for submenus.
|
||||
setNavigationBarColor(preferenceScreenDialog.getWindow());
|
||||
|
||||
// Fix edge-to-edge screen with Android 15 and YT 19.45+
|
||||
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
|
||||
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
|
||||
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
|
||||
|
||||
// Apply padding for display cutout in landscape.
|
||||
int leftPadding = cutoutInsets.left;
|
||||
int rightPadding = cutoutInsets.right;
|
||||
int topPadding = statusInsets.top;
|
||||
int bottomPadding = navInsets.bottom;
|
||||
|
||||
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
Toolbar toolbar = new Toolbar(childScreen.getContext());
|
||||
toolbar.setTitle(childScreen.getTitle());
|
||||
toolbar.setNavigationIcon(getBackButtonDrawable());
|
||||
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
|
||||
|
||||
final int margin = Utils.dipToPixels(16);
|
||||
toolbar.setTitleMargin(margin, 0, margin, 0);
|
||||
|
||||
TextView toolbarTextView = Utils.getChildView(toolbar,
|
||||
true, TextView.class::isInstance);
|
||||
if (toolbarTextView != null) {
|
||||
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
|
||||
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
|
||||
}
|
||||
|
||||
LicenseActivityHook.setToolbarLayoutParams(toolbar);
|
||||
|
||||
if (LicenseActivityHook.searchViewController != null
|
||||
&& LicenseActivityHook.searchViewController.isSearchActive()) {
|
||||
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
|
||||
}
|
||||
|
||||
rootView.addView(toolbar, 0);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package app.revanced.extension.youtube.settings.preference;
|
||||
|
||||
import static app.revanced.extension.shared.StringRef.str;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import app.revanced.extension.shared.settings.preference.SortedListPreference;
|
||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||
|
||||
@SuppressWarnings({"deprecation", "unused"})
|
||||
public class SpoofAudioSelectorListPreference extends SortedListPreference {
|
||||
|
||||
private final boolean available;
|
||||
|
||||
{
|
||||
if (SpoofVideoStreamsPatch.getLanguageOverride() != null) {
|
||||
available = false;
|
||||
super.setEnabled(false);
|
||||
super.setSummary(str("revanced_spoof_video_streams_language_not_available"));
|
||||
} else {
|
||||
available = true;
|
||||
}
|
||||
}
|
||||
|
||||
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public SpoofAudioSelectorListPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSummary(CharSequence summary) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.setSummary(summary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings({"deprecation", "unused"})
|
||||
public class SpoofStreamingDataSideEffectsPreference extends Preference {
|
||||
@@ -69,7 +70,7 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
ClientType clientType = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
ClientType clientType = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
if (currentClientType == clientType) {
|
||||
return;
|
||||
}
|
||||
@@ -78,21 +79,25 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
|
||||
Logger.printDebug(() -> "Updating spoof stream side effects preference");
|
||||
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());
|
||||
|
||||
String key = "revanced_spoof_video_streams_about_" +
|
||||
(clientType == ClientType.IOS_UNPLUGGED
|
||||
? "ios_tv"
|
||||
: "android");
|
||||
String title = str(key + "_title");
|
||||
String summary = str(key + "_summary");
|
||||
setTitle(str("revanced_spoof_video_streams_about_title"));
|
||||
|
||||
// Android VR supports AV1 but all other clients do not.
|
||||
if (clientType != ClientType.ANDROID_VR_NO_AUTH) {
|
||||
String summary = str(clientType == ClientType.IPADOS
|
||||
? "revanced_spoof_video_streams_about_ipados_summary"
|
||||
// Same base side effects for Android VR, Android Studio, and visionOS.
|
||||
: "revanced_spoof_video_streams_about_android_summary");
|
||||
|
||||
if (clientType == ClientType.IPADOS) {
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1");
|
||||
} else if (clientType == ClientType.VISIONOS) {
|
||||
summary = str("revanced_spoof_video_streams_about_experimental")
|
||||
+ '\n' + summary
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_kids_videos");
|
||||
} else if (clientType == ClientType.ANDROID_CREATOR) {
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_kids_videos");
|
||||
}
|
||||
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
|
||||
|
||||
setTitle(title);
|
||||
setSummary(summary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
||||
org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
version = 5.37.0-dev.2
|
||||
version = 5.40.0-dev.3
|
||||
|
||||
@@ -264,6 +264,14 @@ public final class app/revanced/patches/instagram/ads/HideAdsPatchKt {
|
||||
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/instagram/feed/LimitFeedToFollowedProfilesKt {
|
||||
public static final fun getLimitFeedToFollowedProfiles ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt {
|
||||
public static final fun getHideExportFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt {
|
||||
public static final fun getHideNavigationButtonsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -272,6 +280,10 @@ public final class app/revanced/patches/instagram/hide/stories/HideStoriesKt {
|
||||
public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/instagram/misc/extension/SharedExtensionPatchKt {
|
||||
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
|
||||
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -368,8 +380,9 @@ public final class app/revanced/patches/music/layout/premium/HideGetPremiumPatch
|
||||
public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatchKt {
|
||||
public static final fun getRemoveUpgradeButtonPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public final class app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatchKt {
|
||||
public static final fun getHideUpgradeButton ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static final fun getRemoveUpgradeButton ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatchKt {
|
||||
@@ -392,7 +405,21 @@ public final class app/revanced/patches/music/misc/gms/GmsCoreSupportPatchKt {
|
||||
public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsKt {
|
||||
public final class app/revanced/patches/music/misc/settings/PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/misc/settings/PreferenceScreen;
|
||||
public fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreenPreference;)V
|
||||
public final fun getADS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||
public final fun getGENERAL ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||
public final fun getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||
public final fun getPLAYER ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/settings/SettingsPatchKt {
|
||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatchKt {
|
||||
public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
@@ -1648,7 +1675,6 @@ public final class app/revanced/patches/youtube/misc/settings/PreferenceScreen :
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/settings/SettingsPatchKt {
|
||||
public static final fun addSettingPreference (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V
|
||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.instagram.feed
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
|
||||
internal val mainFeedRequestClassFingerprint = fingerprint {
|
||||
strings("Request{mReason=", ", mInstanceNumber=")
|
||||
}
|
||||
|
||||
context(BytecodePatchContext)
|
||||
internal val initMainFeedRequestFingerprint get() = fingerprint {
|
||||
custom { method, classDef ->
|
||||
method.name == "<init>" &&
|
||||
classDef == mainFeedRequestClassFingerprint.classDef
|
||||
}
|
||||
}
|
||||
|
||||
internal val mainFeedHeaderMapFinderFingerprint = fingerprint {
|
||||
strings("pagination_source", "FEED_REQUEST_SENT")
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package app.revanced.patches.instagram.feed
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/instagram/feed/LimitFeedToFollowedProfiles;"
|
||||
|
||||
@Suppress("unused")
|
||||
val limitFeedToFollowedProfiles = bytecodePatch(
|
||||
name = "Limit feed to followed profiles",
|
||||
description = "Filters the home feed to display only content from profiles you follow.",
|
||||
use = false
|
||||
) {
|
||||
compatibleWith("com.instagram.android")
|
||||
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
execute {
|
||||
/**
|
||||
* Since the header field is obfuscated and there is no easy way to identify it among all the class fields,
|
||||
* an additional method is fingerprinted.
|
||||
* This method uses the map, so we can get the field name of the map field using this.
|
||||
*/
|
||||
val mainFeedRequestHeaderFieldName: String
|
||||
|
||||
with(mainFeedHeaderMapFinderFingerprint.method) {
|
||||
mainFeedRequestHeaderFieldName = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>().let { ref ->
|
||||
ref?.type == "Ljava/util/Map;" &&
|
||||
ref.definingClass == mainFeedRequestClassFingerprint.classDef.toString()
|
||||
|
||||
}
|
||||
}.let { instructionIndex ->
|
||||
getInstruction(instructionIndex).getReference<FieldReference>()!!.name
|
||||
}
|
||||
}
|
||||
|
||||
initMainFeedRequestFingerprint.method.apply {
|
||||
// Finds the instruction where the map is being initialized in the constructor
|
||||
val getHeaderIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>().let {
|
||||
it?.name == mainFeedRequestHeaderFieldName
|
||||
}
|
||||
}
|
||||
|
||||
val paramHeaderRegister = getInstruction<TwoRegisterInstruction>(getHeaderIndex).registerA
|
||||
|
||||
// Replace the `pagination_source` header value with `following` in the feed/timeline request.
|
||||
addInstructions(
|
||||
getHeaderIndex,
|
||||
"""
|
||||
invoke-static { v$paramHeaderRegister }, $EXTENSION_CLASS_DESCRIPTOR->setFollowingHeader(Ljava/util/Map;)Ljava/util/Map;
|
||||
move-result-object v$paramHeaderRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
package app.revanced.patches.instagram.hide.explore
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
internal val exploreResponseJsonParserFingerprint = fingerprint {
|
||||
strings("sectional_items", "ExploreTopicalFeedResponse")
|
||||
custom { method, _ -> method.name == "parseFromJson" }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package app.revanced.patches.instagram.hide.explore
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
val hideExportFeedPatch = bytecodePatch(
|
||||
name = "Hide explore feed",
|
||||
description = "Hides posts and reels from the explore/search page.",
|
||||
use = false
|
||||
) {
|
||||
compatibleWith("com.instagram.android")
|
||||
|
||||
execute {
|
||||
exploreResponseJsonParserFingerprint.method.apply {
|
||||
val sectionalItemStringIndex = exploreResponseJsonParserFingerprint.stringMatches!!.first().index
|
||||
val sectionalItemStringRegister = getInstruction<OneRegisterInstruction>(sectionalItemStringIndex).registerA
|
||||
|
||||
/**
|
||||
* Replacing the JSON key we want to skip with a random string that is not a valid JSON key.
|
||||
* This way the feeds array will never be populated.
|
||||
* Received JSON keys that are not handled are simply ignored, so there are no side effects.
|
||||
*/
|
||||
replaceInstruction(
|
||||
sectionalItemStringIndex,
|
||||
"const-string v$sectionalItemStringRegister, \"BOGUS\""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ internal val tabCreateButtonsLoopEndFingerprint = fingerprint {
|
||||
Opcode.IPUT_OBJECT,
|
||||
// Injection Jump
|
||||
Opcode.ADD_INT_LIT8, //Increase Index
|
||||
Opcode.GOTO_16 // Jump to loopStart
|
||||
Opcode.GOTO // Jump to loopStart
|
||||
// LoopEnd
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
|
||||
description = "Hides navigation bar buttons, such as the Reels and Create button.",
|
||||
use = false
|
||||
) {
|
||||
compatibleWith("com.instagram.android")
|
||||
compatibleWith("com.instagram.android"("397.1.0.52.81"))
|
||||
|
||||
val hideReels by booleanOption(
|
||||
key = "hideReels",
|
||||
@@ -49,7 +49,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
|
||||
val freeRegister = findFreeRegister(insertIndex, loopIndexRegister)
|
||||
val instruction = getInstruction(endIndex - 1)
|
||||
|
||||
var instructions = buildString {
|
||||
val instructions = buildString {
|
||||
if (hideCreate!!) {
|
||||
appendLine(
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.patches.instagram.misc.extension
|
||||
|
||||
import app.revanced.patches.instagram.misc.extension.hooks.applicationInitHook
|
||||
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
||||
|
||||
val sharedExtensionPatch = sharedExtensionPatch(
|
||||
"instagram",
|
||||
applicationInitHook,
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.patches.instagram.misc.extension.hooks
|
||||
|
||||
import app.revanced.patches.shared.misc.extension.extensionHook
|
||||
|
||||
internal val applicationInitHook = extensionHook {
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && classDef.endsWith("/InstagramAppShell;")
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,27 @@
|
||||
package app.revanced.patches.music.ad.video
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideVideoAdsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val hideVideoAdsPatch = bytecodePatch(
|
||||
name = "Hide music video ads",
|
||||
description = "Hides ads that appear while listening to or streaming music videos, podcasts, or songs.",
|
||||
description = "Adds an option to hide ads that appear while listening to or streaming music videos, podcasts, or songs.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
@@ -15,9 +29,21 @@ val hideVideoAdsPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("music", "ad.video.hideVideoAdsPatch")
|
||||
|
||||
PreferenceScreen.ADS.addPreferences(
|
||||
SwitchPreference("revanced_music_hide_video_ads"),
|
||||
)
|
||||
|
||||
navigate(showVideoAdsParentFingerprint.originalMethod)
|
||||
.to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1)
|
||||
.stop()
|
||||
.addInstruction(0, "const/4 p1, 0x0")
|
||||
.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->showVideoAds(Z)Z
|
||||
move-result p1
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package app.revanced.patches.music.audio.exclusiveaudio
|
||||
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.util.returnEarly
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -8,6 +10,11 @@ val enableExclusiveAudioPlaybackPatch = bytecodePatch(
|
||||
name = "Enable exclusive audio playback",
|
||||
description = "Enables the option to play audio without video.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
|
||||
@@ -4,13 +4,27 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.util.findFreeRegister
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/PermanentRepeatPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val permanentRepeatPatch = bytecodePatch(
|
||||
name = "Permanent repeat",
|
||||
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.",
|
||||
use = false,
|
||||
description = "Adds an option to always repeat even if the playlist ends or another track is played."
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
@@ -18,13 +32,27 @@ val permanentRepeatPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("music", "interaction.permanentrepeat.permanentRepeatPatch")
|
||||
|
||||
PreferenceScreen.PLAYER.addPreferences(
|
||||
SwitchPreference("revanced_music_play_permanent_repeat"),
|
||||
)
|
||||
|
||||
val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex
|
||||
val repeatIndex = startIndex + 1
|
||||
|
||||
repeatTrackFingerprint.method.apply {
|
||||
// Start index is at a branch, but the same
|
||||
// register is clobbered in both branch paths.
|
||||
val freeRegister = findFreeRegister(startIndex + 1)
|
||||
|
||||
addInstructionsWithLabels(
|
||||
startIndex,
|
||||
"goto :repeat",
|
||||
"""
|
||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->permanentRepeat()Z
|
||||
move-result v$freeRegister
|
||||
if-nez v$freeRegister, :repeat
|
||||
""",
|
||||
ExternalLabel("repeat", instructions[repeatIndex]),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,32 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
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.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.util.addInstructionsAtControlFlowLabel
|
||||
import app.revanced.util.findFreeRegister
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val hideCategoryBar = bytecodePatch(
|
||||
name = "Hide category bar",
|
||||
description = "Hides the category bar at the top of the homepage.",
|
||||
use = false,
|
||||
description = "Adds an option to hide the category bar at the top of the homepage."
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
@@ -19,16 +34,27 @@ val hideCategoryBar = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("music", "layout.compactheader.hideCategoryBar")
|
||||
|
||||
PreferenceScreen.GENERAL.addPreferences(
|
||||
SwitchPreference("revanced_music_hide_category_bar"),
|
||||
)
|
||||
|
||||
constructCategoryBarFingerprint.method.apply {
|
||||
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
val freeRegister = findFreeRegister(insertIndex, register)
|
||||
|
||||
addInstructions(
|
||||
addInstructionsWithLabels(
|
||||
insertIndex,
|
||||
"""
|
||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar()Z
|
||||
move-result v$freeRegister
|
||||
if-eqz v$freeRegister, :show
|
||||
const/16 v$freeRegister, 0x8
|
||||
invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V
|
||||
:show
|
||||
nop
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,16 +1,31 @@
|
||||
package app.revanced.patches.music.layout.premium
|
||||
|
||||
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.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideGetPremiumPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val hideGetPremiumPatch = bytecodePatch(
|
||||
name = "Hide 'Get Music Premium' label",
|
||||
description = "Hides the \"Get Music Premium\" label from the account menu and settings.",
|
||||
name = "Hide 'Get Music Premium'",
|
||||
description = "Adds an option to hide the \"Get Music Premium\" label in the settings and account menu.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
@@ -18,6 +33,12 @@ val hideGetPremiumPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("music", "layout.premium.hideGetPremiumPatch")
|
||||
|
||||
PreferenceScreen.ADS.addPreferences(
|
||||
SwitchPreference("revanced_music_hide_get_premium_label"),
|
||||
)
|
||||
|
||||
hideGetPremiumFingerprint.method.apply {
|
||||
val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex
|
||||
|
||||
@@ -37,12 +58,17 @@ val hideGetPremiumPatch = bytecodePatch(
|
||||
)
|
||||
}
|
||||
|
||||
membershipSettingsFingerprint.method.addInstructions(
|
||||
membershipSettingsFingerprint.method.addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
""",
|
||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideGetPremiumLabel()Z
|
||||
move-result v0
|
||||
if-eqz v0, :show
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
:show
|
||||
nop
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,31 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.newLabel
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val removeUpgradeButtonPatch = bytecodePatch(
|
||||
name = "Remove upgrade button",
|
||||
description = "Removes the upgrade tab from the pivot bar.",
|
||||
val hideUpgradeButton = bytecodePatch(
|
||||
name = "Hide upgrade button",
|
||||
description = "Hides the upgrade tab from the pivot bar.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
@@ -25,6 +39,15 @@ val removeUpgradeButtonPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("music", "layout.upgradebutton.hideUpgradeButtonPatch")
|
||||
|
||||
// TODO: Add an extension patch to allow this to be enabled/disabled in app.
|
||||
if (false) {
|
||||
PreferenceScreen.ADS.addPreferences(
|
||||
SwitchPreference("revanced_music_hide_upgrade_button")
|
||||
)
|
||||
}
|
||||
|
||||
pivotBarConstructorFingerprint.method.apply {
|
||||
val pivotBarElementFieldReference =
|
||||
getInstruction(pivotBarConstructorFingerprint.patternMatch!!.endIndex - 1)
|
||||
@@ -77,3 +100,9 @@ val removeUpgradeButtonPatch = bytecodePatch(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Patch was renamed", ReplaceWith("hideUpgradeButton"))
|
||||
@Suppress("unused")
|
||||
val removeUpgradeButton = bytecodePatch{
|
||||
dependsOn(hideUpgradeButton)
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package app.revanced.patches.music.misc.androidauto
|
||||
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.util.returnEarly
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -8,6 +10,11 @@ val bypassCertificateChecksPatch = bytecodePatch(
|
||||
name = "Bypass certificate checks",
|
||||
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
package app.revanced.patches.music.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.util.returnEarly
|
||||
|
||||
val backgroundPlaybackPatch = bytecodePatch(
|
||||
name = "Remove background playback restrictions",
|
||||
description = "Removes restrictions on background playback, including playing kids videos in the background.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
@@ -20,12 +27,6 @@ val backgroundPlaybackPatch = bytecodePatch(
|
||||
"return-void",
|
||||
)
|
||||
|
||||
backgroundPlaybackDisableFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""",
|
||||
)
|
||||
backgroundPlaybackDisableFingerprint.method.returnEarly(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package app.revanced.patches.music.misc.gms
|
||||
|
||||
import app.revanced.patcher.patch.Option
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
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.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
|
||||
import app.revanced.patches.shared.castContextFetchFingerprint
|
||||
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
|
||||
import app.revanced.patches.shared.primeMethodFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -33,4 +38,23 @@ private fun gmsCoreSupportResourcePatch(
|
||||
toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
|
||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||
spoofedPackageSignature = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875",
|
||||
)
|
||||
executeBlock = {
|
||||
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
|
||||
|
||||
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
|
||||
PreferenceScreen.MISC.addPreferences(
|
||||
IntentPreference(
|
||||
"microg_settings",
|
||||
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
|
||||
"$gmsCoreVendorGroupId.android.gms"
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
) {
|
||||
dependsOn(
|
||||
addResourcesPatch,
|
||||
settingsPatch
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.music.misc.settings
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
internal val googleApiActivityFingerprint = fingerprint {
|
||||
returns("V")
|
||||
parameters("Landroid/os/Bundle;")
|
||||
custom { method, classDef ->
|
||||
classDef.endsWith("GoogleApiActivity;") && method.name == "onCreate"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package app.revanced.patches.music.misc.settings
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.*
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.settings.settingsPatch
|
||||
import app.revanced.util.*
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
|
||||
private const val GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/music/settings/GoogleApiActivityHook;"
|
||||
|
||||
private val preferences = mutableSetOf<BasePreference>()
|
||||
|
||||
|
||||
private val settingsResourcePatch = resourcePatch {
|
||||
dependsOn(
|
||||
resourceMappingPatch,
|
||||
settingsPatch(
|
||||
IntentPreference(
|
||||
titleKey = "revanced_settings_title",
|
||||
summaryKey = null,
|
||||
intent = newIntent("revanced_settings_intent"),
|
||||
) to "settings_headers",
|
||||
preferences
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
|
||||
// TODO: Remove this when search will be abstract.
|
||||
copyResources(
|
||||
"settings",
|
||||
ResourceGroup(
|
||||
"layout",
|
||||
"revanced_music_settings_with_toolbar.xml"
|
||||
)
|
||||
)
|
||||
|
||||
val targetResource = "values/styles.xml"
|
||||
inputStreamFromBundledResource(
|
||||
"settings/music",
|
||||
targetResource,
|
||||
)!!.let { inputStream ->
|
||||
"resources".copyXmlNode(
|
||||
document(inputStream),
|
||||
document("res/$targetResource"),
|
||||
).close()
|
||||
}
|
||||
|
||||
// Remove horizontal divider from the settings Preferences.
|
||||
val styleFile = get("res/values/styles.xml")
|
||||
styleFile.writeText(
|
||||
styleFile.readText()
|
||||
.replace(
|
||||
"allowDividerAbove\">true",
|
||||
"allowDividerAbove\">false"
|
||||
).replace(
|
||||
"allowDividerBelow\">true",
|
||||
"allowDividerBelow\">false"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val settingsPatch = bytecodePatch(
|
||||
description = "Adds settings for ReVanced to YouTube Music.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsResourcePatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("music", "misc.settings.settingsPatch")
|
||||
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
||||
|
||||
// Should make a separate debugging patch, but for now include it with all installations.
|
||||
PreferenceScreen.MISC.addPreferences(
|
||||
PreferenceScreenPreference(
|
||||
key = "revanced_debug_screen",
|
||||
sorting = Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_debug"),
|
||||
NonInteractivePreference(
|
||||
"revanced_debug_export_logs_to_clipboard",
|
||||
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
||||
selectable = true
|
||||
),
|
||||
NonInteractivePreference(
|
||||
"revanced_debug_logs_clear_buffer",
|
||||
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
||||
selectable = true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Add an "About" preference to the top.
|
||||
preferences += NonInteractivePreference(
|
||||
key = "revanced_settings_music_screen_0_about",
|
||||
summaryKey = null,
|
||||
tag = "app.revanced.extension.shared.settings.preference.ReVancedAboutPreference",
|
||||
selectable = true,
|
||||
)
|
||||
|
||||
// Modify GoogleApiActivity and remove all existing layout code.
|
||||
// Must modify an existing activity and cannot add a new activity to the manifest,
|
||||
// as that fails for root installations.
|
||||
|
||||
googleApiActivityFingerprint.method.addInstructions(
|
||||
1,
|
||||
"""
|
||||
invoke-static { }, $GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/music/settings/GoogleApiActivityHook;
|
||||
move-result-object v0
|
||||
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
|
||||
// Remove other methods as they will break as the onCreate method is modified above.
|
||||
googleApiActivityFingerprint.classDef.apply {
|
||||
methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
|
||||
}
|
||||
}
|
||||
|
||||
finalize {
|
||||
PreferenceScreen.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an intent to open ReVanced settings.
|
||||
*/
|
||||
fun newIntent(settingsName: String) = IntentPreference.Intent(
|
||||
data = settingsName,
|
||||
targetClass = "com.google.android.gms.common.api.GoogleApiActivity"
|
||||
) {
|
||||
// The package name change has to be reflected in the intent.
|
||||
setOrGetFallbackPackageName("com.google.android.apps.youtube.music")
|
||||
}
|
||||
|
||||
object PreferenceScreen : BasePreferenceScreen() {
|
||||
val ADS = Screen(
|
||||
"revanced_settings_music_screen_1_ads",
|
||||
summaryKey = null
|
||||
)
|
||||
val GENERAL = Screen(
|
||||
"revanced_settings_music_screen_2_general",
|
||||
summaryKey = null
|
||||
)
|
||||
val PLAYER = Screen(
|
||||
"revanced_settings_music_screen_3_player",
|
||||
summaryKey = null
|
||||
)
|
||||
val MISC = Screen(
|
||||
"revanced_settings_music_screen_4_misc",
|
||||
summaryKey = null
|
||||
)
|
||||
|
||||
override fun commit(screen: PreferenceScreenPreference) {
|
||||
preferences += screen
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package app.revanced.patches.music.misc.spoof
|
||||
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.playservice.is_7_33_or_greater
|
||||
import app.revanced.patches.music.playservice.is_8_11_or_greater
|
||||
import app.revanced.patches.music.playservice.is_8_15_or_greater
|
||||
import app.revanced.patches.music.playservice.versionCheckPatch
|
||||
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
|
||||
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
block = {
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
)
|
||||
)
|
||||
|
||||
dependsOn(sharedExtensionPatch, versionCheckPatch, userAgentClientSpoofPatch)
|
||||
},
|
||||
fixMediaFetchHotConfigChanges = { true },
|
||||
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater }
|
||||
)
|
||||
@@ -0,0 +1,59 @@
|
||||
package app.revanced.patches.music.misc.spoof
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.music.playservice.is_7_33_or_greater
|
||||
import app.revanced.patches.music.playservice.is_8_11_or_greater
|
||||
import app.revanced.patches.music.playservice.is_8_15_or_greater
|
||||
import app.revanced.patches.music.playservice.versionCheckPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
|
||||
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
fixMediaFetchHotConfigChanges = { true },
|
||||
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
|
||||
block = {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
versionCheckPatch,
|
||||
userAgentClientSpoofPatch
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
"7.29.52"
|
||||
)
|
||||
)
|
||||
},
|
||||
executeBlock = {
|
||||
addResources("music", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
|
||||
PreferenceScreen.MISC.addPreferences(
|
||||
PreferenceScreenPreference(
|
||||
key = "revanced_spoof_video_streams_screen",
|
||||
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_spoof_video_streams"),
|
||||
ListPreference("revanced_spoof_video_streams_client_type"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
musicActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -150,7 +150,6 @@ internal val nerdsStatsVideoFormatBuilderFingerprint = fingerprint {
|
||||
}
|
||||
|
||||
internal val patchIncludedExtensionMethodFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
|
||||
returns("Z")
|
||||
parameters()
|
||||
custom { method, classDef ->
|
||||
|
||||
@@ -9,8 +9,8 @@ import app.revanced.patcher.patch.BytecodePatchBuilder
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.findFreeRegister
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.getReference
|
||||
@@ -46,6 +46,8 @@ fun spoofVideoStreamsPatch(
|
||||
dependsOn(addResourcesPatch)
|
||||
|
||||
execute {
|
||||
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
|
||||
// region Enable extension helper method used by other patches
|
||||
|
||||
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
|
||||
|
||||
@@ -187,11 +187,16 @@ val customThemePatch = resourcePatch(
|
||||
}
|
||||
|
||||
// Login screen gradient.
|
||||
document("res/drawable/start_screen_gradient.xml").use { document ->
|
||||
val gradientNode = document.getElementsByTagName("gradient").item(0) as Element
|
||||
try {
|
||||
document("res/drawable/start_screen_gradient.xml").use { document ->
|
||||
val gradientNode = document.getElementsByTagName("gradient").item(0) as Element
|
||||
|
||||
gradientNode.setAttribute("android:startColor", "@color/gray_7")
|
||||
gradientNode.setAttribute("android:endColor", "@color/gray_7")
|
||||
gradientNode.setAttribute("android:startColor", "@color/gray_7")
|
||||
gradientNode.setAttribute("android:endColor", "@color/gray_7")
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
// Fails for 9.0.66+
|
||||
// printWarn("Failed to locate start_screen_gradient.xml, skipping modification.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import app.revanced.util.returnEarly
|
||||
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/fix/SpoofClientPatch;"
|
||||
|
||||
@Deprecated("Patch no longer functions")
|
||||
@Suppress("unused")
|
||||
val spoofClientPatch = bytecodePatch(
|
||||
name = "Spoof client",
|
||||
description = "Spoofs the client to fix various functions of the app.",
|
||||
) {
|
||||
val requestListenerPort by intOption(
|
||||
|
||||
@@ -2,12 +2,6 @@ package app.revanced.patches.viber.ads
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
internal val adsFreeFingerprint = fingerprint {
|
||||
returns("I")
|
||||
parameters()
|
||||
custom { method, classDef ->
|
||||
classDef.type.contains("com/viber/voip/feature/viberplus") &&
|
||||
classDef.superclass?.contains("com/viber/voip/core/feature") == true && // Must extend com.viber.voip.core.feature.?
|
||||
classDef.methods.count() == 1
|
||||
}
|
||||
internal val findAdStringFingerprint = fingerprint {
|
||||
strings("viber_plus_debug_ads_free_flag")
|
||||
}
|
||||
|
||||
@@ -1,17 +1,41 @@
|
||||
package app.revanced.patches.viber.ads
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.returnEarly
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||
|
||||
@Suppress("unused")
|
||||
val hideAdsPatch = bytecodePatch(
|
||||
name = "Hide Ads",
|
||||
description = "Hides ad banners between chats.",
|
||||
) {
|
||||
compatibleWith("com.viber.voip")
|
||||
compatibleWith("com.viber.voip"("25.9.2.0", "26.1.2.0"))
|
||||
|
||||
execute {
|
||||
// Return 1 (true) indicating ads should be disabled.
|
||||
adsFreeFingerprint.method.returnEarly(1)
|
||||
val method = findAdStringFingerprint.method
|
||||
|
||||
// Find the ads free string index
|
||||
val stringIndex = findAdStringFingerprint.stringMatches!!.first().index
|
||||
|
||||
// Search backwards from the string to find the `new-instance` (TypeReference) instruction
|
||||
val typeRefIndex = method.indexOfFirstInstructionReversedOrThrow(stringIndex) { this.opcode == Opcode.NEW_INSTANCE }
|
||||
|
||||
// Get the class name from the TypeReference
|
||||
val targetClass = method.getInstruction<ReferenceInstruction>(typeRefIndex).reference as TypeReference
|
||||
|
||||
// Patch the ads-free method to always return true
|
||||
fingerprint {
|
||||
returns("I")
|
||||
parameters()
|
||||
custom { method, classDef ->
|
||||
classDef == targetClass
|
||||
}
|
||||
}.method.returnEarly(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ val downloadsPatch = bytecodePatch(
|
||||
|
||||
// Main activity is used to launch downloader intent.
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
1,
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V"
|
||||
)
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ val hideButtonsPatch = resourcePatch(
|
||||
SwitchPreference("revanced_hide_report_button"),
|
||||
SwitchPreference("revanced_hide_save_button"),
|
||||
SwitchPreference("revanced_hide_share_button"),
|
||||
SwitchPreference("revanced_hide_shop_button"),
|
||||
SwitchPreference("revanced_hide_stop_ads_button"),
|
||||
SwitchPreference("revanced_hide_thanks_button"),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.youtube.layout.seekbar
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
import app.revanced.util.containsLiteralInstruction
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
@@ -103,7 +104,7 @@ internal val launchScreenLayoutTypeFingerprint = fingerprint {
|
||||
custom { method, _ ->
|
||||
val firstParameter = method.parameterTypes.firstOrNull()
|
||||
// 19.25 - 19.45
|
||||
(firstParameter == "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;"
|
||||
(firstParameter == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
|| firstParameter == "Landroid/app/Activity;") // 19.46+
|
||||
&& method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ val shortsAutoplayPatch = bytecodePatch(
|
||||
|
||||
// Main activity is used to check if app is in pip mode.
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
1,
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->setMainActivity(Landroid/app/Activity;)V",
|
||||
)
|
||||
|
||||
|
||||
@@ -90,8 +90,8 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
|
||||
|
||||
// Activity is used as the context to launch an Intent.
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
1,
|
||||
"invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->" +
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"setMainActivity(Landroid/app/Activity;)V",
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.youtube.layout.theme
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
import app.revanced.util.literal
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@@ -37,6 +38,6 @@ internal val splashScreenStyleFingerprint = fingerprint {
|
||||
parameters("Landroid/os/Bundle;")
|
||||
literal { SPLASH_SCREEN_STYLE_FEATURE_FLAG }
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && classDef.endsWith("/MainActivity;")
|
||||
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,7 @@ val announcementsPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
// Insert index must be greater than the insert index used by GmsCoreSupport,
|
||||
// as both patch the same method and GmsCore check should be first.
|
||||
1,
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->showAnnouncement(Landroid/app/Activity;)V",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/EnableDebuggingPatch;"
|
||||
|
||||
// TODO: Refactor this into a shared patch that can be used by both YT and YT Music.
|
||||
// Almost all of the feature flag hooks are the same between both apps.
|
||||
val enableDebuggingPatch = bytecodePatch(
|
||||
name = "Enable debugging",
|
||||
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
|
||||
@@ -45,6 +47,7 @@ val enableDebuggingPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("shared", "misc.debugging.enableDebuggingPatch")
|
||||
addResources("youtube", "misc.debugging.enableDebuggingPatch")
|
||||
|
||||
PreferenceScreen.MISC.addPreferences(
|
||||
@@ -58,13 +61,13 @@ val enableDebuggingPatch = bytecodePatch(
|
||||
SwitchPreference("revanced_debug_toast_on_error"),
|
||||
NonInteractivePreference(
|
||||
"revanced_debug_export_logs_to_clipboard",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.ExportLogToClipboardPreference",
|
||||
selectable = true,
|
||||
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
|
||||
selectable = true
|
||||
),
|
||||
NonInteractivePreference(
|
||||
"revanced_debug_logs_clear_buffer",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.ClearLogBufferPreference",
|
||||
selectable = true,
|
||||
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
|
||||
selectable = true
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -34,12 +34,7 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
|
||||
addResources("youtube", "misc.dns.checkWatchHistoryDomainNameResolutionPatch")
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
// FIXME: Insert index must be greater than the insert index used by GmsCoreSupport,
|
||||
// as both patch the same method and GmsCoreSupport check should be first,
|
||||
// but the patch does not depend on GmsCoreSupport, so it should not be possible to enforce this
|
||||
// unless a third patch is added that this patch and GmsCoreSupport depend on to manage
|
||||
// the order of the patches.
|
||||
1,
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ package app.revanced.patches.youtube.misc.extension
|
||||
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.extension.hooks.*
|
||||
|
||||
val sharedExtensionPatch = sharedExtensionPatch("youtube", applicationInitHook)
|
||||
val sharedExtensionPatch = sharedExtensionPatch("youtube",
|
||||
applicationInitHook, applicationInitOnCrateHook)
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
package app.revanced.patches.youtube.misc.extension.hooks
|
||||
|
||||
import app.revanced.patches.shared.misc.extension.extensionHook
|
||||
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
|
||||
/**
|
||||
* Hooks the context when the app is launched as a regular application (and is not an embedded video playback).
|
||||
*/
|
||||
// Extension context is the Activity itself.
|
||||
internal val applicationInitHook = extensionHook {
|
||||
// Does _not_ resolve to the YouTube main activity.
|
||||
// Required as some hooked code runs before the main activity is launched.
|
||||
strings("Application creation", "Application.onCreate")
|
||||
}
|
||||
|
||||
internal val applicationInitOnCrateHook = extensionHook {
|
||||
returns("V")
|
||||
parameters("Landroid/os/Bundle;")
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ private fun gmsCoreSupportResourcePatch(
|
||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
||||
executeBlock = {
|
||||
addResources("youtube", "misc.gms.gmsCoreSupportResourcePatch")
|
||||
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
|
||||
|
||||
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
|
||||
@@ -62,10 +62,14 @@ private fun gmsCoreSupportResourcePatch(
|
||||
"microg_settings",
|
||||
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
|
||||
"$gmsCoreVendorGroupId.android.gms"
|
||||
},
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
},
|
||||
}
|
||||
) {
|
||||
dependsOn(settingsPatch, addResourcesPatch, accountCredentialsInvalidTextPatch)
|
||||
dependsOn(
|
||||
addResourcesPatch,
|
||||
settingsPatch,
|
||||
accountCredentialsInvalidTextPatch
|
||||
)
|
||||
}
|
||||
|
||||
@@ -127,8 +127,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
// Litho filtering based on navigation tab before the tab is updated.
|
||||
mainActivityOnBackPressedFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { p0 }, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V",
|
||||
"invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V",
|
||||
)
|
||||
|
||||
// Hook the search bar.
|
||||
|
||||
@@ -29,7 +29,9 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
|
||||
private const val LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/settings/LicenseActivityHook;"
|
||||
|
||||
internal var appearanceStringId = -1L
|
||||
@@ -37,10 +39,6 @@ internal var appearanceStringId = -1L
|
||||
|
||||
private val preferences = mutableSetOf<BasePreference>()
|
||||
|
||||
fun addSettingPreference(screen: BasePreference) {
|
||||
preferences += screen
|
||||
}
|
||||
|
||||
private val settingsResourcePatch = resourcePatch {
|
||||
dependsOn(
|
||||
resourceMappingPatch,
|
||||
@@ -225,7 +223,9 @@ val settingsPatch = bytecodePatch(
|
||||
licenseActivityOnCreateFingerprint.method.addInstructions(
|
||||
1,
|
||||
"""
|
||||
invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V
|
||||
invoke-static {}, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/youtube/settings/LicenseActivityHook;
|
||||
move-result-object v0
|
||||
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
@@ -249,7 +249,7 @@ val settingsPatch = bytecodePatch(
|
||||
).toMutable().apply {
|
||||
addInstructions(
|
||||
"""
|
||||
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
|
||||
invoke-static { p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
|
||||
move-result-object p1
|
||||
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
|
||||
return-void
|
||||
@@ -294,7 +294,7 @@ val settingsPatch = bytecodePatch(
|
||||
addInstructions(
|
||||
"""
|
||||
invoke-super { p0, p1 }, Landroid/app/Activity;->onConfigurationChanged(Landroid/content/res/Configuration;)V
|
||||
invoke-static { p0, p1 }, $EXTENSION_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V
|
||||
invoke-static { p0, p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
@@ -309,15 +309,15 @@ val settingsPatch = bytecodePatch(
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
addInstructionsAtControlFlowLabel(
|
||||
index,
|
||||
"invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
|
||||
"invoke-static { v$register }, ${LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Add setting to force cairo settings fragment on/off.
|
||||
// Add setting to force Cairo settings fragment on/off.
|
||||
cairoFragmentConfigFingerprint.method.insertLiteralOverride(
|
||||
CAIRO_CONFIG_LITERAL_VALUE,
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
|
||||
"$LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.revanced.patches.youtube.misc.spoof
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
@@ -13,56 +14,69 @@ import app.revanced.patches.youtube.misc.playservice.is_20_14_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
"19.43.41",
|
||||
"19.47.53",
|
||||
"20.07.39",
|
||||
"20.12.46",
|
||||
"20.13.41",
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;"
|
||||
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
block = {
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
"19.43.41",
|
||||
"19.47.53",
|
||||
"20.07.39",
|
||||
"20.12.46",
|
||||
"20.13.41",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
dependsOn(
|
||||
userAgentClientSpoofPatch,
|
||||
settingsPatch,
|
||||
versionCheckPatch
|
||||
)
|
||||
}, {
|
||||
is_19_34_or_greater
|
||||
}, {
|
||||
// In 20.14 the flag was merged with 20.03 start playback flag.
|
||||
is_20_10_or_greater && !is_20_14_or_greater
|
||||
}, {
|
||||
is_20_03_or_greater
|
||||
}, {
|
||||
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
dependsOn(
|
||||
userAgentClientSpoofPatch,
|
||||
settingsPatch,
|
||||
versionCheckPatch
|
||||
)
|
||||
},
|
||||
fixMediaFetchHotConfigChanges = {
|
||||
is_19_34_or_greater
|
||||
},
|
||||
fixMediaFetchHotConfigAlternativeChanges = {
|
||||
// In 20.14 the flag was merged with 20.03 start playback flag.
|
||||
is_20_10_or_greater && !is_20_14_or_greater
|
||||
},
|
||||
fixParsePlaybackResponseFeatureFlag = {
|
||||
is_20_03_or_greater
|
||||
},
|
||||
executeBlock = {
|
||||
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
|
||||
PreferenceScreen.MISC.addPreferences(
|
||||
PreferenceScreenPreference(
|
||||
key = "revanced_spoof_video_streams_screen",
|
||||
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_spoof_video_streams"),
|
||||
ListPreference("revanced_spoof_video_streams_client_type"),
|
||||
NonInteractivePreference(
|
||||
// Requires a key and title but the actual text is chosen at runtime.
|
||||
key = "revanced_spoof_video_streams_about_android",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
|
||||
),
|
||||
ListPreference(
|
||||
key = "revanced_spoof_video_streams_language",
|
||||
// Language strings are declared in Setting patch.
|
||||
entriesKey = "revanced_language_entries",
|
||||
entryValuesKey = "revanced_language_entry_values",
|
||||
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference"
|
||||
),
|
||||
SwitchPreference("revanced_spoof_video_streams_ios_force_avc"),
|
||||
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"),
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
PreferenceScreen.MISC.addPreferences(
|
||||
PreferenceScreenPreference(
|
||||
key = "revanced_spoof_video_streams_screen",
|
||||
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_spoof_video_streams"),
|
||||
ListPreference("revanced_spoof_video_streams_client_type"),
|
||||
NonInteractivePreference(
|
||||
// Requires a key and title but the actual text is chosen at runtime.
|
||||
key = "revanced_spoof_video_streams_about_android",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
|
||||
),
|
||||
ListPreference(
|
||||
key = "revanced_spoof_video_streams_language",
|
||||
// Language strings are declared in Setting patch.
|
||||
entriesKey = "revanced_language_entries",
|
||||
entryValuesKey = "revanced_language_entry_values",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.SpoofAudioSelectorListPreference"
|
||||
),
|
||||
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,8 @@ import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal const val YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE = "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;"
|
||||
|
||||
internal val conversionContextFingerprintToString = fingerprint {
|
||||
parameters()
|
||||
strings(
|
||||
@@ -48,7 +50,7 @@ internal val mainActivityConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
parameters()
|
||||
custom { _, classDef ->
|
||||
classDef.endsWith("/MainActivity;")
|
||||
classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +59,7 @@ internal val mainActivityOnBackPressedFingerprint = fingerprint {
|
||||
returns("V")
|
||||
parameters()
|
||||
custom { method, classDef ->
|
||||
method.name == "onBackPressed" && classDef.endsWith("/MainActivity;")
|
||||
method.name == "onBackPressed" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +67,7 @@ internal val mainActivityOnCreateFingerprint = fingerprint {
|
||||
returns("V")
|
||||
parameters("Landroid/os/Bundle;")
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && classDef.endsWith("/MainActivity;")
|
||||
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.revanced.patches.youtube.video.audio
|
||||
|
||||
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
|
||||
@@ -14,6 +15,7 @@ import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
import app.revanced.util.findMethodFromToString
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.insertLiteralOverride
|
||||
@@ -61,6 +63,11 @@ val forceOriginalAudioPatch = bytecodePatch(
|
||||
)
|
||||
)
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setPreferredLanguage()V"
|
||||
)
|
||||
|
||||
// Disable feature flag that ignores the default track flag
|
||||
// and instead overrides to the user region language.
|
||||
if (is_20_07_or_greater) {
|
||||
|
||||
@@ -30,6 +30,10 @@ Second \"item\" text"</string>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -96,6 +100,7 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||
This button only shows if the user ip is from specific region such as the USA or EU. -->
|
||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
</patch>
|
||||
<patch id="layout.buttons.navigation.navigationButtonsPatch">
|
||||
@@ -207,8 +212,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
</patch>
|
||||
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
|
||||
@@ -240,6 +243,21 @@ Second \"item\" text"</string>
|
||||
<patch id="interaction.seekbar.enableSlideToSeekPatch">
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -30,6 +30,10 @@ Second \"item\" text"</string>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -96,6 +100,7 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||
This button only shows if the user ip is from specific region such as the USA or EU. -->
|
||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
</patch>
|
||||
<patch id="layout.buttons.navigation.navigationButtonsPatch">
|
||||
@@ -207,8 +212,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
</patch>
|
||||
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
|
||||
@@ -240,6 +243,21 @@ Second \"item\" text"</string>
|
||||
<patch id="interaction.seekbar.enableSlideToSeekPatch">
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
and changes made here must also be made there. -->
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">ØĨؚداداØĒ GmsCore</string>
|
||||
<string name="microg_settings_summary">ØĨؚداداØĒ ŲŲ GmsCore</string>
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
<string name="gms_core_toast_not_installed_message">ŲŲ
ŲØĒŲ
ØĒØĢØ¨ŲØĒ MicroG GmsCore. ŲŲ
بØĒØĢØ¨ŲØĒŲ.</string>
|
||||
<string name="gms_core_dialog_title">Ø§ŲØĨØŦØąØ§ØĄ Ų
ØˇŲŲØ¨</string>
|
||||
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
|
||||
اŲŲØą ŲŲŲ Ø˛Øą Ø§ŲØ§ØŗØĒŲ
ØąØ§Øą ŲØ§ØŗŲ
Ø Ø¨ØĒØēŲبਧØĒ Ø§ŲØĒØØŗŲŲ."</string>
|
||||
<string name="gms_core_dialog_continue_text">Ų
ØĒابؚ؊</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">Spoof Video Streams</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ØĒØ˛ŲŲŲ ØĒدŲŲØ§ØĒ اŲŲŲØ¯ŲŲ Ø§ŲØŽØ§ØĩØŠ Ø¨Ø§ŲØšŲ
ŲŲ ŲŲ
ŲØš ØØ¯ŲØĢ Ų
Ø´ŲŲØ§ØĒ ØŖØĢŲØ§ØĄ Ø§ŲØĒØ´ØēŲŲ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_title">Ø§ŲØĒØØ§Ų Ø¨ØĢŲØĢ Ø§ŲŲŲØ¯ŲŲ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">Ø§ŲØĒØØ§Ų Ø¨ØĢŲØĢ Ø§ŲŲŲØ¯ŲŲ Ø§ŲØŽØ§ØĩØŠ Ø¨Ø§ŲØšŲ
ŲŲ ŲŲ
ŲØš Ų
Ø´ŲŲØ§ØĒ Ø§ŲØĒØ´ØēŲŲ</string>
|
||||
<string name="revanced_spoof_video_streams_title">Spoof Video Streams</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">"ØĒدŲŲØ§ØĒ اŲŲŲØ¯ŲŲ Ų
Ø˛ŲØąØŠ
|
||||
|
||||
ØĨذا ŲŲØĒ Ų
ØŗØĒ؎دŲ
ŲØ§ ŲŲ YouTube PremiumØ ŲŲØ¯ ŲØ§ ŲŲŲŲ ŲØ°Ø§ Ø§ŲØĨؚداد Ų
ØˇŲŲØ¨Ųا"</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"ŲŲ
ŲØĒŲ
Ø§ŲØĒØØ§Ų Ø¨ØĢŲØĢ Ø§ŲŲŲØ¯ŲŲ
|
||||
|
||||
ŲØ¯ ŲØ§ ŲØšŲ
Ų Ø§ŲØĒØ´ØēŲŲ"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">ŲØ¯ ŲØ¤Ø¯Ų ØĨŲŲØ§Ų ØĒØ´ØēŲŲ ŲØ°Ø§ Ø§ŲØĨؚداد ØĨŲŲ Ų
Ø´ŲŲØ§ØĒ ŲŲ Ø§ŲØĒØ´ØēŲŲ.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Ø§ŲØšŲ
ŲŲ Ø§ŲØ§ŲØĒØąØ§ØļŲ</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_screen_summary">ØĒŲ
ŲŲŲ ØŖŲ ØĒØšØˇŲŲ ØŽŲØ§ØąØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_title">ØĒØŗØŦŲŲ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_summary_on">ØĒŲ
ØĒŲ
ŲŲŲ ØĒØŗØŦŲŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_summary_off">ØĒŲ
ØĒØšØˇŲŲ ØĒØŗØŦŲŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">ØĒØĩØ¯ŲØą ØŗØŦŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ŲØŗØŽ ØŗØŦŲØ§ØĒ ØĒØĩØŲØ ØŖØŽØˇØ§ØĄ ReVanced ØĨŲŲ Ø§ŲØØ§ŲØ¸ØŠ</string>
|
||||
<string name="revanced_debug_logs_disabled">ØĒŲ
ØĒØšØˇŲŲ ØĒØŗØŦŲŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_logs_none_found">ŲŲ
ŲØĒŲ
Ø§ŲØšØĢŲØą ØšŲŲ ØŗØŦŲØ§ØĒ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">ØĒŲ
ŲØŗØŽ Ø§ŲØŗØŦŲØ§ØĒ</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">ŲØ´Ų ØĒØĩØ¯ŲØą Ø§ŲØŗØŦŲØ§ØĒ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">Ų
ØŗØ ØŗØŦŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">ŲŲ
ØŗØ ØŦŲ
ŲØš ØŗØŦŲØ§ØĒ ØĒØĩØŲØ ØŖØŽØˇØ§ØĄ ReVanced اŲŲ
ØŽØ˛ŲØŠ</string>
|
||||
<string name="revanced_debug_logs_clear_toast">ØĒŲ
Ų
ØŗØ Ø§ŲØŗØŦŲØ§ØĒ</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_shorts_disable_background_playback_summary_off">ØĒŲ
ØĒŲ
ŲŲŲ ØĒØ´ØēŲŲ Shorts Ø¨Ø§ŲØŽŲŲŲØŠ</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_screen_summary">ØĒŲ
ŲŲŲ ØŖŲ ØĒØšØˇŲŲ ØŽŲØ§ØąØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_title">ØĒØŗØŦŲŲ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_summary_on">ØĒŲ
ØĒŲ
ŲŲŲ ØĒØŗØŦŲŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_summary_off">ØĒŲ
ØĒØšØˇŲŲ ØĒØŗØŦŲŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_protobuffer_title">ØŗØŦŲ Ø¨ØąŲØĒŲŲŲŲ Ø§ŲØĒØŽØ˛ŲŲ Ø§ŲŲ
Ø¤ŲØĒ</string>
|
||||
<string name="revanced_debug_protobuffer_summary_on">ØĒØĒØļŲ
Ų ØŗØŦŲØ§ØĒ Ø§ŲØĒØĩØŲØ Ø§ŲØĒØŽØ˛ŲŲ Ø§ŲŲ
Ø¤ŲØĒ</string>
|
||||
<string name="revanced_debug_protobuffer_summary_off">ŲØ§ ØĒØĒØļŲ
Ų ØŗØŦŲØ§ØĒ Ø§ŲØĒØĩØŲØ Ø§ŲØĒØŽØ˛ŲŲ Ø§ŲŲ
Ø¤ŲØĒ</string>
|
||||
@@ -132,15 +160,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"ŲØ¤Ø¯Ų ØĨŲŲØ§Ų ØĒØ´ØēŲŲ Ų
ŲØ§ØØ¸Ø§ØĒ Ø§ŲØŖØŽØˇØ§ØĄ ØĨŲŲ ØĨØŽŲØ§ØĄ ŲØ§ŲØŠ ØĨØ´ØšØ§ØąØ§ØĒ ØŖØŽØˇØ§ØĄ ReVanced.
|
||||
|
||||
ŲŲ ŲØĒŲ
ØĨØšŲØ§Ų
Ų Ø¨ØŖŲ ØŖØŽØˇØ§ØĄ ØēŲØą Ų
ØĒŲŲØšØŠ."</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">ØĒØĩØ¯ŲØą ØŗØŦŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ŲØŗØŽ ØŗØŦŲØ§ØĒ ØĒØĩØŲØ ØŖØŽØˇØ§ØĄ ReVanced ØĨŲŲ Ø§ŲØØ§ŲØ¸ØŠ</string>
|
||||
<string name="revanced_debug_logs_disabled">ØĒŲ
ØĒØšØˇŲŲ ØĒØŗØŦŲŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_logs_none_found">ŲŲ
ŲØĒŲ
Ø§ŲØšØĢŲØą ØšŲŲ ØŗØŦŲØ§ØĒ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">ØĒŲ
ŲØŗØŽ Ø§ŲØŗØŦŲØ§ØĒ</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">ŲØ´Ų ØĒØĩØ¯ŲØą Ø§ŲØŗØŦŲØ§ØĒ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">Ų
ØŗØ ØŗØŦŲØ§ØĒ ØĒØĩØŲØ Ø§ŲØŖØŽØˇØ§ØĄ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">ŲŲ
ØŗØ ØŦŲ
ŲØš ØŗØŦŲØ§ØĒ ØĒØĩØŲØ ØŖØŽØˇØ§ØĄ ReVanced اŲŲ
ØŽØ˛ŲØŠ</string>
|
||||
<string name="revanced_debug_logs_clear_toast">ØĒŲ
Ų
ØŗØ Ø§ŲØŗØŦŲØ§ØĒ</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||
<string name="revanced_hide_album_cards_title">ØĨØŽŲØ§ØĄ Ø¨ØˇØ§ŲØ§ØĒ Ø§ŲØŖŲبŲŲ
</string>
|
||||
@@ -602,6 +621,10 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_clip_button_title">ØĨØŽŲØ§ØĄ اŲŲ
ŲØˇØš</string>
|
||||
<string name="revanced_hide_clip_button_summary_on">ØĒŲ
ØĨØŽŲØ§ØĄ Ø˛Øą ØĨŲØ´Ø§ØĄ Ų
ŲØˇØš</string>
|
||||
<string name="revanced_hide_clip_button_summary_off">ŲØĒŲ
ØšØąØļ Ø˛Øą ØĨŲØ´Ø§ØĄ Ų
ŲØˇØš</string>
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_shop_button_title">ØĨØŽŲØ§ØĄ اŲŲ
ØĒØŦØą</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">Ø˛Øą اŲŲ
ØĒØŦØą Ų
ØŽŲŲ</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">Ø˛Øą اŲŲ
ØĒØŦØą Ų
ØšØąŲØļ</string>
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_save_button_title">ØĨØŽŲØ§ØĄ ØŲظ</string>
|
||||
<string name="revanced_hide_save_button_summary_on">Ø˛Øą Ø§ŲØŲØ¸ Ų
ØŽŲŲ</string>
|
||||
@@ -700,9 +723,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">ØĒŲ
ØĨØŽŲØ§ØĄ ŲØ§ØĻŲ
ØŠ اŲŲ
ŲØˇØš Ø§ŲØĩŲØĒŲ</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_off">ŲØĒŲ
ØšØąØļ ŲØ§ØĻŲ
ØŠ اŲŲ
ŲØˇØš Ø§ŲØĩŲØĒŲ</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"ØĒŲ
ØĨØŽŲØ§ØĄ ŲØ§ØĻŲ
ØŠ اŲŲ
ŲØˇØš Ø§ŲØĩŲØĒŲ
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"ŲØ§ØĻŲ
ØŠ اŲŲ
ØŗØ§ØąØ§ØĒ Ø§ŲØĩŲØĒŲØŠ Ų
ØŽŲŲØŠ
|
||||
|
||||
ŲØšØąØļ ŲØ§ØĻŲ
ØŠ اŲŲ
ŲØˇØš Ø§ŲØĩŲØĒŲØ ØēŲŲØą 'Spoof Video Streams' ØĨŲŲ iOS TV"</string>
|
||||
ŲØšØąØļ ŲØ§ØĻŲ
ØŠ اŲŲ
ØŗØ§ØąØ§ØĒ Ø§ŲØĩŲØĒŲØŠØ ØēŲŲØą 'ØĒØ˛ŲŲŲ ØĒدŲŲØ§ØĒ اŲŲŲØ¯ŲŲ' ØĨŲŲ iPadOS"</string>
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_title">ØĨØŽŲØ§ØĄ اŲŲ
Ø´Ø§ŲØ¯ØŠ ŲŲ VR</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">ØĒŲ
ØĨØŽŲØ§ØĄ ŲØ§ØĻŲ
ØŠ اŲŲ
Ø´Ø§ŲØ¯ØŠ ŲŲ Ø§ŲŲØļØš Ø§ŲØ§ŲØĒØąØ§ØļŲ</string>
|
||||
@@ -1415,10 +1438,6 @@ Second \"item\" text"</string>
|
||||
ŲŲ
ŲŲ ØŖŲ ŲØ¤Ø¯Ų ØĒŲØšŲŲ ŲØ°Ø§ ØĨŲŲ ŲØĒØ ØŦŲØ¯ØŠ ØŖØšŲŲ ŲŲŲŲØ¯ŲŲ"</string>
|
||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">ŲØ¯ ŲØ¤Ø¯Ų ØĒŲ
ŲŲŲ ŲØ°Ø§ ØĨŲŲ ØĒØ¨Ø§ØˇØ¤ ØĒØ´ØēŲŲ Ø§ŲŲŲØ¯ŲŲ ŲØĒØ¯ŲŲØą ØšŲ
Øą Ø§ŲØ¨ØˇØ§ØąŲØŠ ŲØĸØĢØ§Øą ØŦØ§ŲØ¨ŲØŠ ØēŲØą Ų
ØšØąŲŲØŠ.</string>
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">ØĨؚداداØĒ GmsCore</string>
|
||||
<string name="microg_settings_summary">ØĨؚداداØĒ ŲŲ GmsCore</string>
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
<string name="revanced_disable_haptic_feedback_title">Ø§ŲØ§ŲØĒØ˛Ø§Ø˛ ØšŲØ¯ Ø§ŲØļØēØˇ</string>
|
||||
<string name="revanced_disable_haptic_feedback_summary">ØĒØēŲŲØą Ø§ŲØ§ŲØĒØ˛Ø§Ø˛ ØšŲØ¯ Ø§ŲØļØēØˇ</string>
|
||||
@@ -1458,7 +1477,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Ø§ØŗØĒ؎داŲ
ŲØēØŠ Ø§ŲØĩŲØĒ Ø§ŲØŖØĩŲŲØŠ</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Ø§ØŗØĒ؎داŲ
Ø§ŲØĩŲØĒ Ø§ŲØ§ŲØĒØąØ§ØļŲ</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">ŲØ§ØŗØĒ؎داŲ
ŲØ°Ų اŲŲ
ŲØ˛ØŠØ ØēŲŲØą \'Spoof Video Streams\' ØĨŲŲ iOS TV</string>
|
||||
<string name="revanced_force_original_audio_not_available">ŲØ§ØŗØĒ؎داŲ
ŲØ°Ų اŲŲ
ŲØ˛ØŠØ ØēŲŲØą \"ØĒØ˛ŲŲØą ØĒØ¯ŲŲØ§ØĒ اŲŲŲØ¯ŲŲ\" ØĨŲŲ ØŖŲ ØšŲ
ŲŲ Ø¨Ø§ØŗØĒØĢŲØ§ØĄ Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
@@ -1532,35 +1551,54 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">ØĒŲ
ØĒØšØˇŲŲ Ø§ŲØĒŲ
ØąŲØą ŲŲØĒŲØ¯ŲŲ
ØŖŲ Ø§ŲØĒØąØŦŲØš</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">Spoof Video Streams</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ØĒØ˛ŲŲŲ ØĒدŲŲØ§ØĒ اŲŲŲØ¯ŲŲ Ø§ŲØŽØ§ØĩØŠ Ø¨Ø§ŲØšŲ
ŲŲ ŲŲ
ŲØš ØØ¯ŲØĢ Ų
Ø´ŲŲØ§ØĒ ØŖØĢŲØ§ØĄ Ø§ŲØĒØ´ØēŲŲ</string>
|
||||
<string name="revanced_spoof_video_streams_title">Spoof Video Streams</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">ŲØĒŲ
ØĒØ˛ŲŲŲ ØĒدŲŲØ§ØĒ اŲŲŲØ¯ŲŲ</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"ŲØ§ ŲØĒŲ
ØĒØ˛ŲŲŲ ØĒدŲŲØ§ØĒ اŲŲŲØ¯ŲŲ
|
||||
|
||||
ŲØ¯ ŲØ§ ŲØšŲ
Ų ØĒØ´ØēŲŲ Ø§ŲŲŲØ¯ŲŲ"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">ØĨŲŲØ§Ų ØĒØ´ØēŲŲ ŲØ°Ø§ Ø§ŲØĨؚداد ŲØ¯ ŲØŗØ¨Ø¨ Ų
شاŲŲ ŲŲ ØĒØ´ØēŲŲ Ø§ŲŲŲØ¯ŲŲ.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Ø§ŲØšŲ
ŲŲ Ø§ŲØ§ŲØĒØąØ§ØļŲ</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_title">ŲØąØļ iOS AVC (H.264)</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">ŲØĒŲ
ŲØąØļ ØĒØąŲ
ŲØ˛ ŲŲØ¯ŲŲ ØšŲŲ AVC (H.264)</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">ŲØĒŲ
ØĒØØ¯Ųد ØĒØąŲ
ŲØ˛ اŲŲŲØ¯ŲŲ ØĒŲŲØ§ØĻŲŲØ§</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"ŲØ¯ ŲØ¤Ø¯Ų ØĒŲ
ŲŲŲ ŲØ°Ø§ ØĨŲŲ ØĒØØŗŲŲ ØšŲ
Øą Ø§ŲØ¨ØˇØ§ØąŲØŠ ŲØĨØĩŲØ§Ø ØĒŲØˇŲØš Ø§ŲØĒØ´ØēŲŲ.
|
||||
|
||||
AVC ŲØ¯ŲŲ ØØ¯ ØŖŲØĩŲ ŲŲØ¯ŲØŠ 1080pØ ŲØ§ ŲØĒŲŲØą ØĒØąŲ
ŲØ˛ Ø§ŲØĩŲØĒ OpusØ ŲØŗŲŲ ŲØŗØĒ؎دŲ
ØĒØ´ØēŲŲ Ø§ŲŲŲØ¯ŲŲ Ø¨ŲØ§ŲاØĒ ØĨŲØĒØąŲØĒ ØŖŲØĢØą Ų
Ų VP9 ØŖŲ AV1."</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_title">Ø§ŲØĸØĢØ§Øą Ø§ŲØŦØ§ŲØ¨ŲØŠ ŲŲ
ØØ§Ųا؊ ŲŲŲØŠ iOS</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"âĸ ŲØ¯ ŲØ§ ŲØĒŲ
ØĒØ´ØēŲŲ Ø§ŲØŖŲŲØ§Ų
ØŖŲ Ø§ŲŲŲØ¯ŲŲŲØ§ØĒ اŲŲ
دŲŲØšØŠ
|
||||
âĸ Ų
ØŗØĒŲŲ Ø§ŲØĩŲØĒ Ø§ŲØĢØ§Ø¨ØĒ ØēŲØą Ų
ØĒŲŲØą
|
||||
âĸ ØĒŲØĒŲŲ Ø§ŲŲŲØ¯ŲŲŲØ§ØĒ ŲØ¨Ų ب 1 ØĢاŲŲØŠ"</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Ø§ŲØĸØĢØ§Øą Ø§ŲØŦØ§ŲØ¨ŲØŠ ŲŲØĒØ˛ŲŲØą</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_title">Ø§ŲØĸØĢØ§Øą Ø§ŲØŦØ§ŲØ¨ŲØŠ ŲŲ
ØØ§Ųا؊ ŲŲŲØŠ Android</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ ŲØ§ØĻŲ
ØŠ اŲŲ
ŲØˇØš Ø§ŲØĩŲØĒŲ Ų
ŲŲŲØ¯ØŠ
|
||||
âĸ Ų
ØŗØĒŲŲ Ø§ŲØĩŲØĒ Ø§ŲØĢØ§Ø¨ØĒ ØēŲØą Ų
ØĒاØ
|
||||
âĸ ŲØąØļ Ø§ŲØĩŲØĒ Ø§ŲØŖØĩŲŲ ØēŲØą Ų
ØĒŲŲØą"</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ ŲØ§ØĻŲ
ØŠ اŲŲ
ØŗØ§ØąØ§ØĒ Ø§ŲØĩŲØĒŲØŠ Ų
ŲŲŲØ¯ØŠ
|
||||
âĸ Ų
ØŗØĒŲŲ Ø§ŲØĩŲØĒ Ø§ŲŲ
ØŗØĒŲØą ØēŲØą Ų
ØĒاØ"</string>
|
||||
<string name="revanced_spoof_video_streams_about_ipados_summary">âĸ ŲØ¯ ŲØĒŲŲŲ Ø§ŲŲŲØ¯ŲŲ ØšŲØ¯ 1:00Ø ØŖŲ ŲØ¯ ŲØ§ ŲŲŲŲ Ų
ØĒاØŲا ŲŲ Ø¨ØšØļ اŲŲ
ŲØ§ØˇŲ</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">âĸ ØšŲ
ŲŲ ØĒØŦØąŲØ¨Ų ŲŲØ¯ ŲØĒŲŲŲ ØšŲ Ø§ŲØšŲ
Ų ŲŲ ØŖŲ ŲŲØĒ</string>
|
||||
<string name="revanced_spoof_video_streams_about_no_av1">âĸ ŲØ§ ŲŲØŦد ØĒØąŲ
ŲØ˛ اŲŲŲØ¯ŲŲ AV1</string>
|
||||
<string name="revanced_spoof_video_streams_about_kids_videos">âĸ ŲØ¯ ŲØ§ ŲØĒŲ
ØĒØ´ØēŲŲ Ø§ŲŲŲØ¯ŲŲŲØ§ØĒ اŲŲ
ØŽØĩØĩØŠ ŲŲØŖØˇŲØ§Ų ØšŲØ¯ ØĒØŗØŦŲŲ Ø§ŲØŽØąŲØŦ ØŖŲ ØšŲØ¯ Ø§ØŗØĒ؎داŲ
ŲØļØš Ø§ŲØĒØĩŲØ اŲŲ
ØĒØŽŲŲ</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">ØšØąØļ ŲŲ ØĨØØĩØ§ØĄØ§ØĒ ØĒŲŲŲØŠ</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">ŲØĒŲ
ØšØąØļ Ųب𠨧بšŲ
ŲŲ ŲŲ ØĨØØĩØ§ØĄØ§ØĒ ØĒŲŲŲØŠ</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">ØĒŲ
ØĨØŽŲØ§ØĄ Ųب𠨧بšŲ
ŲŲ ŲŲ ØĨØØĩØ§ØĄØ§ØĒ ØĒŲŲŲØŠ</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">ŲØēØŠ Ø§ŲØ¨ØĢ Ø§ŲØĩŲØĒŲ Ø§ŲØ§ŲØĒØąØ§ØļŲØŠ ŲŲŲØ§ŲØš Ø§ŲØ§ŲØĒØąØ§ØļŲ VR</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">ŲØēØŠ بØĢ Ø§ŲØĩŲØĒ</string>
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
<string name="revanced_spoof_video_streams_language_not_available">ŲØĒØØ¯ŲØ¯ ŲØēØŠ ØĩŲØĒŲØŠ Ų
ØšŲŲØŠØ ŲŲ
بØĨŲŲØ§Ų ØĒØ´ØēŲŲ \"ŲØąØļ ŲØēØŠ Ø§ŲØĩŲØĒ Ø§ŲØŖØĩŲŲØŠ\"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">ØŲŲ</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">ØĨØšŲØ§ŲاØĒ</string>
|
||||
<string name="revanced_settings_music_screen_2_general_title">ؚاŲ
</string>
|
||||
<string name="revanced_settings_music_screen_3_player_title">اŲŲ
Ø´ØēŲ</string>
|
||||
<string name="revanced_settings_music_screen_4_misc_title">Ų
ØĒŲŲØšØŠ</string>
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
<string name="revanced_music_hide_video_ads_title">ØĨØŽŲØ§ØĄ ØĨØšŲØ§ŲاØĒ اŲŲŲØ¯ŲŲ</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_on">ØĒŲ
ØĨØŽŲØ§ØĄ ØĨØšŲØ§ŲاØĒ اŲŲŲØ¯ŲŲ</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_off">ØĒŲ
ØšØąØļ ØĨØšŲØ§ŲاØĒ اŲŲŲØ¯ŲŲ</string>
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
<string name="revanced_music_play_permanent_repeat_title">ØĒŲ
ŲŲŲ Ø§ŲØĒŲØąØ§Øą Ø§ŲØ¯Ø§ØĻŲ
</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_on">ØĒŲ
ØĒŲ
ŲŲŲ Ø§ŲØĒŲØąØ§Øą Ø§ŲØ¯Ø§ØĻŲ
</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_off">ØĒŲ
ØĒØšØˇŲŲ Ø§ŲØĒŲØąØ§Øą Ø§ŲØ¯Ø§ØĻŲ
</string>
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
<string name="revanced_music_hide_category_bar_title">ØĨØŽŲØ§ØĄ Ø´ØąŲØˇ اŲŲØĻØ§ØĒ</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_on">Ø´ØąŲØˇ اŲŲØĻØ§ØĒ Ų
ØŽŲŲ</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_off">Ø´ØąŲØˇ اŲŲØĻØ§ØĒ Ų
ØšØąŲØļ</string>
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
<string name="revanced_music_hide_get_premium_label_title">ØĨØŽŲØ§ØĄ ØĒØŗŲ
ŲØŠ \'Ø§ŲØØĩŲŲ ØšŲŲ Music Premium\'</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_on">Ø§ŲØĒØŗŲ
ŲØŠ Ų
ØŽŲŲØŠ</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_off">Ø§ŲØĒØŗŲ
ŲØŠ Ų
ØšØąŲØļØŠ</string>
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
<string name="revanced_music_hide_upgrade_button_title">ØĨØŽŲØ§ØĄ Ø˛Øą Ø§ŲØĒØąŲŲØŠ</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_on">Ø§ŲØ˛Øą Ų
ØŽŲŲ</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_off">Ø§ŲØ˛Øą Ų
ØšØąŲØļ</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -30,6 +30,10 @@ Second \"item\" text"</string>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -96,6 +100,7 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||
This button only shows if the user ip is from specific region such as the USA or EU. -->
|
||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
</patch>
|
||||
<patch id="layout.buttons.navigation.navigationButtonsPatch">
|
||||
@@ -209,8 +214,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
</patch>
|
||||
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
|
||||
@@ -242,6 +245,21 @@ Second \"item\" text"</string>
|
||||
<patch id="interaction.seekbar.enableSlideToSeekPatch">
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -68,6 +68,8 @@ Yeni dillÉri tÉrcÃŧmÉ etmÉk ÃŧçÃŧn translate.revanced.app 'É daxil olun"</
|
||||
and changes made here must also be made there. -->
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore TÉnzimlÉmÉlÉri</string>
|
||||
<string name="microg_settings_summary">GmsCore ÃŧçÃŧn TÉnzimlÉmÉlÉr</string>
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
<string name="gms_core_toast_not_installed_message">MicroG GmsCore quraÅdÄąrÄąlmayÄąb. Bunu quraÅdÄąr.</string>
|
||||
<string name="gms_core_dialog_title">FÉaliyyÉt lazÄąmdÄąr</string>
|
||||
@@ -84,6 +86,37 @@ MicroG ÃŧçÃŧn batareya optimallaÅmasÄąn qapatma batareya istifadÉsinÉ mÉnfi
|
||||
Davam et dÃŧymÉsinÉ toxun vÉ optimallaÅdÄąrma dÉyiÅikliklÉrin qÉbul et."</string>
|
||||
<string name="gms_core_dialog_continue_text">Davam et</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">Video yayÄąmlarÄą saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">Oynatma problemlÉrin ÃļnlÉmÉk ÃŧçÃŧn qÉbuledici video yayÄąmlarÄąn saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_screen_title">Video yayÄąmlarÄąn saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">Oynatma problemlÉrin ÃļnlÉmÉk ÃŧçÃŧn qÉbuledici video yayÄąmlarÄąn saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_title">Video yayÄąmlarÄą saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">"Video yayÄąmlarÄą saxtalaÅdÄąrÄąlÄąb
|
||||
|
||||
ÆgÉr YouTube Premium istifadÉçisisinizsÉ, bu tÉnzimlÉnmÉ tÉlÉb olunmaya bilÉr"</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"Video yayÄąmlarÄą saxtalaÅmayÄąb
|
||||
|
||||
Oynatma iÅlÉmÉyÉ bilÉr"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Bu tÉnzimlÉmÉni qapatmaq oynatma problemlÉrinÉ sÉbÉb ola bilÉr.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">İlkin qÉbuledici</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Sazlama</string>
|
||||
<string name="revanced_debug_screen_summary">Sazlama seçimlÉrini aktiv/qeyri-aktiv et</string>
|
||||
<string name="revanced_debug_title">Sazlama jurnalÄą</string>
|
||||
<string name="revanced_debug_summary_on">Sazlama jurnalÄą iÅlÉkdir</string>
|
||||
<string name="revanced_debug_summary_off">Sazlama jurnalÄą qeyri-aktivdir</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">Sazlama qeydlÉrini ixrac edin</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ReVanced sazlama qeydlÉrini buferÉ kÃļçÃŧrÃŧr</string>
|
||||
<string name="revanced_debug_logs_disabled">Sazlama qeydi qapalÄądÄąr</string>
|
||||
<string name="revanced_debug_logs_none_found">QeydlÉr tapÄąlmadÄą</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">QeydlÉr kÃļçÃŧrÃŧldÃŧ</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">QeydlÉri ixrac etmÉk alÄąnmadÄą: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">Sazlama qeydlÉrini tÉmizlÉ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">SaxlanÄąlan bÃŧtÃŧn ReVanced sazlama qeydlÉrini tÉmizlÉyir</string>
|
||||
<string name="revanced_debug_logs_clear_toast">QeydlÉr silindi</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -110,11 +143,6 @@ Davam et dÃŧymÉsinÉ toxun vÉ optimallaÅdÄąrma dÉyiÅikliklÉrin qÉbul et."
|
||||
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts arxa plan oynatma aktivdir</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Sazlama</string>
|
||||
<string name="revanced_debug_screen_summary">Sazlama seçimlÉrini aktiv/qeyri-aktiv et</string>
|
||||
<string name="revanced_debug_title">Sazlama jurnalÄą</string>
|
||||
<string name="revanced_debug_summary_on">Sazlama jurnalÄą iÅlÉkdir</string>
|
||||
<string name="revanced_debug_summary_off">Sazlama jurnalÄą qeyri-aktivdir</string>
|
||||
<string name="revanced_debug_protobuffer_title">Bufer protokol jurnalÄą</string>
|
||||
<string name="revanced_debug_protobuffer_summary_on">Sazlama jurnallarÄąna protokol buferi daxildir</string>
|
||||
<string name="revanced_debug_protobuffer_summary_off">Sazlama jurnallarÄąna protokol buferi daxil deyil</string>
|
||||
@@ -132,15 +160,6 @@ HÉr halda, bunu aktivlÉÅdirmÉ IP ÃŧnvanÄąnÄąz kimi bÉzi istifadÉçi mÉlum
|
||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"XÉta ani bildiriÅlÉrin qapatmaq, bÃŧtÃŧn ReVanced xÉta bildiriÅlÉrin gizlÉdir.
|
||||
|
||||
GÃļzlÉnilmÉz hallardan xÉbÉrdar olmayacaqsÄąnÄąz."</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">Sazlama qeydlÉrini ixrac edin</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ReVanced sazlama qeydlÉrini buferÉ kÃļçÃŧrÃŧr</string>
|
||||
<string name="revanced_debug_logs_disabled">Sazlama qeydi qapalÄądÄąr</string>
|
||||
<string name="revanced_debug_logs_none_found">QeydlÉr tapÄąlmadÄą</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">QeydlÉr kÃļçÃŧrÃŧldÃŧ</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">QeydlÉri ixrac etmÉk alÄąnmadÄą: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">Sazlama qeydlÉrini tÉmizlÉ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">SaxlanÄąlan bÃŧtÃŧn ReVanced sazlama qeydlÉrini tÉmizlÉyir</string>
|
||||
<string name="revanced_debug_logs_clear_toast">QeydlÉr silindi</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||
<string name="revanced_hide_album_cards_title">Albom kartlarÄąnÄą gizlÉt</string>
|
||||
@@ -602,6 +621,10 @@ EkranÄąn saÄ tÉrÉfindÉ dÃŧzÃŧnÉ sÃŧrÃŧÅdÃŧrÉrÉk sÉs sÉviyyÉsini tÉnz
|
||||
<string name="revanced_hide_clip_button_title">KÉsmÉ/ gizlÉt</string>
|
||||
<string name="revanced_hide_clip_button_summary_on">KÉsmÉ dÃŧymÉsi gizlidir</string>
|
||||
<string name="revanced_hide_clip_button_summary_off">KÉsmÉ dÃŧymÉsi gÃļstÉrilir</string>
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_shop_button_title">MaÄazanÄą GizlÉt</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">MaÄaza dÃŧymÉsi gizlidir</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">MaÄaza dÃŧymÉsi gÃļrÃŧnÃŧr</string>
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_save_button_title">SaxlayÄąn-Äą GizlÉt</string>
|
||||
<string name="revanced_hide_save_button_summary_on">SaxlayÄąn dÃŧymÉsi gizlidir</string>
|
||||
@@ -700,9 +723,9 @@ Bu seçimi dÉyiÅdirmÉ iÅÉ dÃŧÅmÃŧrsÉ, Gizli rejimÉ keçmÉyÉ Ã§alÄąÅÄą
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">SÉs axÄąnÄą menyusu gizlidir</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_off">SÉs axÄąnÄą menyusu gÃļstÉrilir</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"Audio trek seçimi gizlÉdilib
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"SÉs trek menyusu gizlidir
|
||||
|
||||
Audio trek seçimin gÃļstÉrmÉk ÃŧçÃŧn \"Video axÄąnlarÄą saxtalaÅdÄąr\"Äą iOS TV-yÉ dÉyiÅ"</string>
|
||||
SÉs treki menyusunu gÃļstÉrmÉk ÃŧçÃŧn \"Video yayÄąmlarÄą saxtalaÅdÄąr\"Äą iPadOS-a dÉyiÅ"</string>
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_title">\"VR-da İzlÉni\" gizlÉt</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">VR menyusunda izlÉmÉ gizlidir</string>
|
||||
@@ -1414,10 +1437,6 @@ YÃŧksÉk video keyfiyyÉtlÉr gÃļrÃŧnÉ bilÉr, ancaq video oynadÄąlmasÄąnda qÄą
|
||||
Bunu aktivlÉÅdirmÉ daha yÃŧksÉk video keyfiyyÉtlÉri ÉngÉlin silÉ bilÉr"</string>
|
||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">Bunu aktivlÉÅdirmÉ, video oynatma donmalarÄąna, daha pis batareya istismarÄąna vÉ bilinmÉyÉn yan tÉsirlÉrÉ sÉbÉb ola bilÉr.</string>
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore TÉnzimlÉmÉlÉri</string>
|
||||
<string name="microg_settings_summary">GmsCore ÃŧçÃŧn TÉnzimlÉmÉlÉr</string>
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
<string name="revanced_disable_haptic_feedback_title">Æks-ÉlaqÉ reaksiyasÄą</string>
|
||||
<string name="revanced_disable_haptic_feedback_summary">Æks-ÉlaqÉ reaksiyasÄąnÄą dÉyiÅdir</string>
|
||||
@@ -1457,7 +1476,7 @@ Bunu aktivlÉÅdirmÉ daha yÃŧksÉk video keyfiyyÉtlÉri ÉngÉlin silÉ bilÉr
|
||||
<string name="revanced_force_original_audio_summary_on">Orijinal sÉs dilini istifadÉ</string>
|
||||
<string name="revanced_force_original_audio_summary_off">İlkin sÉs istifadÉsi</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Bu xÃŧsusiyyÉti istifadÉ etmÉk ÃŧçÃŧn \"Saxta video yayÄąmlarÄąn\" iOS TV-yÉ dÉyiÅ</string>
|
||||
<string name="revanced_force_original_audio_not_available">Bu funksiyanÄą istifadÉ etmÉk ÃŧçÃŧn \"Video yayÄąmlarÄą saxtalaÅdÄąrÄą\" Android Studio savayÄą istÉnilÉn qÉbulediciyÉ dÉyiÅ</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
@@ -1531,35 +1550,54 @@ Bunu aktivlÉÅdirmÉ daha yÃŧksÉk video keyfiyyÉtlÉri ÉngÉlin silÉ bilÉr
|
||||
<string name="revanced_slide_to_seek_summary_off">Axtarmaq ÃŧçÃŧn sÃŧrÃŧÅdÃŧrmÉ aktiv deyil</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">Video yayÄąmlarÄą saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">Oynatma problemlÉrin ÃļnlÉmÉk ÃŧçÃŧn qÉbuledici video yayÄąmlarÄąn saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_title">Video yayÄąmlarÄą saxtalaÅdÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">Video yayÄąmlarÄą saxtalaÅdÄąrÄąlÄąr</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"Video yayÄąmlar saxtalaÅdÄąrÄąlmÄąr
|
||||
|
||||
Video oynatma iÅlÉmÉyÉ bilÉr"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Bu seçimi baÄlamaq, video oynatma problemlÉrinÉ sÉbÉb olar.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">İlkin qÉbuledici</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_title">IOS-da AVC (H.264)-ni mÉcbur et</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">Video kodlama AVC (H.264)-yÉ mÉcbur edilir</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">Video kodlayÄącÄą avtomatik mÃŧÉyyÉn edilir</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"Bunu aktivlÉÅdirmÉ, batareya ÃļmrÃŧn yaxÅÄąlaÅdÄąra vÉ oynatma qÄąrÄąlmasÄąn dÃŧzÉldÉ bilÉr.
|
||||
|
||||
AVC maksimum 1080p gÃļrÃŧntÃŧ imkanÄąna malikdir, Opus audio kodlama olmur vÉ video oynatma VP9 vÉ ya AV1-dÉn daha çox internet mÉlumatÄą sÉrf edÉcÉk."</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_title">iOS saxtalaÅdÄąrma yan tÉsirlÉri</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"âĸ FilmlÉr vÉ ya ÃļdÉniÅli videolar oynadÄąla bilmÉz
|
||||
âĸ Stabil sÉs sÉviyyÉsi mÃļvcud deyil
|
||||
âĸ Videolar 1 saniyÉ tez bitir"</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">SaxtakarlÄąq yan tÉsirlÉri</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_title">Android saxtalaÅdÄąrma yan tÉsirlÉri</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ SÉs treki menyusu yoxdur
|
||||
âĸ Sabit sÉs sÉviyyÉsi yoxdur
|
||||
âĸ İlkin sÉsi mÉcbur etmÉ mÃŧmkÃŧn deyil"</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ SÉs treki menyusu ÉlçatmazdÄąr
|
||||
âĸ Sabit sÉs sÉviyyÉsi yoxdur"</string>
|
||||
<string name="revanced_spoof_video_streams_about_ipados_summary">âĸ Video 01:00-da dayana bilÉr vÉ ya bÉzi bÃļlgÉlÉrdÉ mÃļvcud olmaya bilÉr</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">âĸ TÉcrÃŧbi qÉbuledici vÉ hÉr vaxt iÅlÉmÉyi dayandÄąra bilÉr</string>
|
||||
<string name="revanced_spoof_video_streams_about_no_av1">âĸ AV1 video kodlayÄącÄą yoxdur</string>
|
||||
<string name="revanced_spoof_video_streams_about_kids_videos">âĸ GiriÅ edilmÉyÉndÉ vÉ ya gizli rejimdÉ uÅaq videolarÄą oynadÄąla bilmÉz</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">İstÉk ÃŧçÃŧn Statistikada gÃļstÉr</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">QÉbuledici nÃļvÃŧ İstÉk ÃŧçÃŧn statistikada gÃļstÉrilir</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">QÉbuledici nerd ÃŧçÃŧn Statistikada gizlidir</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">VR-da ilkin sÉs yayÄąmÄą dili</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">SÉs yayÄąm dili</string>
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
<string name="revanced_spoof_video_streams_language_not_available">XÃŧsusi sÉs dilini seçmÉk ÃŧçÃŧn \"Orijinal sÉs dilini zorlanÄą\" qapat</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">HaqqÄąnda</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Reklamlar</string>
|
||||
<string name="revanced_settings_music_screen_2_general_title">Ãmumi</string>
|
||||
<string name="revanced_settings_music_screen_3_player_title">OynadÄącÄą</string>
|
||||
<string name="revanced_settings_music_screen_4_misc_title">ÃoxvariantlÄą</string>
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
<string name="revanced_music_hide_video_ads_title">Video reklamlarÄąnÄą gizlÉt</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_on">Video reklamlarÄą gizlidir</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_off">Video reklamlarÄą gÃļrÃŧnÃŧr</string>
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
<string name="revanced_music_play_permanent_repeat_title">KÉsintisiz tÉkrarlamanÄą aktivlÉÅdir</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_on">KÉsintisiz tÉkrarlama aktivdir</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_off">KÉsintisiz tÉkrarlama qapalÄądÄąr</string>
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
<string name="revanced_music_hide_category_bar_title">Kateqoriya cizgisin gizlÉt</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_on">Kateqoriya cizgisi gizlidir</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_off">Kateqoriya cizgisi gÃļrÃŧnÃŧr</string>
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
<string name="revanced_music_hide_get_premium_label_title"> \'Musiqi Premiumu ÆldÉ et\' etiketini gizlÉt</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_on">Etiket gizlidir</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_off">Etiket gÃļrÃŧnÃŧr</string>
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
<string name="revanced_music_hide_upgrade_button_title">TÉkmillÉÅdirmÉ dÃŧymÉsini gizlÉt</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_on">DÃŧymÉ gizlidir</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_off">DÃŧymÉ gÃļrÃŧnÃŧr</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
and changes made here must also be made there. -->
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">ĐаĐģĐ°Đ´Ņ GmsCore</string>
|
||||
<string name="microg_settings_summary">ĐаĐģĐ°Đ´Ņ Đ´ĐģŅ GmsCore</string>
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
<string name="gms_core_toast_not_installed_message">MicroG GmsCore ĐŊĐĩ ŅŅŅаĐģŅваĐŊŅ. ĐŖŅŅаĐģŅĐšŅĐĩ ŅĐŗĐž.</string>
|
||||
<string name="gms_core_dialog_title">ĐаŅŅайŅĐĩŅŅа дСĐĩŅĐŊĐŊĐĩ</string>
|
||||
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
|
||||
ĐаŅŅŅĐŊŅŅĐĩ ĐēĐŊĐžĐŋĐēŅ \"ĐŅаŅŅĐŗĐŊŅŅŅ\" Ņ Đ´Đ°ĐˇĐ˛ĐžĐģŅŅĐĩ СĐŧŅĐŊŅŅŅ Đ°ĐŋŅŅĐŧŅСаŅŅŅ."</string>
|
||||
<string name="gms_core_dialog_continue_text">ĐŅаŅŅĐŗĐŊŅŅŅ</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">ĐОддĐĩĐģŅваŅŅ ĐŋĐžŅĐžĐēи видĐĩĐž</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ĐĐŧиŅиŅŅĐšŅĐĩ ĐŋĐžŅĐžĐēи видĐĩĐž ĐēĐģиĐĩĐŊŅОв, ŅŅĐžĐąŅ ĐŋŅĐĩĐ´ĐžŅвŅаŅиŅŅ ĐŋŅОйĐģĐĩĐŧŅ Ņ Đ˛ĐžŅĐŋŅОиСвĐĩĐ´ĐĩĐŊиĐĩĐŧ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_title">ĐадĐŧĐĩĐŊа вŅĐ´ŅаĐŋаŅĐžĐēаŅ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ĐадĐŧĐĩĐŊа вŅĐ´ŅаĐŋаŅĐžĐēĐ°Ņ ĐēĐģŅĐĩĐŊŅа Đ´ĐģŅ ĐŋŅадŅŅ
ŅĐģĐĩĐŊĐŊŅ ĐŋŅайĐģĐĩĐŧ С ĐŋŅĐ°ĐšĐŗŅаваĐŊĐŊĐĩĐŧ</string>
|
||||
<string name="revanced_spoof_video_streams_title">ĐОддĐĩĐģŅваŅŅ ĐŋĐžŅĐžĐēи видĐĩĐž</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">"ĐŅĐ´ŅаŅŅŅŅĐŧĐĩĐŊŅ ĐŋадŅОйĐģĐĩĐŊŅ
|
||||
|
||||
ĐаĐģŅ Đ˛Ņ ĐēаŅŅŅŅаĐĩŅĐĩŅŅ YouTube Premium, ĐŗŅŅĐ°Ņ ĐŊаĐģада ĐŧĐžĐļа ĐŊĐĩ ŅĐŋаŅŅŅĐąŅŅŅа"</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"ĐŅĐ´ŅаĐŋаŅĐžĐēŅ ĐŊĐĩ ĐŋадĐŧĐĩĐŊĐĩĐŊŅ
|
||||
|
||||
ĐŅĐ°ĐšĐŗŅаваĐŊĐŊĐĩ ĐŧĐžĐļа ĐŊĐĩ ĐŋŅаŅаваŅŅ"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">ĐĐ´ĐēĐģŅŅŅĐŊĐŊĐĩ ĐŗŅŅаК ĐŊаĐģĐ°Đ´Ņ ĐŧĐžĐļа вŅĐēĐģŅĐēаŅŅ ĐŋŅайĐģĐĩĐŧŅ Đˇ ĐŋŅĐ°ĐšĐŗŅаваĐŊĐŊĐĩĐŧ.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">ĐĐģиĐĩĐŊŅ ĐŋĐž ŅĐŧĐžĐģŅаĐŊиŅ</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ĐĐ´ĐģадĐēа</string>
|
||||
<string name="revanced_debug_screen_summary">ĐŖĐēĐģŅŅŅŅŅ Đ°ĐąĐž вŅĐēĐģŅŅŅŅŅ ĐŋаŅаĐŧĐĩŅŅŅ Đ°Đ´ĐģадĐēŅ</string>
|
||||
<string name="revanced_debug_title">ĐаĐŋŅŅ Đ°Đ´ĐģадĐēŅ</string>
|
||||
<string name="revanced_debug_summary_on">ĐŅŅĐŊаĐģŅ Đ°Đ´ĐģадĐēŅ ŅĐēĐģŅŅаĐŊŅ</string>
|
||||
<string name="revanced_debug_summary_off">ĐŅŅĐŊаĐģŅ Đ°Đ´ĐģадĐēŅ Đ°Đ´ĐēĐģŅŅаĐŊŅ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">ĐĐēŅĐŋаŅŅаваŅŅ Đ°Đ´ĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ĐаĐŋŅŅŅĐĩ адĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ ReVanced Ņ ĐąŅŅĐĩŅ Đ°ĐąĐŧĐĩĐŊŅ</string>
|
||||
<string name="revanced_debug_logs_disabled">ĐĐ´ĐģадаŅĐŊаĐĩ ĐģĐ°ĐŗĐ°Đ˛Đ°ĐŊĐŊĐĩ адĐēĐģŅŅаĐŊа</string>
|
||||
<string name="revanced_debug_logs_none_found">ĐĐ°ĐŗŅ ĐŊĐĩ СĐŊОКдСĐĩĐŊŅ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">ĐĐ°ĐŗŅ ŅĐēаĐŋŅŅваĐŊŅ</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">ĐĐĩ ŅдаĐģĐžŅŅ ŅĐēŅĐŋаŅŅаваŅŅ ĐļŅŅĐŊаĐģŅ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">ĐŅŅŅŅŅŅŅ Đ°Đ´ĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">ĐŅŅŅŅаĐĩ ŅŅĐĩ СаŅ
аваĐŊŅŅ Đ°Đ´ĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ ReVanced</string>
|
||||
<string name="revanced_debug_logs_clear_toast">ĐĐ°ĐŗŅ Đ°ŅŅŅŅаĐŊŅ</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊОвŅĐš ĐŋĐģĐĩĐšĐģиŅŅ Shorts вĐēĐģŅŅĐĩĐŊ</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ĐĐ´ĐģадĐēа</string>
|
||||
<string name="revanced_debug_screen_summary">ĐŖĐēĐģŅŅŅŅŅ Đ°ĐąĐž вŅĐēĐģŅŅŅŅŅ ĐŋаŅаĐŧĐĩŅŅŅ Đ°Đ´ĐģадĐēŅ</string>
|
||||
<string name="revanced_debug_title">ĐаĐŋŅŅ Đ°Đ´ĐģадĐēŅ</string>
|
||||
<string name="revanced_debug_summary_on">ĐŅŅĐŊаĐģŅ Đ°Đ´ĐģадĐēŅ ŅĐēĐģŅŅаĐŊŅ</string>
|
||||
<string name="revanced_debug_summary_off">ĐŅŅĐŊаĐģŅ Đ°Đ´ĐģадĐēŅ Đ°Đ´ĐēĐģŅŅаĐŊŅ</string>
|
||||
<string name="revanced_debug_protobuffer_title">ĐŅŅĐĩŅ ĐŋŅаŅаĐēĐžĐģŅ ŅаŅĐžĐŋŅŅа</string>
|
||||
<string name="revanced_debug_protobuffer_summary_on">ĐŅŅĐŊаĐģŅ Đ°Đ´ĐģадĐēŅ ŅĐēĐģŅŅаŅŅŅ ĐŋŅаŅайŅŅĐĩŅ</string>
|
||||
<string name="revanced_debug_protobuffer_summary_off">ĐŅŅĐŊаĐģŅ Đ°Đ´ĐģадĐēŅ ĐŊĐĩ ŅĐēĐģŅŅаŅŅŅ ĐŋŅаŅайŅŅĐĩŅ</string>
|
||||
@@ -132,15 +160,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"ĐĐ´ĐēĐģŅŅŅĐŊĐŊĐĩ ĐŋавĐĩдаĐŧĐģĐĩĐŊĐŊŅŅ ĐŋŅа ĐŋаĐŧŅĐģĐēŅ ŅŅ
аваĐĩ ŅŅĐĩ аĐŋавŅŅŅŅĐŊĐŊŅ ReVanced ĐŋŅа ĐŋаĐŧŅĐģĐēŅ.
|
||||
|
||||
ĐŅ ĐŊĐĩ ĐąŅдСĐĩŅĐĩ аŅŅŅĐŧĐģŅваŅŅ Đ°ĐŋавŅŅŅŅĐŊĐŊŅ ĐŋŅа ĐŊĐĩŅаĐēаĐŊŅŅ ĐŋадСĐĩŅ."</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">ĐĐēŅĐŋаŅŅаваŅŅ Đ°Đ´ĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ĐаĐŋŅŅŅĐĩ адĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ ReVanced Ņ ĐąŅŅĐĩŅ Đ°ĐąĐŧĐĩĐŊŅ</string>
|
||||
<string name="revanced_debug_logs_disabled">ĐĐ´ĐģадаŅĐŊаĐĩ ĐģĐ°ĐŗĐ°Đ˛Đ°ĐŊĐŊĐĩ адĐēĐģŅŅаĐŊа</string>
|
||||
<string name="revanced_debug_logs_none_found">ĐĐ°ĐŗŅ ĐŊĐĩ СĐŊОКдСĐĩĐŊŅ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">ĐĐ°ĐŗŅ ŅĐēаĐŋŅŅваĐŊŅ</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">ĐĐĩ ŅдаĐģĐžŅŅ ŅĐēŅĐŋаŅŅаваŅŅ ĐļŅŅĐŊаĐģŅ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">ĐŅŅŅŅŅŅŅ Đ°Đ´ĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">ĐŅŅŅŅаĐĩ ŅŅĐĩ СаŅ
аваĐŊŅŅ Đ°Đ´ĐģадаŅĐŊŅŅ ĐģĐ°ĐŗŅ ReVanced</string>
|
||||
<string name="revanced_debug_logs_clear_toast">ĐĐ°ĐŗŅ Đ°ŅŅŅŅаĐŊŅ</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||
<string name="revanced_hide_album_cards_title">ĐĄŅ
аваŅŅ ĐēаŅŅŅ Đ°ĐģŅйОĐŧа</string>
|
||||
@@ -602,6 +621,10 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_clip_button_title">ĐĄŅ
аваŅŅ ĐēĐģŅĐŋ</string>
|
||||
<string name="revanced_hide_clip_button_summary_on">ĐĐŊĐžĐŋĐēа ĐēĐģŅĐŋа ŅŅ
аваĐŊа</string>
|
||||
<string name="revanced_hide_clip_button_summary_off">ĐаĐēаСаĐŊа ĐēĐŊĐžĐŋĐēа ĐēĐģŅĐŋа</string>
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_shop_button_title">ĐĄŅ
аваŅŅ ĐŅаĐŧŅ</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">ĐĐŊĐžĐŋĐēа \"ĐŅаĐŧа\" ŅŅ
аваĐŊа</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">ĐĐŊĐžĐŋĐēа \"ĐŅаĐŧа\" ĐŋаĐēаСаĐŊа</string>
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_save_button_title">ĐĄŅ
аваŅŅ \"ĐаŅ
аваŅŅ\"</string>
|
||||
<string name="revanced_hide_save_button_summary_on">ĐĐŊĐžĐŋĐēа \"ĐаŅ
аваŅŅ\" ŅŅ
аваĐŊа</string>
|
||||
@@ -702,7 +725,7 @@ Second \"item\" text"</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"ĐĐĩĐŊŅ Đ°ŅĐ´ŅŅдаŅĐžĐļĐēŅ ŅŅ
аваĐŊа
|
||||
|
||||
Đай ĐŋаĐēаСаŅŅ ĐŧĐĩĐŊŅ Đ°ŅĐ´ŅŅдаŅĐžĐļĐēŅ, СĐŧŅĐŊŅŅĐĩ \"ĐадŅОйĐēа вŅĐ´ŅаŅŅŅŅĐŧĐĩĐŊŅŅ\" ĐŊа iOS TV"</string>
|
||||
Đай ĐŋаĐēаСаŅŅ ĐŧĐĩĐŊŅ Đ°ŅĐ´ŅŅдаŅĐžĐļĐēŅ, СĐŧŅĐŊŅŅĐĩ \"ĐадĐŧĐĩĐŊа вŅĐ´ŅаĐŋаŅĐžĐēаŅ\" ĐŊа iPadOS"</string>
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_title">ĐĄŅ
аваŅŅ ĐŗĐ°Đ´ĐˇŅĐŊĐŊŅĐē Ņ VR</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">ĐĐĩĐŊŅ ĐŋŅĐ°ĐŗĐģŅĐ´Ņ Ņ VR ŅŅ
аваĐŊа</string>
|
||||
@@ -1416,10 +1439,6 @@ Second \"item\" text"</string>
|
||||
ĐŖĐēĐģŅŅŅĐŊĐŊĐĩ ĐŗŅŅĐ°ĐŗĐ° ĐŧĐžĐļа ŅаСйĐģаĐēаваŅŅ ĐąĐžĐģŅŅ Đ˛ŅŅĐžĐēŅŅ ŅĐēаŅŅŅ Đ˛ŅĐ´Ņа"</string>
|
||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">ĐŖĐēĐģŅŅŅĐŊĐŊĐĩ ĐŗŅŅĐ°ĐŗĐ° ĐŧĐžĐļа ĐŋŅŅвĐĩŅŅŅ Đ´Đ° ĐŋŅŅĐŋŅĐŊĐēĐ°Ņ ĐŋŅĐ°ĐšĐŗŅаваĐŊĐŊŅ Đ˛ŅĐ´Ņа, ĐŋĐ°ĐŗĐ°ŅŅŅĐŊĐŊŅ ŅŅŅĐŧŅĐŊŅ ŅĐģŅĐļĐąŅ ĐąĐ°ŅаŅŅŅ Ņ ĐŊĐĩвŅĐ´ĐžĐŧŅŅ
ĐŋайОŅĐŊŅŅ
ŅŅĐĩĐēŅаŅ.</string>
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">ĐаĐģĐ°Đ´Ņ GmsCore</string>
|
||||
<string name="microg_settings_summary">ĐаĐģĐ°Đ´Ņ Đ´ĐģŅ GmsCore</string>
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
<string name="revanced_disable_haptic_feedback_title">ĐĸаĐēŅŅĐģŅĐŊĐ°Ņ ĐˇĐ˛Đ°ŅĐžŅĐŊĐ°Ņ ŅŅвŅСŅ</string>
|
||||
<string name="revanced_disable_haptic_feedback_summary">ĐĐŧŅĐŊŅŅŅ ŅаĐēŅŅĐģŅĐŊŅŅ ĐˇĐ˛Đ°ŅĐžŅĐŊŅŅ ŅŅвŅСŅ</string>
|
||||
@@ -1459,7 +1478,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_force_original_audio_summary_on">ĐŅĐēаŅŅŅŅĐžŅваŅŅ Đ°ŅŅĐŗŅĐŊаĐģŅĐŊŅŅ ĐŧĐžĐ˛Ņ Đ°ŅĐ´ŅŅ</string>
|
||||
<string name="revanced_force_original_audio_summary_off">ĐŅĐēаŅŅŅŅаĐŊĐŊĐĩ аŅĐ´ŅŅ Đŋа СĐŧаŅŅаĐŊĐŊŅ</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Đай вŅĐēаŅŅŅŅĐžŅваŅŅ ĐŗŅŅŅ ŅŅĐŊĐēŅŅŅ, СĐŧŅĐŊŅŅĐĩ ĐŋаŅаĐŧĐĩŅŅ \"ĐадŅайĐģŅŅŅ Đ˛ŅĐ´ŅаŅŅŅŅĐŧĐĩĐŊŅ\" ĐŊа iOS TV</string>
|
||||
<string name="revanced_force_original_audio_not_available">Đай вŅĐēаŅŅŅŅаŅŅ ĐŗŅŅŅŅ ŅŅĐŊĐēŅŅŅ, СĐŧŅĐŊŅŅĐĩ \'ĐадĐŧĐĩĐŊа вŅĐ´ŅаŅŅŅŅĐŧĐĩĐŊŅŅ\' ĐŊа ĐģŅĐąĐžĐŗĐ° ĐēĐģŅĐĩĐŊŅа, аĐēŅаĐŧŅ Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
@@ -1533,35 +1552,54 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Đ´ĐģŅ ĐŋĐžŅŅĐēŅ ĐŊĐĩ ŅĐēĐģŅŅаĐŊŅ</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">ĐОддĐĩĐģŅваŅŅ ĐŋĐžŅĐžĐēи видĐĩĐž</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ĐĐŧиŅиŅŅĐšŅĐĩ ĐŋĐžŅĐžĐēи видĐĩĐž ĐēĐģиĐĩĐŊŅОв, ŅŅĐžĐąŅ ĐŋŅĐĩĐ´ĐžŅвŅаŅиŅŅ ĐŋŅОйĐģĐĩĐŧŅ Ņ Đ˛ĐžŅĐŋŅОиСвĐĩĐ´ĐĩĐŊиĐĩĐŧ</string>
|
||||
<string name="revanced_spoof_video_streams_title">ĐОддĐĩĐģŅваŅŅ ĐŋĐžŅĐžĐēи видĐĩĐž</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">ĐĐžŅĐžĐēи видĐĩĐž ĐŋОддĐĩĐģаĐŊŅ</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"ĐŅĐ´ŅаŅŅŅŅĐŧ ĐŊĐĩ ĐŋадŅОйĐģĐĩĐŊŅ
|
||||
|
||||
ĐŅĐ°ĐšĐŗŅаваĐŊĐŊĐĩ вŅĐ´Ņа ĐŧĐžĐļа ĐŊĐĩ ĐŋŅаŅаваŅŅ"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">ĐĐ´ĐēĐģŅŅŅĐŊĐŊĐĩ ĐŗŅŅаК ĐŊаĐģĐ°Đ´Ņ ĐŧĐžĐļа вŅĐēĐģŅĐēаŅŅ ĐŋŅайĐģĐĩĐŧŅ Đˇ ĐŋŅĐ°ĐšĐŗŅаваĐŊĐŊĐĩĐŧ вŅĐ´Ņа.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">ĐĐģиĐĩĐŊŅ ĐŋĐž ŅĐŧĐžĐģŅаĐŊиŅ</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_title">ĐŅĐŧŅŅŅŅŅ iOS AVC (H.264)</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">ĐŅĐ´ŅаĐēaĐ´ŅĐē СаŅŅĐēŅаваĐŊŅ Ņ AVC (H.264)</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">ĐŅĐ´ŅаĐēaĐ´ŅĐē вŅСĐŊаŅаĐĩŅŅа аŅŅаĐŧаŅŅŅĐŊа</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"ĐŖĐēĐģŅŅŅĐŊĐŊĐĩ ĐŗŅŅĐ°ĐŗĐ° ĐŧĐžĐļа ĐŋаĐģĐĩĐŋŅŅŅŅ ŅĐ°Ņ Đ°ŅŅаĐŊĐžĐŧĐŊаК ĐŋŅаŅŅ Ņ Đ˛ŅĐŋŅавŅŅŅ ĐˇĐ°ŅĐēаĐŊĐŊĐĩ ĐŋŅĐ°ĐšĐŗŅаваĐŊĐŊŅ.
|
||||
|
||||
AVC ĐŧаĐĩ ĐŧаĐēŅŅĐŧаĐģŅĐŊаĐĩ даСвОĐģ 1080p, аŅĐ´ŅŅĐēадŅĐē Opus ĐŊĐĩдаŅŅŅĐŋĐŊŅ, а ĐŋŅĐ°ĐšĐŗŅаваĐŊĐŊĐĩ вŅĐ´Ņа ĐąŅдСĐĩ вŅĐēаŅŅŅŅĐžŅваŅŅ ĐąĐžĐģŅŅ ŅĐŊŅŅŅĐŊŅŅ-даĐŊŅŅ
, ŅŅĐŧ VP9 айО AV1."</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_title">ĐайОŅĐŊŅŅ ŅŅĐĩĐēŅŅ ĐŋадŅОйĐēŅ iOS</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"âĸ ФŅĐģŅĐŧŅ Đ°ĐąĐž ĐŋĐģаŅĐŊŅŅ Đ˛ŅĐ´Ņа ĐŧĐžĐŗŅŅŅ ĐŊĐĩ ĐŋŅĐ°ĐšĐŗŅаваŅŅа
|
||||
âĸ ĐĄŅайŅĐģŅĐŊĐ°Ņ ĐŗŅŅĐŊаŅŅŅ ĐŊĐĩдаŅŅŅĐŋĐŊаŅ
|
||||
âĸ ĐŅĐ´Ņа СаĐēаĐŊŅваŅŅŅа ĐŊа 1 ŅĐĩĐēŅĐŊĐ´Ņ ŅаĐŊĐĩĐš"</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">ĐайОŅĐŊŅŅ ŅŅĐĩĐēŅŅ ĐŋадŅОйĐēŅ</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_title">ĐОйŅŅĐŊŅŅ ŅŅĐĩĐēŅŅ ĐŋадŅОйĐēŅ Android</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ ĐĐĩĐŊŅ ĐŗŅĐēавОК даŅĐžĐļĐēŅ Đ°Đ´ŅŅŅĐŊŅŅаĐĩ
|
||||
âĸ ĐĄŅайŅĐģŅĐŊŅ ĐŗŅĐē ĐŊĐĩдаŅŅŅĐŋĐŊŅ
|
||||
âĸ ĐŅŅĐŧŅŅОваĐĩ аŅŅĐŗŅĐŊаĐģŅĐŊаĐĩ аŅĐ´ŅŅ ĐŊĐĩдаŅŅŅĐŋĐŊа"</string>
|
||||
âĸ ĐĄŅайŅĐģŅĐŊĐ°Ņ ĐŗŅŅĐŊаŅŅŅ ĐŊĐĩдаŅŅŅĐŋĐŊа"</string>
|
||||
<string name="revanced_spoof_video_streams_about_ipados_summary">âĸ ĐŅĐ´Ņа ĐŧĐžĐļа ŅĐŋŅĐŊŅŅŅа ĐŊа 1:00, ŅŅ ĐŧĐžĐļа ĐąŅŅŅ ĐŊĐĩдаŅŅŅĐŋĐŊŅĐŧ Ņ ĐŊĐĩĐēаŅĐžŅŅŅ
ŅŅĐŗŅŅĐŊаŅ
</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">âĸ ĐĐēŅĐŋĐĩŅŅĐŧĐĩĐŊŅаĐģŅĐŊŅ ĐēĐģŅĐĩĐŊŅ Ņ ĐŧĐžĐļа ŅĐŋŅĐŊŅŅŅ ĐŋŅаŅŅ Ņ ĐģŅĐąŅ ŅаŅ</string>
|
||||
<string name="revanced_spoof_video_streams_about_no_av1">âĸ ĐŅĐŧа вŅĐ´ŅаĐēŅдаваĐŊĐŊŅ AV1</string>
|
||||
<string name="revanced_spoof_video_streams_about_kids_videos">âĸ ĐСŅŅŅŅŅŅ Đ˛ŅĐ´Ņа ĐŧĐžĐŗŅŅŅ ĐŊĐĩ ĐŋŅĐ°ĐšĐŗŅаваŅŅа Ņ ŅŅаĐŊĐĩ вŅŅ
Đ°Đ´Ņ Đˇ аĐēаŅĐŊŅа айО Ņ ŅŅĐļŅĐŧĐĩ ŅĐŊĐēĐžĐŗĐŊŅŅа</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">ĐаĐēаСаŅŅ Ņ ŅŅаŅŅŅŅŅŅŅ Đ´ĐģŅ ŅĐŋĐĩŅŅŅĐģŅŅŅаŅ</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">ĐĸŅĐŋ ĐēĐģŅĐĩĐŊŅа адĐģŅŅŅŅĐžŅваĐĩŅŅа Ņ ŅŅаŅŅŅŅŅŅŅ Đ´ĐģŅ ŅĐŋĐĩŅŅŅĐģŅŅŅаŅ</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">ĐĐģŅĐĩĐŊŅ ŅŅ
аваĐŊŅ Ņ ŅŅаŅŅŅŅŅŅŅ Đ´ĐģŅ ŅĐŋĐĩŅŅŅĐģŅŅŅаŅ</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">ĐОва ĐŗŅĐēавОК даŅĐžĐļĐēŅ Đŋа СĐŧаŅŅаĐŊĐŊŅ Đ´ĐģŅ VR</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">ĐОва аŅĐ´ŅŅĐŋаŅĐžĐēŅ</string>
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
<string name="revanced_spoof_video_streams_language_not_available">Đай вŅĐąŅаŅŅ ĐŋŅŅĐŊŅŅ ĐŧĐžĐ˛Ņ Đ°ŅĐ´ŅŅ, адĐēĐģŅŅŅŅĐĩ \'ĐŅŅĐŧŅŅĐžĐ˛Đ°Ņ Đ°ŅŅĐŗŅĐŊаĐģŅĐŊĐ°Ņ ĐŧОва аŅĐ´ŅŅ\'</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">ĐŅа</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Đ ŅĐēĐģаĐŧа</string>
|
||||
<string name="revanced_settings_music_screen_2_general_title">ĐĐŗŅĐģŅĐŊŅŅ</string>
|
||||
<string name="revanced_settings_music_screen_3_player_title">ĐĐģŅĐĩŅ</string>
|
||||
<string name="revanced_settings_music_screen_4_misc_title">РОСĐŊаĐĩ</string>
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
<string name="revanced_music_hide_video_ads_title">ĐĄŅ
аваŅŅ Đ˛ŅĐ´ŅаŅŅĐēĐģаĐŧŅ</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_on">ĐŅĐ´ŅаŅŅĐēĐģаĐŧа ŅŅ
аваĐŊаŅ</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_off">ĐŅĐ´ŅаŅŅĐēĐģаĐŧа ĐŋаĐēаСаĐŊаŅ</string>
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
<string name="revanced_music_play_permanent_repeat_title">ĐŖĐēĐģŅŅŅŅŅ ĐŋаŅŅаŅĐŊĐŊŅ ĐŋаŅŅĐžŅ</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_on">ĐаŅŅаŅĐŊĐŊŅ ĐŋаŅŅĐžŅ ŅĐēĐģŅŅаĐŊŅ</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_off">ĐаŅŅаŅĐŊĐŊŅ ĐŋаŅŅĐžŅ Đ°Đ´ĐēĐģŅŅаĐŊŅ</string>
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
<string name="revanced_music_hide_category_bar_title">ĐĄŅ
аваŅŅ ĐŋаĐŊŅĐģŅ ĐēаŅŅĐŗĐžŅŅĐš</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_on">ĐаĐŊŅĐģŅ ĐēаŅŅĐŗĐžŅŅĐš ŅŅ
аваĐŊаŅ</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_off">ĐаĐŊŅĐģŅ ĐēаŅŅĐŗĐžŅŅĐš ĐŋаĐēаСаĐŊаŅ</string>
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
<string name="revanced_music_hide_get_premium_label_title">ĐĄŅ
аваŅŅ ĐŊадĐŋŅŅ \"ĐŅŅŅĐŧаŅŅ Music Premium\"</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_on">ĐадĐŋŅŅ ŅŅ
аваĐŊŅ</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_off">ĐадĐŋŅŅ ĐŋаĐēаСаĐŊŅ</string>
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
<string name="revanced_music_hide_upgrade_button_title">ĐĄŅ
аваŅŅ ĐēĐŊĐžĐŋĐēŅ Đ°ĐąĐŊаŅĐģĐĩĐŊĐŊŅ</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_on">ĐĐŊĐžĐŋĐēа ŅŅ
аваĐŊаŅ</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_off">ĐĐŊĐžĐŋĐēа ĐŋаĐēаСаĐŊаŅ</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
and changes made here must also be made there. -->
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore ĐаŅŅŅОКĐēи</string>
|
||||
<string name="microg_settings_summary">ĐаŅŅŅОКĐēи ĐŊа GmsCore</string>
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
<string name="gms_core_toast_not_installed_message">GmsCore ĐŊĐĩ Đĩ иĐŊŅŅаĐģиŅаĐŊ. ĐĐŊŅŅаĐģиŅаКŅĐĩ ĐŗĐž.</string>
|
||||
<string name="gms_core_dialog_title">ĐŅĐļĐŊĐž Đĩ Đ´ĐĩĐšŅŅвиĐĩ</string>
|
||||
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
|
||||
ĐĐžĐēĐžŅĐŊĐĩŅĐĩ ĐąŅŅĐžĐŊа Са ĐŋŅОдŅĐģĐļаваĐŊĐĩ и ŅаСŅĐĩŅĐĩŅĐĩ ĐŋŅĐžĐŧĐĩĐŊи в ĐžĐŋŅиĐŧиСаŅиŅŅа."</string>
|
||||
<string name="gms_core_dialog_continue_text">ĐŅОдŅĐģĐļи</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">ĐОдĐŋŅавŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ĐОдĐŋŅавĐĩŅĐĩ ĐēĐģиĐĩĐŊŅŅĐēиŅĐĩ видĐĩĐž ĐŋĐžŅĐžŅи, Са да ĐŋŅĐĩĐ´ĐžŅвŅаŅиŅĐĩ ĐŋŅОйĐģĐĩĐŧи Ņ Đ˛ŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž</string>
|
||||
<string name="revanced_spoof_video_streams_screen_title">ĐĐŧиŅиŅаĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ĐĐŧиŅиŅаКŅĐĩ видĐĩĐž ĐŋĐžŅĐžŅиŅĐĩ ĐŊа ĐēĐģиĐĩĐŊŅа, Са да ĐŋŅĐĩĐ´ĐžŅвŅаŅиŅĐĩ ĐŋŅОйĐģĐĩĐŧи Ņ Đ˛ŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž</string>
|
||||
<string name="revanced_spoof_video_streams_title">ĐОдĐŋŅавŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">"ĐидĐĩĐž ĐŋĐžŅĐžŅиŅĐĩ Ņа ĐŋОдĐŧĐĩĐŊĐĩĐŊи
|
||||
|
||||
ĐĐēĐž ŅŅĐĩ ĐŋĐžŅŅĐĩйиŅĐĩĐģ ĐŊа YouTube Premium, ŅаСи ĐŊаŅŅŅОКĐēа ĐŧĐžĐļĐĩ да ĐŊĐĩ Đĩ ĐŊĐĩОйŅ
ОдиĐŧа"</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"ĐидĐĩĐžĐŋĐžŅĐžŅиŅĐĩ ĐŊĐĩ Ņа ĐŋОдĐŋŅавĐĩĐŊи
|
||||
|
||||
ĐŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž ĐŧĐžĐļĐĩ да ĐŊĐĩ ŅайОŅи"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">ĐСĐēĐģŅŅваĐŊĐĩŅĐž ĐŊа ŅаСи ĐŊаŅŅŅОКĐēа ĐŧĐžĐļĐĩ да ĐŋŅиŅиĐŊи ĐŋŅОйĐģĐĩĐŧи Ņ Đ˛ŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">ĐĐģиĐĩĐŊŅ ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ĐŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_screen_summary">ĐĐēŅивиŅаĐŊĐĩ иĐģи Đ´ĐĩаĐēŅивиŅаĐŊĐĩ ĐŊа ĐžŅŅŅŅаĐŊŅваĐŊĐĩŅĐž ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_title">ĐĐŊĐĩвĐŊиĐē ĐŊа ĐžŅŅŅŅаĐŊŅваĐŊĐĩŅĐž ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_summary_on">ĐĐŊĐĩвĐŊиĐēŅŅ ĐˇĐ° ĐžŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи Đĩ аĐēŅивиŅаĐŊ</string>
|
||||
<string name="revanced_debug_summary_off">ĐĐŊĐĩвĐŊиĐēŅŅ ĐˇĐ° ĐžŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи Đĩ Đ´ĐĩаĐēŅивиŅаĐŊ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">ĐĐēŅĐŋĐžŅŅиŅаĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ĐĐžĐŋиŅа ĐģĐžĐŗĐžĐ˛ĐĩŅĐĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи ĐŊа ReVanced в ĐēĐģиĐŋйОŅда</string>
|
||||
<string name="revanced_debug_logs_disabled">ĐŅŅŅŅаĐŊŅваĐŊĐĩŅĐž ĐŊа ĐŗŅĐĩŅĐēи Đĩ Đ´ĐĩаĐēŅивиŅаĐŊĐž</string>
|
||||
<string name="revanced_debug_logs_none_found">ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">ĐĐžĐŗĐžĐ˛ĐĩŅĐĩ Ņа ĐēĐžĐŋиŅаĐŊи</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐĩĐēŅĐŋĐžŅŅиŅаĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">ĐСŅиŅŅваĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛ĐĩŅĐĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">ĐСŅиŅŅва вŅиŅĐēи ŅŅŅ
ŅаĐŊĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи ĐŊа ReVanced</string>
|
||||
<string name="revanced_debug_logs_clear_toast">ĐĐžĐŗĐžĐ˛ĐĩŅĐĩ Ņа иСŅиŅŅĐĩĐŊи</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊОвОŅĐž вŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩ ĐŊа Shorts Đĩ аĐēŅивиŅаĐŊĐž</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ĐŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_screen_summary">ĐĐēŅивиŅаĐŊĐĩ иĐģи Đ´ĐĩаĐēŅивиŅаĐŊĐĩ ĐŊа ĐžŅŅŅŅаĐŊŅваĐŊĐĩŅĐž ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_title">ĐĐŊĐĩвĐŊиĐē ĐŊа ĐžŅŅŅŅаĐŊŅваĐŊĐĩŅĐž ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_summary_on">ĐĐŊĐĩвĐŊиĐēŅŅ ĐˇĐ° ĐžŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи Đĩ аĐēŅивиŅаĐŊ</string>
|
||||
<string name="revanced_debug_summary_off">ĐĐŊĐĩвĐŊиĐēŅŅ ĐˇĐ° ĐžŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи Đĩ Đ´ĐĩаĐēŅивиŅаĐŊ</string>
|
||||
<string name="revanced_debug_protobuffer_title">ĐŅŅĐĩŅ ĐŊа ĐŋŅĐžŅĐžĐēĐžĐģа Са Đ´ĐŊĐĩвĐŊиĐēа</string>
|
||||
<string name="revanced_debug_protobuffer_summary_on">ФаКĐģОвĐĩ Ņ Đ´ĐŊĐĩвĐŊиŅи Са ĐŗŅĐĩŅĐēи вĐēĐģŅŅĐ˛Đ°Ņ ĐąŅŅĐĩŅа</string>
|
||||
<string name="revanced_debug_protobuffer_summary_off">ФаКĐģОвĐĩ Ņ Đ´ĐŊĐĩвĐŊиŅи Са ĐŗŅĐĩŅĐēи ĐŊĐĩ вĐēĐģŅŅĐ˛Đ°Ņ ĐąŅŅĐĩŅа</string>
|
||||
@@ -132,15 +160,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"ĐСĐēĐģŅŅваĐŊĐĩŅĐž ĐŊа иСŅĐēаŅаŅи ŅŅОйŅĐĩĐŊĐ¸Ņ ĐˇĐ° ĐŗŅĐĩŅĐēи ĐēŅиĐĩ вŅиŅĐēи иСвĐĩŅŅĐ¸Ņ ĐˇĐ° ĐŗŅĐĩŅĐēи ĐŊа ReVanced.
|
||||
|
||||
ĐŅĐŧа да ĐąŅĐ´ĐĩŅĐĩ ŅвĐĩĐ´ĐžĐŧĐĩĐŊи Са ĐŊĐĩĐžŅаĐēваĐŊи ŅŅйиŅиŅ."</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">ĐĐēŅĐŋĐžŅŅиŅаĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">ĐĐžĐŋиŅа ĐģĐžĐŗĐžĐ˛ĐĩŅĐĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи ĐŊа ReVanced в ĐēĐģиĐŋйОŅда</string>
|
||||
<string name="revanced_debug_logs_disabled">ĐŅŅŅŅаĐŊŅваĐŊĐĩŅĐž ĐŊа ĐŗŅĐĩŅĐēи Đĩ Đ´ĐĩаĐēŅивиŅаĐŊĐž</string>
|
||||
<string name="revanced_debug_logs_none_found">ĐĐĩ Ņа ĐŊаĐŧĐĩŅĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">ĐĐžĐŗĐžĐ˛ĐĩŅĐĩ Ņа ĐēĐžĐŋиŅаĐŊи</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">ĐĐĩŅŅĐŋĐĩŅĐŊĐž ĐĩĐēŅĐŋĐžŅŅиŅаĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">ĐСŅиŅŅваĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛ĐĩŅĐĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">ĐСŅиŅŅва вŅиŅĐēи ŅŅŅ
ŅаĐŊĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅŅŅŅаĐŊŅваĐŊĐĩ ĐŊа ĐŗŅĐĩŅĐēи ĐŊа ReVanced</string>
|
||||
<string name="revanced_debug_logs_clear_toast">ĐĐžĐŗĐžĐ˛ĐĩŅĐĩ Ņа иСŅиŅŅĐĩĐŊи</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||
<string name="revanced_hide_album_cards_title">\"ĐаŅŅи ĐŊа аĐģĐąŅĐŧиŅĐĩ\"</string>
|
||||
@@ -602,6 +621,10 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_clip_button_title">ĐŅŅĐžĐŊ Са ŅŅСдаваĐŊĐĩ ĐŊа ĐēĐģиĐŋ</string>
|
||||
<string name="revanced_hide_clip_button_summary_on">ĐŅŅĐžĐŊа Са ĐēĐģиĐŋ Đĩ ŅĐēŅиŅ</string>
|
||||
<string name="revanced_hide_clip_button_summary_off">ĐŅŅĐžĐŊа Са ĐēĐģиĐŋ ŅĐĩ ĐŋĐžĐēаСва</string>
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_shop_button_title">ĐĄĐēŅиК ĐŧĐ°ĐŗĐ°ĐˇĐ¸ĐŊ</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">ĐŅŅĐžĐŊŅŅ ĐˇĐ° ĐŧĐ°ĐŗĐ°ĐˇĐ¸ĐŊ Đĩ ŅĐēŅиŅ</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">ĐŅŅĐžĐŊŅŅ ĐˇĐ° ĐŧĐ°ĐŗĐ°ĐˇĐ¸ĐŊ Đĩ ĐŋĐžĐēаСаĐŊ</string>
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_save_button_title">ĐĄĐēŅиваĐŊĐĩ ĐŊа ĐаĐŋаСваĐŊĐĩ</string>
|
||||
<string name="revanced_hide_save_button_summary_on">ĐŅŅĐžĐŊŅŅ ĐˇĐ° СаĐŋаСваĐŊĐĩ Đĩ ŅĐēŅиŅ</string>
|
||||
@@ -700,9 +723,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">ĐĐĩĐŊŅŅĐž Са Đ¸ĐˇĐąĐžŅ ĐŊа ĐŅдиО Đĩ ŅĐēŅиŅĐž</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_off">ĐĐĩĐŊŅŅĐž Са Đ¸ĐˇĐąĐžŅ ĐŊа ĐŅдиО ŅĐĩ ĐŋĐžĐēаСва</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"ĐĐĩĐŊŅŅĐž Са аŅдиО ŅŅаĐēОвĐĩ Đĩ ŅĐēŅиŅĐž
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"ĐĐĩĐŊŅŅĐž Са аŅдиОСаĐŋĐ¸Ņ Đĩ ŅĐēŅиŅĐž
|
||||
|
||||
Đа да ĐŋĐžĐēаĐļĐĩŅĐĩ ĐŧĐĩĐŊŅŅĐž Са аŅдиО ŅŅаĐēОвĐĩ, ĐŋŅĐžĐŧĐĩĐŊĐĩŅĐĩ \"ĐОдĐŧŅĐŊа ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи\" ĐŊа iOS TV"</string>
|
||||
Đа да ĐŋĐžĐēаĐļĐĩŅĐĩ ĐŧĐĩĐŊŅŅĐž Са аŅдиОСаĐŋиŅ, ĐŋŅĐžĐŧĐĩĐŊĐĩŅĐĩ âĐОдĐŋŅавŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅиâ ĐŊа iPadOS"</string>
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_title">ĐĐģĐĩдаКŅĐĩ вŅв VR</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">ĐĐĩĐŊŅŅĐž Са ĐŗĐģĐĩдаĐŊĐĩ в VR Đĩ ŅĐēŅиŅĐž</string>
|
||||
@@ -1415,10 +1438,6 @@ Second \"item\" text"</string>
|
||||
ĐĐēŅивиŅаĐŊĐĩŅĐž ĐŊа ŅОва ĐŧĐžĐļĐĩ да ĐžŅĐēĐģŅŅи ĐŋĐž-виŅĐžĐēи видĐĩĐž ĐēаŅĐĩŅŅва"</string>
|
||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">РаСŅĐĩŅаваĐŊĐĩŅĐž ĐŊа ŅОва ĐŧĐžĐļĐĩ да ĐŋŅиŅиĐŊи ĐŋŅĐĩĐēŅŅваĐŊĐĩ ĐŊа вŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž ĐŊа видĐĩĐž, вĐģĐžŅĐĩĐŊ ĐļĐ¸Đ˛ĐžŅ ĐŊа йаŅĐĩŅиŅŅа и ĐŊĐĩиСвĐĩŅŅĐŊи ŅŅŅаĐŊиŅĐŊи ĐĩŅĐĩĐēŅи.</string>
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore ĐаŅŅŅОКĐēи</string>
|
||||
<string name="microg_settings_summary">ĐаŅŅŅОКĐēи ĐŊа GmsCore</string>
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
<string name="revanced_disable_haptic_feedback_title">ĐийŅаŅиОĐŊĐŊа ОйŅаŅĐŊа вŅŅСĐēа</string>
|
||||
<string name="revanced_disable_haptic_feedback_summary">ĐŅĐžĐŧŅĐŊа ĐŊа вийŅаŅиОĐŊĐŊаŅа ОйŅаŅĐŊа вŅŅСĐēа</string>
|
||||
@@ -1458,7 +1477,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_force_original_audio_summary_on">ĐСĐŋĐžĐģСваĐŊĐĩ ĐŊа ĐžŅĐ¸ĐŗĐ¸ĐŊаĐģĐŊĐ¸Ņ ĐĩСиĐē ĐŊа аŅдиОŅĐž</string>
|
||||
<string name="revanced_force_original_audio_summary_off">ĐСĐŋĐžĐģСваĐŊĐĩ ĐŊа аŅдиО ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Đа да иСĐŋĐžĐģСваŅĐĩ ŅаСи ŅŅĐŊĐēŅиŅ, ŅĐŧĐĩĐŊĐĩŅĐĩ âФаĐģŅиŅиŅиŅаĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅиâ ĐŊа iOS TV</string>
|
||||
<string name="revanced_force_original_audio_not_available">Đа да иСĐŋĐžĐģСваŅĐĩ ŅаСи ŅŅĐŊĐēŅиŅ, ĐŋŅĐžĐŧĐĩĐŊĐĩŅĐĩ \'ФаĐģŅиŅиŅиŅаĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи\' ĐŊа вŅĐĩĐēи ĐēĐģиĐĩĐŊŅ, ĐžŅвĐĩĐŊ Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
@@ -1532,35 +1551,54 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Са ĐŋŅĐĩвŅŅŅаĐŊĐĩ Đĩ Đ´ĐĩаĐēŅивиŅаĐŊ</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">ĐОдĐŋŅавŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">ĐОдĐŋŅавĐĩŅĐĩ ĐēĐģиĐĩĐŊŅŅĐēиŅĐĩ видĐĩĐž ĐŋĐžŅĐžŅи, Са да ĐŋŅĐĩĐ´ĐžŅвŅаŅиŅĐĩ ĐŋŅОйĐģĐĩĐŧи Ņ Đ˛ŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž</string>
|
||||
<string name="revanced_spoof_video_streams_title">ĐОдĐŋŅавŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅĐžŅи</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">ĐидĐĩĐž ĐŋĐžŅĐžŅиŅĐĩ Ņа ĐŋОдĐŋŅавĐĩĐŊи</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"ĐĐžŅĐžŅиŅĐĩ ĐŊа видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŊĐĩ Ņа ŅаĐģŅиŅиŅиŅаĐŊи
|
||||
|
||||
ĐŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž ĐŊа видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ ŅайОŅи"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">ĐĐĩаĐēŅивиŅаĐŊĐĩŅĐž ĐŊа ŅаСи ĐŊаŅŅŅОКĐēа ŅĐĩ дОвĐĩĐ´Đĩ Đ´Đž ĐŋŅОйĐģĐĩĐŧи Ņ Đ˛ŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž ĐŊа видĐĩĐž.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">ĐĐģиĐĩĐŊŅ ĐŋĐž ĐŋОдŅаСйиŅаĐŊĐĩ</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_title">ĐŅиĐŊŅдиŅĐĩĐģĐŊĐž иСĐŋĐžĐģСваĐŊĐĩ ĐŊа AVC (H.264) ĐŊа iOS</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">ĐидĐĩĐž ĐēОдĐĩĐēŅŅ Đĩ ĐŋŅиĐŊŅдиŅĐĩĐģĐŊĐž СададĐĩĐŊ ĐŊа AVC (H.264)</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">ĐидĐĩĐž ĐēОдĐĩĐēŅŅ ŅĐĩ ĐžĐŋŅĐĩĐ´ĐĩĐģŅ Đ°Đ˛ŅĐžĐŧаŅиŅĐŊĐž</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"ĐĐēĐģŅŅваĐŊĐĩŅĐž ĐŊа ŅОва ĐŧĐžĐļĐĩ да ĐŋОдОйŅи ĐļивОŅа ĐŊа йаŅĐĩŅиŅŅа и да ĐŋĐžĐŋŅави СаĐĩĐēваĐŊĐĩŅĐž ĐŋŅи вŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩ.
|
||||
|
||||
AVC иĐŧа ĐŧаĐēŅиĐŧаĐģĐŊа ŅĐĩСОĐģŅŅĐ¸Ņ ĐžŅ 1080p, Opus аŅдиО ĐēОдĐĩĐē ĐŊĐĩ Đĩ ĐŊаĐģиŅĐĩĐŊ и вŅСĐŋŅОиСвĐĩĐļдаĐŊĐĩŅĐž ĐŊа видĐĩĐž ŅĐĩ иСĐŋĐžĐģСва ĐŋОвĐĩŅĐĩ иĐŊŅĐĩŅĐŊĐĩŅ Đ´Đ°ĐŊĐŊи ĐžŅ VP9 иĐģи AV1."</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_title">ĐŅĐĩĐēŅи ĐŊа иСĐŧаĐŧаŅа в iOS</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"âĸ ФиĐģĐŧи иĐģи ĐŋĐģаŅĐĩĐŊи видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ ŅĐĩ вŅСĐŋŅОиСвĐĩĐļдаŅ
|
||||
âĸ ĐĄŅайиĐģĐĩĐŊ СвŅĐē ĐŊĐĩ Đĩ ĐŊаĐģиŅĐĩĐŊ
|
||||
âĸ ĐидĐĩĐžĐēĐģиĐŋОвĐĩŅĐĩ СавŅŅŅĐ˛Đ°Ņ 1 ŅĐĩĐēŅĐŊда ĐŋĐž-ŅаĐŊĐž"</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">ĐĄŅŅаĐŊиŅĐŊи ĐĩŅĐĩĐēŅи ĐžŅ ĐŋОдĐŧĐĩĐŊŅĐŊĐĩŅĐž</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_title">Strani4ni efekti na fal6ivoto predstavqne na Android</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ Lipsva menju za audio pisti
|
||||
âĸ Ne e nali4na stabilna glasnost
|
||||
âĸ Ne e nali4na forsirana originalna audio pista"</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ ĐиĐŋŅва ĐŧĐĩĐŊŅŅĐž Са аŅдиОСаĐŋиŅи
|
||||
âĸ ĐĄŅайиĐģĐĩĐŊ СвŅĐē ĐŊĐĩ Đĩ ĐŊаĐģиŅĐĩĐŊ"</string>
|
||||
<string name="revanced_spoof_video_streams_about_ipados_summary">âĸ ĐидĐĩĐžŅĐž ĐŧĐžĐļĐĩ да ŅĐŋŅĐĩ ĐŊа 1:00 иĐģи ĐŧĐžĐļĐĩ да ĐŊĐĩ Đĩ ĐŊаĐģиŅĐŊĐž в ĐŊŅĐēОи ŅĐĩĐŗĐ¸ĐžĐŊи</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">âĸ ĐĐēŅĐŋĐĩŅиĐŧĐĩĐŊŅаĐģĐĩĐŊ ĐēĐģиĐĩĐŊŅ Đ¸ ĐŧĐžĐļĐĩ да ŅĐŋŅĐĩ да ŅайОŅи ĐŋĐž вŅŅĐēĐž вŅĐĩĐŧĐĩ</string>
|
||||
<string name="revanced_spoof_video_streams_about_no_av1">âĸ ĐĐĩС AV1 видĐĩĐž ĐēОдĐĩĐē</string>
|
||||
<string name="revanced_spoof_video_streams_about_kids_videos">âĸ ĐĐĩŅŅĐēиŅĐĩ видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ ŅĐĩ вŅСĐŋŅОиСвĐĩĐļдаŅ, ĐēĐžĐŗĐ°ŅĐž ŅŅĐĩ иСĐģĐĩСĐģи ĐžŅ ĐŋŅĐžŅиĐģа Ņи иĐģи в ŅĐĩĐļиĐŧ \"иĐŊĐēĐžĐŗĐŊиŅĐž\"</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Poka6i v Statistiki za nerds</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">TipŅŅ na klienta se poka6va v Statistiki za nerds</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">KlientŅŅ e skriŅ v Statistiki za nerds</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">Ezik po ĐŋОдŅаСйиŅаĐŊĐĩ za audio potok v VR</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">ĐСиĐē ĐŊа аŅдиО ĐŋĐžŅĐžĐēа</string>
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
<string name="revanced_spoof_video_streams_language_not_available">Đа да иСйĐĩŅĐĩŅĐĩ ĐēĐžĐŊĐēŅĐĩŅĐĩĐŊ аŅдиО ĐĩСиĐē, иСĐēĐģŅŅĐĩŅĐĩ \'ĐŅиĐŊŅдиŅĐĩĐģĐŊĐž ĐžŅĐ¸ĐŗĐ¸ĐŊаĐģĐĩĐŊ аŅдиО ĐĩСиĐē\'</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">ĐŅĐŊĐžŅĐŊĐž</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Đ ĐĩĐēĐģаĐŧи</string>
|
||||
<string name="revanced_settings_music_screen_2_general_title">ĐĐąŅи</string>
|
||||
<string name="revanced_settings_music_screen_3_player_title">ĐĐģĐĩĐšŅŅ</string>
|
||||
<string name="revanced_settings_music_screen_4_misc_title">РаСĐŊи</string>
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
<string name="revanced_music_hide_video_ads_title">ĐĄĐēŅиваĐŊĐĩ ĐŊа видĐĩĐžŅĐĩĐēĐģаĐŧи</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_on">ĐидĐĩĐžŅĐĩĐēĐģаĐŧиŅĐĩ Ņа ŅĐēŅиŅи</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_off">ĐидĐĩĐžŅĐĩĐēĐģаĐŧиŅĐĩ Ņа ĐŋĐžĐēаСаĐŊи</string>
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
<string name="revanced_music_play_permanent_repeat_title">ĐĐēŅивиŅаĐŊĐĩ ĐŊа ĐŋĐžŅŅĐžŅĐŊĐŊĐž ĐŋОвŅаŅŅĐŊĐĩ</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_on">ĐĐžŅŅĐžŅĐŊĐŊĐžŅĐž ĐŋОвŅаŅŅĐŊĐĩ Đĩ аĐēŅивиŅаĐŊĐž</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_off">ĐĐžŅŅĐžŅĐŊĐŊĐžŅĐž ĐŋОвŅаŅŅĐŊĐĩ Đĩ Đ´ĐĩаĐēŅивиŅаĐŊĐž</string>
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
<string name="revanced_music_hide_category_bar_title">ĐĄĐēŅиваĐŊĐĩ ĐŊа ĐģĐĩĐŊŅаŅа Ņ ĐēаŅĐĩĐŗĐžŅии</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_on">ĐĐĩĐŊŅаŅа Ņ ĐēаŅĐĩĐŗĐžŅии Đĩ ŅĐēŅиŅа</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_off">ĐĐĩĐŊŅаŅа Ņ ĐēаŅĐĩĐŗĐžŅии Đĩ ĐŋĐžĐēаСаĐŊа</string>
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
<string name="revanced_music_hide_get_premium_label_title">ĐĄĐēŅиваĐŊĐĩ ĐŊа ĐĩŅиĐēĐĩŅа âĐСĐĩĐŧĐĩŅĐĩ Music Premiumâ</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_on">ĐŅиĐēĐĩŅŅŅ Đĩ ŅĐēŅиŅ</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_off">ĐŅиĐēĐĩŅŅŅ Đĩ ĐŋĐžĐēаСаĐŊ</string>
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
<string name="revanced_music_hide_upgrade_button_title">ĐĄĐēŅиваĐŊĐĩ ĐŊа ĐąŅŅĐžĐŊа Са ĐŊадŅŅŅОКĐēа</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_on">ĐŅŅĐžĐŊŅŅ Đĩ ŅĐēŅиŅ</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_off">ĐŅŅĐžĐŊŅŅ Đĩ ĐŋĐžĐēаСаĐŊ</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
and changes made here must also be made there. -->
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore āϏā§āĻāĻŋāĻ</string>
|
||||
<string name="microg_settings_summary">GmsCore āĻāϰ āĻāύā§āϝ āϏā§āĻāĻŋāĻ</string>
|
||||
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
|
||||
<string name="gms_core_toast_not_installed_message">MicroG GmsCore āĻāύāϏā§āĻāϞ āĻāϰāĻž āĻšā§āύāĻŋāĨ¤ āĻāύāϏā§āĻāϞ āĻāϰā§āύāĨ¤</string>
|
||||
<string name="gms_core_dialog_title">āĻĒāĻĻāĻā§āώā§āĻĒ āĻĒā§āϰā§ā§āĻāύ</string>
|
||||
@@ -84,6 +86,37 @@ MicroG-āĻāϰ āĻāύā§āϝ āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āĻ
āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻ
|
||||
āĻāĻžāϞāĻŋāϝāĻŧā§ āϝāĻžāύ āĻŦā§āϤāĻžāĻŽāĻāĻŋ āĻā§āϝāĻžāĻĒ āĻāϰā§āύ āĻāĻŦāĻ āĻ
āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻā§āĻļāύ āĻĒāϰāĻŋāĻŦāϰā§āϤāύāĻā§āϞāĻŋ āĻ
āύā§āĻŽā§āĻĻāύ āĻāϰā§āύāĨ¤"</string>
|
||||
<string name="gms_core_dialog_continue_text">āĻāĻāĻŋā§ā§ āϝāĻžāύ</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽāĻŋāĻ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āϏāĻŽāϏā§āϝāĻž āĻĒā§āϰāϤāĻŋāϰā§āϧ āĻāϰāϤ⧠āĻā§āϞāĻžā§ā§āύā§āĻ āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_title">āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āϏāĻāĻā§āϰāĻžāύā§āϤ āϏāĻŽāϏā§āϝāĻž āϰā§āϧ āĻāϰāϤ⧠āĻā§āϞāĻžāϝāĻŧā§āύā§āĻā§āϰ āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽāĻā§āϞāĻŋ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_title">āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽāĻŋāĻ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">"āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§
|
||||
|
||||
āĻāĻĒāύāĻŋ āϝāĻĻāĻŋ YouTube Premium āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āĻšāύ, āϤāĻžāĻšāϞ⧠āĻāĻ āϏā§āĻāĻŋāĻāĻāĻŋāϰ āĻĒā§āϰāϝāĻŧā§āĻāύ āύāĻžāĻ āĻšāϤ⧠āĻĒāĻžāϰā§"</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰāĻž āĻšāϝāĻŧāύāĻŋ
|
||||
|
||||
āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āĻāĻžāĻ āύāĻžāĻ āĻāϰāϤ⧠āĻĒāĻžāϰā§"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">āĻāĻ āϏā§āĻāĻŋāĻ āĻŦāύā§āϧ āĻāϰāϞ⧠āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āϏāĻŽāϏā§āϝāĻž āĻšāϤ⧠āĻĒāĻžāϰā§āĨ¤</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">āĻĄāĻŋāĻĢāϞā§āĻ āĻā§āϞāĻžā§ā§āύā§āĻ</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">āĻĄāĻŋāĻŦāĻžāĻāĻŋāĻ</string>
|
||||
<string name="revanced_debug_screen_summary">āĻĄāĻŋāĻŦāĻžāĻāĻŋāĻ āĻ
āĻĒāĻļāύ āϏāĻā§āϰāĻŋā§ āĻŦāĻž āύāĻŋāώā§āĻā§āϰāĻŋā§ āĻāϰā§āύ</string>
|
||||
<string name="revanced_debug_title">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻŋāĻ</string>
|
||||
<string name="revanced_debug_summary_on">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āϏāĻā§āϰāĻŋā§ āĻšā§ā§āĻā§</string>
|
||||
<string name="revanced_debug_summary_off">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āύāĻŋāώā§āĻā§āϰāĻŋā§ āĻšā§ā§āĻā§</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻā§āϞāĻŋ āϰāĻĢāϤāĻžāύāĻŋ āĻāϰā§āύ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">āĻā§āϞāĻŋāĻĒāĻŦā§āϰā§āĻĄā§ ReVanced āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻā§āϞāĻŋ āĻ
āύā§āϞāĻŋāĻĒāĻŋ āĻāϰā§</string>
|
||||
<string name="revanced_debug_logs_disabled">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻŋāĻ āύāĻŋāώā§āĻā§āϰāĻŋāϝāĻŧ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
<string name="revanced_debug_logs_none_found">āĻā§āύ⧠āϞāĻ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāϝāĻŧāύāĻŋ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">āϞāĻ āĻ
āύā§āϞāĻŋāĻĒāĻŋ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">āϞāĻ āĻāĻā§āϏāĻĒā§āϰā§āĻ āĻāϰāĻž āϝāĻžāϝāĻŧāύāĻŋ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻā§āϞāĻŋ āϏāĻžāĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">āϏāĻŽāϏā§āϤ āϏāĻā§āĻāĻŋāϤ ReVanced āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āϏāĻžāĻĢ āĻāϰā§</string>
|
||||
<string name="revanced_debug_logs_clear_toast">āϞāĻ āϏāĻžāĻĢ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
@@ -110,11 +143,6 @@ MicroG-āĻāϰ āĻāύā§āϝ āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āĻ
āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻ
|
||||
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts āĻŦā§āϝāĻžāĻāĻā§āϰāĻžāĻāύā§āĻĄ āĻĒā§āϞ⧠āϏāĻā§āώāĻŽ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">āĻĄāĻŋāĻŦāĻžāĻāĻŋāĻ</string>
|
||||
<string name="revanced_debug_screen_summary">āĻĄāĻŋāĻŦāĻžāĻāĻŋāĻ āĻ
āĻĒāĻļāύ āϏāĻā§āϰāĻŋā§ āĻŦāĻž āύāĻŋāώā§āĻā§āϰāĻŋā§ āĻāϰā§āύ</string>
|
||||
<string name="revanced_debug_title">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻŋāĻ</string>
|
||||
<string name="revanced_debug_summary_on">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āϏāĻā§āϰāĻŋā§ āĻšā§ā§āĻā§</string>
|
||||
<string name="revanced_debug_summary_off">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āύāĻŋāώā§āĻā§āϰāĻŋā§ āĻšā§ā§āĻā§</string>
|
||||
<string name="revanced_debug_protobuffer_title">āĻĒā§āϰāĻā§āĻāϞ āĻŦāĻžāĻĢāĻžāϰ āϞāĻ</string>
|
||||
<string name="revanced_debug_protobuffer_summary_on">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āĻĒā§āϰāĻā§āĻāϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻāϝā§āĻā§āϤ āĻāϰāĻŦā§</string>
|
||||
<string name="revanced_debug_protobuffer_summary_off">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āĻĒā§āϰāĻā§āĻāϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻāϝā§āĻā§āϤ āĻāϰāĻŦā§ āύāĻž</string>
|
||||
@@ -128,15 +156,6 @@ MicroG-āĻāϰ āĻāύā§āϝ āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āĻ
āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻ
|
||||
<string name="revanced_debug_toast_on_error_user_dialog_message">"āϤā§āϰā§āĻāĻŋ \"toast\" āĻŦāύā§āϧ āĻāϰ⧠ReVanced āϤā§āϰā§āĻāĻŋ āĻŦāĻŋāĻā§āĻāĻĒā§āϤāĻŋāĻā§āϞāĻŋ āϞā§āĻāĻžāύ⧠āĻšāϝāĻŧāĨ¤
|
||||
|
||||
āĻāĻĒāύāĻŋ āĻā§āύāĻ āĻ
āĻĒā§āϰāϤā§āϝāĻžāĻļāĻŋāϤ āĻāĻāύāĻžāϰ āĻŦāĻŋāώāϝāĻŧā§ āĻ
āĻŦāĻšāĻŋāϤ āĻšāĻŦā§āύ āύāĻžāĨ¤"</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_title">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻā§āϞāĻŋ āϰāĻĢāϤāĻžāύāĻŋ āĻāϰā§āύ</string>
|
||||
<string name="revanced_debug_export_logs_to_clipboard_summary">āĻā§āϞāĻŋāĻĒāĻŦā§āϰā§āĻĄā§ ReVanced āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻā§āϞāĻŋ āĻ
āύā§āϞāĻŋāĻĒāĻŋ āĻāϰā§</string>
|
||||
<string name="revanced_debug_logs_disabled">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻŋāĻ āύāĻŋāώā§āĻā§āϰāĻŋāϝāĻŧ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
<string name="revanced_debug_logs_none_found">āĻā§āύ⧠āϞāĻ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāϝāĻŧāύāĻŋ</string>
|
||||
<string name="revanced_debug_logs_copied_to_clipboard">āϞāĻ āĻ
āύā§āϞāĻŋāĻĒāĻŋ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
<string name="revanced_debug_logs_failed_to_export">āϞāĻ āĻāĻā§āϏāĻĒā§āϰā§āĻ āĻāϰāĻž āϝāĻžāϝāĻŧāύāĻŋ: %s</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_title">āĻĄāĻŋāĻŦāĻžāĻ āϞāĻāĻā§āϞāĻŋ āϏāĻžāĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_debug_logs_clear_buffer_summary">āϏāĻŽāϏā§āϤ āϏāĻā§āĻāĻŋāϤ ReVanced āĻĄāĻŋāĻŦāĻžāĻ āϞāĻ āϏāĻžāĻĢ āĻāϰā§</string>
|
||||
<string name="revanced_debug_logs_clear_toast">āϞāĻ āϏāĻžāĻĢ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.general.hideLayoutComponentsPatch">
|
||||
<string name="revanced_hide_album_cards_title">āĻ
ā§āϝāĻžāϞāĻŦāĻžāĻŽ āĻāĻžāϰā§āĻĄ āϞā§āĻāĻžāύ</string>
|
||||
@@ -598,6 +617,10 @@ MicroG-āĻāϰ āĻāύā§āϝ āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āĻ
āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻ
|
||||
<string name="revanced_hide_clip_button_title">āĻā§āϞāĻŋāĻĒ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_hide_clip_button_summary_on">āĻā§āϞāĻŋāĻĒ āĻŦā§āϤāĻžāĻŽ āϞā§āĻāĻŋā§ā§ āϰā§ā§āĻā§</string>
|
||||
<string name="revanced_hide_clip_button_summary_off">āĻā§āϞāĻŋāĻĒ āĻŦā§āϤāĻžāĻŽ āĻĒā§āϰāĻĻāϰā§āĻļāĻŋāϤ āĻšā§ā§āĻā§</string>
|
||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_shop_button_title">āĻļāĻĒ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">āĻļāĻĒ āĻŦāĻžāĻāύ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">āĻļāĻĒ āĻŦāĻžāĻāύ āĻĻā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_save_button_title">āϏāĻāϰāĻā§āώāĻŖ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_hide_save_button_summary_on">āϏāĻāϰāĻā§āώāĻŖ āĻŦā§āϤāĻžāĻŽ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
@@ -698,7 +721,7 @@ MicroG-āĻāϰ āĻāύā§āϝ āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āĻ
āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻ
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_not_available">"āĻ
āĻĄāĻŋāĻ āĻā§āϰā§āϝāĻžāĻ āĻŽā§āύ⧠āϞā§āĻāĻžāύ⧠āĻāĻā§
|
||||
|
||||
āĻ
āĻĄāĻŋāĻ āĻā§āϰā§āϝāĻžāĻ āĻŽā§āύ⧠āĻĻā§āĻāĻžāϤā§, 'āϏā§āĻĒā§āĻĢ āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ' āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰ⧠iOS TV āĻāϰā§āύ"</string>
|
||||
āĻ
āĻĄāĻŋāĻ āĻā§āϰā§āϝāĻžāĻ āĻŽā§āύ⧠āĻĻā§āĻāĻžāύā§āϰ āĻāύā§āϝ, 'āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ' āĻā§ iPadOS āĻ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰā§āύ"</string>
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_title">āĻāĻŋāĻāϰ-āĻ āĻāĻĄāĻŧāĻŋ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">āĻāĻŋāĻāϰ āĻŽā§āύā§āϤ⧠āĻĻā§āĻā§āύ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
@@ -1411,10 +1434,6 @@ DeArrow āϏāĻŽā§āĻĒāϰā§āĻā§ āĻāϰāĻ āĻāĻžāύāϤ⧠āĻāĻāĻžāύ⧠āĻ
|
||||
āĻāĻāĻŋ āϏāĻā§āϰāĻŋāϝāĻŧ āĻāϰāĻž āĻāĻā§āĻ āĻāĻŋāĻĄāĻŋāĻ āĻā§āĻŖāĻŽāĻžāύāĻā§āϞāĻŋ āĻāύāϞāĻ āĻāϰāϤ⧠āĻĒāĻžāϰā§"</string>
|
||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">āĻāĻāĻŋ āϏāĻā§āϰāĻŋā§ āĻāϰāĻžāϰ āĻĢāϞ⧠āĻāĻĒāύāĻŋ āĻāĻŋāĻĄāĻŋāĻ āĻāϞāĻžāϰ āĻā§āώā§āϤā§āϰ⧠āĻāĻāĻā§ āĻāϞāĻž, āĻāĻžāϰāĻžāĻĒ āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āϞāĻžāĻāĻĢ āĻāĻŦāĻ āĻ
āĻāĻžāύāĻž āĻĒāĻžāϰā§āĻļā§āĻŦ-āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋā§āĻžāϰ āϏāĻŽā§āĻŽā§āĻāĻŋāύ āĻšāϤ⧠āĻĒāĻžāϰā§āύāĨ¤</string>
|
||||
</patch>
|
||||
<patch id="misc.gms.gmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore āϏā§āĻāĻŋāĻ</string>
|
||||
<string name="microg_settings_summary">GmsCore āĻāϰ āĻāύā§āϝ āϏā§āĻāĻŋāĻ</string>
|
||||
</patch>
|
||||
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
|
||||
<string name="revanced_disable_haptic_feedback_title">āĻāĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋā§āĻž</string>
|
||||
<string name="revanced_disable_haptic_feedback_summary">āĻāĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋā§āĻž āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰā§āύ</string>
|
||||
@@ -1454,7 +1473,7 @@ DeArrow āϏāĻŽā§āĻĒāϰā§āĻā§ āĻāϰāĻ āĻāĻžāύāϤ⧠āĻāĻāĻžāύ⧠āĻ
|
||||
<string name="revanced_force_original_audio_summary_on">āĻŽā§āϞ āĻ
āĻĄāĻŋāĻ āĻāĻžāώāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšāĻā§āĻā§</string>
|
||||
<string name="revanced_force_original_audio_summary_off">āĻĄāĻŋāĻĢāϞā§āĻ āĻ
āĻĄāĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻā§</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">āĻāĻ āĻŦā§āĻļāĻŋāώā§āĻā§āϝāĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤā§, \'āϏā§āĻĒā§āĻĢ āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰā§āĻŽ\' āĻā§ iOS TV-āϤ⧠āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰā§āύ</string>
|
||||
<string name="revanced_force_original_audio_not_available">āĻāĻ āĻŦā§āĻļāĻŋāώā§āĻā§āϝāĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤā§, \'āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ\' āĻ
ā§āϝāĻžāύā§āĻĄā§āϰāϝāĻŧā§āĻĄ āϏā§āĻā§āĻĄāĻŋāĻ āĻāĻžāĻĄāĻŧāĻž āĻ
āύā§āϝ āĻā§āύ⧠āĻā§āϞāĻžāϝāĻŧā§āύā§āĻā§ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰā§āύ</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
@@ -1528,35 +1547,54 @@ DeArrow āϏāĻŽā§āĻĒāϰā§āĻā§ āĻāϰāĻ āĻāĻžāύāϤ⧠āĻāĻāĻžāύ⧠āĻ
|
||||
<string name="revanced_slide_to_seek_summary_off">āĻāĻŋāĻĄāĻŋāĻāϰ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻ
āĻāĻļā§ āϝā§āϤ⧠āĻāĻžāύā§āύ āϏāĻā§āϰāĻŋā§ āĻāϰāĻž āĻšā§āύāĻŋ</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_screen_title">āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽāĻŋāĻ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_screen_summary">āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āϏāĻŽāϏā§āϝāĻž āĻĒā§āϰāϤāĻŋāϰā§āϧ āĻāϰāϤ⧠āĻā§āϞāĻžā§ā§āύā§āĻ āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_title">āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽāĻŋāĻ āϏā§āĻĒā§āĻĢ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_summary_on">āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āϏā§āĻĒā§āĻĢ āĻāϰāĻž āĻšā§ā§āĻā§</string>
|
||||
<string name="revanced_spoof_video_streams_summary_off">"āĻāĻŋāĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āĻā§āϝāĻŧāĻž āύāϝāĻŧ
|
||||
|
||||
āĻāĻŋāĻĄāĻŋāĻ āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āĻāĻžāĻ āύāĻžāĻ āĻāϰāϤ⧠āĻĒāĻžāϰā§"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">āĻāĻ āϏā§āĻāĻŋāĻāĻāĻŋ āĻŦāύā§āϧ āĻāϰāĻžāϰ āĻĢāϞ⧠āĻāĻŋāĻĄāĻŋāĻ āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āϤā§āϰā§āĻāĻŋ āĻšāϤ⧠āĻĒāĻžāϰā§āĨ¤</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">āĻĄāĻŋāĻĢāϞā§āĻ āĻā§āϞāĻžā§ā§āύā§āĻ</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_title">iOS AVC (H.264) āĻŦāĻžāϧā§āϝāϤāĻžāĻŽā§āϞāĻ āĻāϰā§āύ</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">āĻāĻŋāĻĄāĻŋāĻ āĻā§āĻĄā§āĻ AVC (H.264) āĻ āĻŦāĻžāϧā§āϝāϤāĻžāĻŽā§āϞāĻ āĻāϰāĻž āĻšā§ā§āĻā§</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">āĻāĻŋāĻĄāĻŋāĻ āĻā§āĻĄā§āĻ āϏā§āĻŦāϝāĻŧāĻāĻā§āϰāĻŋāϝāĻŧāĻāĻžāĻŦā§ āύāĻŋāϰā§āϧāĻžāϰāĻŋāϤ āĻšā§</string>
|
||||
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"āĻāĻāĻŋ āϏāĻā§āώāĻŽ āĻāϰāϞ⧠āĻŦā§āϝāĻžāĻāĻžāϰāĻŋ āϞāĻžāĻāĻĢ āĻāύā§āύāϤ āĻšāϤ⧠āĻĒāĻžāϰ⧠āĻāĻŦāĻ āĻĒā§āϞā§āĻŦā§āϝāĻžāĻ āϏā§āĻāĻžāĻāĻžāϰāĻŋāĻ āϏāĻŽāϏā§āϝāĻž āϏāĻŽāĻžāϧāĻžāύ āĻšāϤ⧠āĻĒāĻžāϰā§āĨ¤
|
||||
|
||||
AVC-āĻāϰ āϏāϰā§āĻŦā§āĻā§āĻ āϰā§āĻā§āϞāĻŋāĻāĻļāύ āĻšāϞ 1080p, Opus āĻ
āĻĄāĻŋāĻ āĻā§āĻĄā§āĻ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž āĻāĻŦāĻ VP9 āĻŦāĻž AV1-āĻāϰ āϤā§āϞāύāĻžāϝāĻŧ āĻāĻŋāĻĄāĻŋāĻ āĻĒā§āϞā§āĻŦā§āϝāĻžāĻā§ āĻŦā§āĻļāĻŋ āĻāύā§āĻāĻžāϰāύā§āĻ āĻĄā§āĻāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšāĻŦā§ã"</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_title">āĻāĻāĻāĻāϏ āϏā§āĻĒā§āĻĢāĻŋāĻāϝāĻŧā§āϰ āĻĒāĻžāϰā§āĻļā§āĻŦ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻž</string>
|
||||
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"âĸ āĻŽā§āĻāĻŋ āĻŦāĻž āĻ
āϰā§āĻĨ āĻĒā§āϰāĻĻāĻžāύā§āϰ āĻāĻŋāĻĄāĻŋāĻ āĻāĻžāϞ⧠āύāĻžāĻ āĻšāϤ⧠āĻĒāĻžāϰā§
|
||||
âĸ āϏā§āĻĨāĻŋāϰ āĻāϞāĻŋāĻāĻŽ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž
|
||||
âĸ āĻāĻŋāĻĄāĻŋāĻāĻā§āϞāĻŋ 1 āϏā§āĻā§āύā§āĻĄ āĻāĻā§ āĻļā§āώ āĻšāϝāĻŧā§ āϝāĻžāϝāĻŧ"</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">āϏā§āĻĒā§āĻĢāĻŋāĻā§ā§āϰ āĻĒāĻžāϰā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻž</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_title">Android āϏā§āĻĒā§āĻĢāĻŋāĻāϝāĻŧā§āϰ āĻĒāĻžāϰā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻž</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ āĻ
āĻĄāĻŋāĻ āĻā§āϰā§āϝāĻžāĻ āĻŽā§āύ⧠āύā§āĻ
|
||||
âĸ āϏā§āĻĨāĻŋāϰ āĻāϞāĻŋāĻāĻŽ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž
|
||||
âĸ āĻŽā§āϞ āĻ
āĻĄāĻŋāĻ āĻā§āϰ āĻāϰ⧠āĻāĻžāϞ⧠āĻāϰāĻž āϝāĻžāϝāĻŧ āύāĻž"</string>
|
||||
<string name="revanced_spoof_video_streams_about_android_summary">"âĸ āĻ
āĻĄāĻŋāĻ āĻā§āϰā§āϝāĻžāĻ āĻŽā§āύ⧠āĻ
āύā§āĻĒāϏā§āĻĨāĻŋāϤ
|
||||
âĸ āϏā§āĻĨāĻŋāϤāĻŋāĻļā§āϞ āĻāϞāĻŋāĻāĻŽ āĻāĻĒāϞāĻŦā§āϧ āύā§āĻ"</string>
|
||||
<string name="revanced_spoof_video_streams_about_ipados_summary">âĸ āĻāĻŋāĻĄāĻŋāĻ ā§§:ā§Ļā§Ļ āĻŽāĻŋāύāĻŋāĻā§ āĻŦāύā§āϧ āĻšāϤ⧠āĻĒāĻžāϰā§, āĻ
āĻĨāĻŦāĻž āĻāĻŋāĻā§ āĻ
āĻā§āĻāϞ⧠āĻāĻĒāϞāĻŦā§āϧ āύāĻžāĻ āĻšāϤ⧠āĻĒāĻžāϰā§</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">âĸ āĻĒāϰā§āĻā§āώāĻžāĻŽā§āϞāĻ āĻā§āϞāĻžāϝāĻŧā§āύā§āĻ āĻāĻŦāĻ āϝā§āĻā§āύ⧠āϏāĻŽāϝāĻŧ āĻāĻžāĻ āĻāϰāĻž āĻŦāύā§āϧ āĻāϰāϤ⧠āĻĒāĻžāϰā§</string>
|
||||
<string name="revanced_spoof_video_streams_about_no_av1">âĸ āĻā§āύ⧠AV1 āĻāĻŋāĻĄāĻŋāĻ āĻā§āĻĄā§āĻ āύā§āĻ</string>
|
||||
<string name="revanced_spoof_video_streams_about_kids_videos">âĸ āϞāĻāĻāĻāĻ āĻāϰāĻž āĻšāϞ⧠āĻŦāĻž āĻāĻĻā§āĻŽāĻŦā§āĻļā§ āĻŽā§āĻĄā§ āĻŦāĻžāĻā§āĻāĻžāĻĻā§āϰ āĻāĻŋāĻĄāĻŋāĻ āĻāϞāϤ⧠āύāĻžāĻ āĻĒāĻžāϰā§</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">āϏā§āĻā§āϝāĻžāĻāϏ āĻĢāϰ āύāĻžāϰā§āĻĄāϏ⧠āĻĻā§āĻāĻžāύ</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">āϏā§āĻā§āϝāĻžāĻāϏ āĻĢāϰ āύāĻžāϰā§āĻĄāϏ⧠āĻā§āϞāĻžāϝāĻŧā§āύā§āĻ āĻĒā§āϰāĻāĻžāϰ āĻĻā§āĻāĻžāύ⧠āĻšāĻŦā§</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">āϏā§āĻā§āϝāĻžāĻāϏ āĻĢāϰ āύāĻžāϰā§āĻĄāϏ⧠āĻā§āϞāĻžāϝāĻŧā§āύā§āĻ āϞā§āĻāĻžāύ⧠āĻšāĻŦā§</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">VR āĻĄāĻŋāĻĢāϞā§āĻ āĻ
āĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āĻāĻžāώāĻž</string>
|
||||
<string name="revanced_spoof_video_streams_language_title">āĻ
āĻĄāĻŋāĻ āϏā§āĻā§āϰāĻŋāĻŽ āĻāĻžāώāĻž</string>
|
||||
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
|
||||
<string name="revanced_spoof_video_streams_language_not_available">āĻāĻāĻāĻŋ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻ
āĻĄāĻŋāĻ āĻāĻžāώāĻž āύāĻŋāϰā§āĻŦāĻžāĻāύ āĻāϰāϤā§, \'āĻŽā§āϞ āĻ
āĻĄāĻŋāĻ āĻāĻžāώāĻž āĻā§āϰ āĻāϰ⧠āĻāĻžāϞ⧠āϰāĻžāĻā§āύ\' āĻŦāύā§āϧ āĻāϰā§āύ</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">āϏāĻŽā§āĻĒāϰā§āĻā§</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">āĻŦāĻŋāĻā§āĻāĻžāĻĒāύ</string>
|
||||
<string name="revanced_settings_music_screen_2_general_title">āϏāĻžāϧāĻžāϰāĻŖ</string>
|
||||
<string name="revanced_settings_music_screen_3_player_title">āĻĒā§āϞā§āϝāĻŧāĻžāϰ</string>
|
||||
<string name="revanced_settings_music_screen_4_misc_title">āĻŦāĻŋāĻŦāĻŋāϧ</string>
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
<string name="revanced_music_hide_video_ads_title">āĻāĻŋāĻĄāĻŋāĻ āĻŦāĻŋāĻā§āĻāĻžāĻĒāύ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_on">āĻāĻŋāĻĄāĻŋāĻ āĻŦāĻŋāĻā§āĻāĻžāĻĒāύ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
<string name="revanced_music_hide_video_ads_summary_off">āĻāĻŋāĻĄāĻŋāĻ āĻŦāĻŋāĻā§āĻāĻžāĻĒāύ āĻĻā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
</patch>
|
||||
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
|
||||
<string name="revanced_music_play_permanent_repeat_title">āϏā§āĻĨāĻžāϝāĻŧā§ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋ āϏāĻā§āώāĻŽ āĻāϰā§āύ</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_on">āϏā§āĻĨāĻžāϝāĻŧā§ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋ āϏāĻā§āώāĻŽ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
<string name="revanced_music_play_permanent_repeat_summary_off">āϏā§āĻĨāĻžāϝāĻŧā§ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋ āĻ
āĻā§āώāĻŽ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§</string>
|
||||
</patch>
|
||||
<patch id="layout.compactheader.hideCategoryBar">
|
||||
<string name="revanced_music_hide_category_bar_title">āĻā§āϝāĻžāĻāĻžāĻāϰāĻŋ āĻŦāĻžāϰ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_on">āĻā§āϝāĻžāĻāĻžāĻāϰāĻŋ āĻŦāĻžāϰ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
<string name="revanced_music_hide_category_bar_summary_off">āĻā§āϝāĻžāĻāĻžāĻāϰāĻŋ āĻŦāĻžāϰ āĻĻā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
</patch>
|
||||
<patch id="layout.premium.hideGetPremiumPatch">
|
||||
<string name="revanced_music_hide_get_premium_label_title">\'āĻā§āĻ āĻŽāĻŋāĻāĻāĻŋāĻ āĻĒā§āϰāĻŋāĻŽāĻŋāϝāĻŧāĻžāĻŽ\' āϞā§āĻŦā§āϞ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_on">āϞā§āĻŦā§āϞ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
<string name="revanced_music_hide_get_premium_label_summary_off">āϞā§āĻŦā§āϞ āĻĻā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
</patch>
|
||||
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
|
||||
<string name="revanced_music_hide_upgrade_button_title">āĻāĻĒāĻā§āϰā§āĻĄ āĻŦāĻžāĻāύ āϞā§āĻāĻžāύ</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_on">āĻŦāĻžāĻāύ āϞā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
<string name="revanced_music_hide_upgrade_button_summary_off">āĻŦāĻžāĻāύ āĻĻā§āĻāĻžāύ⧠āĻāĻā§</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="twitch">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user