Compare commits
41 Commits
v5.43.0-de
...
v5.45.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfdbbfa047 | ||
|
|
e9f45ce926 | ||
|
|
1b38b1a3c8 | ||
|
|
13cf1724bf | ||
|
|
6d01863ec7 | ||
|
|
a32ed30b4c | ||
|
|
ef44eaa119 | ||
|
|
c73a03c9e1 | ||
|
|
c1681f982a | ||
|
|
1502bf7524 | ||
|
|
dffb1e6525 | ||
|
|
b8c2ede2bf | ||
|
|
591e106098 | ||
|
|
e7336d2ef3 | ||
|
|
7a53f8f62d | ||
|
|
3466d9d210 | ||
|
|
876d7a6b03 | ||
|
|
a2aa9cac27 | ||
|
|
08baa19b4a | ||
|
|
7283b93cea | ||
|
|
754b71959a | ||
|
|
c64e29ec57 | ||
|
|
b2dd008aee | ||
|
|
de97562c5d | ||
|
|
6373829fd6 | ||
|
|
cfd244b408 | ||
|
|
e8e28e2b6a | ||
|
|
2e4c6fdcad | ||
|
|
644d6dcb51 | ||
|
|
14dd7346a8 | ||
|
|
0af8c8a766 | ||
|
|
96454c843b | ||
|
|
476ef0fae1 | ||
|
|
bbec724afb | ||
|
|
7a1dcbd4ee | ||
|
|
2a1e31860f | ||
|
|
949d6bdd19 | ||
|
|
7563990750 | ||
|
|
4b605eb270 | ||
|
|
c2d7a7fb8b | ||
|
|
a55560dc25 |
134
CHANGELOG.md
@@ -1,3 +1,137 @@
|
||||
# [5.45.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.2...v5.45.0-dev.3) (2025-10-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Change Header:** Use SVG for header logo ([#6178](https://github.com/ReVanced/revanced-patches/issues/6178)) ([e9f45ce](https://github.com/ReVanced/revanced-patches/commit/e9f45ce92695d5857473ff71c14b190bded28a73))
|
||||
|
||||
# [5.45.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.1...v5.45.0-dev.2) (2025-10-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Force original audio:** Fall back to visionOS and not Android Studio if Android VR is not available ([6d01863](https://github.com/ReVanced/revanced-patches/commit/6d01863ec70617d9abc864ce6686ed9764dd151d))
|
||||
* **YouTube Music - Hide category bar:** Correctly hide the category bar in newer app targets ([#6175](https://github.com/ReVanced/revanced-patches/issues/6175)) ([13cf172](https://github.com/ReVanced/revanced-patches/commit/13cf1724bf2f946c7129cab0db96721c90f9fe89))
|
||||
|
||||
# [5.45.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.44.0...v5.45.0-dev.1) (2025-10-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram:** Update failing fingerprints on newer versions ([#6181](https://github.com/ReVanced/revanced-patches/issues/6181)) ([c73a03c](https://github.com/ReVanced/revanced-patches/commit/c73a03c9e18a12262939c974cdf16221221d1487))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **TikTok:** Add `Sanitize sharing links` patch ([#6176](https://github.com/ReVanced/revanced-patches/issues/6176)) ([ef44eaa](https://github.com/ReVanced/revanced-patches/commit/ef44eaa119b9d6c5faec051e22d20f883d0da4f1))
|
||||
|
||||
# [5.44.0](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.44.0) (2025-10-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
|
||||
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
|
||||
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
|
||||
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
|
||||
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
|
||||
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
|
||||
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
|
||||
|
||||
# [5.44.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.3...v5.44.0-dev.4) (2025-10-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
|
||||
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
|
||||
|
||||
# [5.44.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.2...v5.44.0-dev.3) (2025-10-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
|
||||
|
||||
# [5.44.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.1...v5.44.0-dev.2) (2025-10-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
|
||||
|
||||
# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
|
||||
|
||||
## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
|
||||
|
||||
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
|
||||
|
||||
## [5.43.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.43.2-dev.1) (2025-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
|
||||
|
||||
## [5.43.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1) (2025-10-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
|
||||
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
|
||||
|
||||
## [5.43.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.1-dev.1...v5.43.1-dev.2) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
|
||||
|
||||
## [5.43.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1-dev.1) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
|
||||
|
||||
# [5.43.0](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.43.0) (2025-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d))
|
||||
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](https://github.com/ReVanced/revanced-patches/commit/be2b144cc9c4108ec37e16f3dd20573d88ffaa2b))
|
||||
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](https://github.com/ReVanced/revanced-patches/commit/54846253d748f4e7e30b2bba427c7d2fb9c341e2))
|
||||
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](https://github.com/ReVanced/revanced-patches/commit/6555f6e6f8b52c2f1ddab1f52c6704cd2d8cfc12))
|
||||
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
|
||||
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b))
|
||||
|
||||
# [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14)
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@ public class HideCastButtonPatch {
|
||||
* Injection point
|
||||
*/
|
||||
public static void hideCastButton(View view) {
|
||||
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view);
|
||||
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON, view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package app.revanced.extension.music.patches;
|
||||
|
||||
import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition;
|
||||
|
||||
import android.view.View;
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -8,7 +11,7 @@ public class HideCategoryBarPatch {
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean hideCategoryBar() {
|
||||
return Settings.HIDE_CATEGORY_BAR.get();
|
||||
public static void hideCategoryBar(View view) {
|
||||
hideViewBy0dpUnderCondition(Settings.HIDE_CATEGORY_BAR, view);
|
||||
}
|
||||
}
|
||||
|
||||
4
extensions/samsung/radio/build.gradle.kts
Normal file
@@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:samsung:radio:stub"))
|
||||
}
|
||||
1
extensions/samsung/radio/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,24 @@
|
||||
package app.revanced.extension.samsung.radio.misc.fix.crash;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class FixCrashPatch {
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Add the required permissions to the request list to avoid crashes on API 34+.
|
||||
**/
|
||||
public static final String[] fixPermissionRequestList(String[] perms) {
|
||||
List<String> permsList = new ArrayList<>(Arrays.asList(perms));
|
||||
if (permsList.contains("android.permission.POST_NOTIFICATIONS")) {
|
||||
permsList.addAll(Arrays.asList("android.permission.RECORD_AUDIO", "android.permission.READ_PHONE_STATE", "android.permission.FOREGROUND_SERVICE_MICROPHONE"));
|
||||
}
|
||||
if (permsList.contains("android.permission.RECORD_AUDIO")) {
|
||||
permsList.add("android.permission.FOREGROUND_SERVICE_MICROPHONE");
|
||||
}
|
||||
return permsList.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package app.revanced.extension.samsung.radio.restrictions.device;
|
||||
|
||||
import android.os.SemSystemProperties;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class BypassDeviceChecksPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Check if the device has the required hardware
|
||||
**/
|
||||
public static final boolean checkIfDeviceIsIncompatible(String[] deviceList) {
|
||||
String currentDevice = SemSystemProperties.getSalesCode();
|
||||
return Arrays.asList(deviceList).contains(currentDevice);
|
||||
}
|
||||
}
|
||||
17
extensions/samsung/radio/stub/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,7 @@
|
||||
package android.os;
|
||||
|
||||
public class SemSystemProperties {
|
||||
public static String getSalesCode() {
|
||||
throw new UnsupportedOperationException("Stub");
|
||||
}
|
||||
}
|
||||
@@ -150,14 +150,14 @@ public class CustomBrandingPatch {
|
||||
}
|
||||
|
||||
for (ComponentName disable : componentsToDisable) {
|
||||
// Use info logging because if the alias status become corrupt the app cannot launch.
|
||||
Logger.printInfo(() -> "Disabling: " + disable.getClassName());
|
||||
pm.setComponentEnabledSetting(disable,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
|
||||
// Use info logging because if the alias status become corrupt the app cannot launch.
|
||||
ComponentName componentToEnableFinal = componentToEnable;
|
||||
Logger.printInfo(() -> "Enabling: " + componentToEnableFinal.getClassName());
|
||||
|
||||
pm.setComponentEnabledSetting(componentToEnable,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -17,9 +17,6 @@ public class LinkSanitizer {
|
||||
|
||||
public LinkSanitizer(String ... parametersToRemove) {
|
||||
final int parameterCount = parametersToRemove.length;
|
||||
if (parameterCount == 0) {
|
||||
throw new IllegalArgumentException("No parameters specified");
|
||||
}
|
||||
|
||||
// List is faster if only checking a few parameters.
|
||||
this.parametersToRemove = parameterCount > 4
|
||||
@@ -40,10 +37,12 @@ public class LinkSanitizer {
|
||||
try {
|
||||
Uri.Builder builder = uri.buildUpon().clearQuery();
|
||||
|
||||
for (String paramName : uri.getQueryParameterNames()) {
|
||||
if (!parametersToRemove.contains(paramName)) {
|
||||
for (String value : uri.getQueryParameters(paramName)) {
|
||||
builder.appendQueryParameter(paramName, value);
|
||||
if (!parametersToRemove.isEmpty()) {
|
||||
for (String paramName : uri.getQueryParameterNames()) {
|
||||
if (!parametersToRemove.contains(paramName)) {
|
||||
for (String value : uri.getQueryParameters(paramName)) {
|
||||
builder.appendQueryParameter(paramName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,12 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
||||
public void addPreferences(Context context) {
|
||||
addPreference(new ReVancedTikTokAboutPreference(context));
|
||||
|
||||
addPreference(new TogglePreference(context,
|
||||
"Sanitize sharing links",
|
||||
"Remove tracking parameters from shared links.",
|
||||
BaseSettings.SANITIZE_SHARED_LINKS
|
||||
));
|
||||
|
||||
addPreference(new TogglePreference(context,
|
||||
"Enable debug log",
|
||||
"Show extension debug log.",
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package app.revanced.extension.tiktok.share;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ShareUrlSanitizer {
|
||||
|
||||
private static final LinkSanitizer sanitizer = new LinkSanitizer();
|
||||
|
||||
/**
|
||||
* Injection point for setting check.
|
||||
*/
|
||||
public static boolean shouldSanitize() {
|
||||
return BaseSettings.SANITIZE_SHARED_LINKS.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point for URL sanitization.
|
||||
*/
|
||||
public static String sanitizeShareUrl(final String url) {
|
||||
if (url == null || url.isEmpty()) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return sanitizer.sanitizeUrlString(url);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package app.revanced.twitter.patches.links;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ChangeLinkSharingDomainPatch {
|
||||
private static final String LINK_FORMAT = "%s/%s/status/%s";
|
||||
private static final String LINK_FORMAT = "https://%s/%s/status/%s";
|
||||
|
||||
/**
|
||||
* Method is modified during patching. Do not change.
|
||||
@@ -11,6 +11,16 @@ public final class ChangeLinkSharingDomainPatch {
|
||||
return "";
|
||||
}
|
||||
|
||||
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String formatResourceLink(Object... formatArgs) {
|
||||
String username = (String) formatArgs[0];
|
||||
String tweetId = (String) formatArgs[1];
|
||||
return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
|
||||
@@ -17,15 +17,25 @@ public class ChangeHeaderPatch {
|
||||
DEFAULT(null, null),
|
||||
REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"),
|
||||
PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"),
|
||||
REVANCED("revanced_header_logo", "revanced_header_logo"),
|
||||
REVANCED_MINIMAL("revanced_header_logo_minimal", "revanced_header_logo_minimal"),
|
||||
CUSTOM("custom_header", "custom_header");
|
||||
ROUNDED("revanced_header_rounded"),
|
||||
MINIMAL("revanced_header_minimal"),
|
||||
CUSTOM("revanced_header_custom"),
|
||||
|
||||
// Old enum names for data migration. TODO: Eventually delete these.
|
||||
@Deprecated
|
||||
REVANCED(ROUNDED.attributeName),
|
||||
@Deprecated
|
||||
REVANCED_MINIMAL(MINIMAL.attributeName);
|
||||
|
||||
@Nullable
|
||||
private final String attributeName;
|
||||
@Nullable
|
||||
private final String drawableName;
|
||||
|
||||
HeaderLogo(String attributeName) {
|
||||
this(Objects.requireNonNull(attributeName), Objects.requireNonNull(attributeName));
|
||||
}
|
||||
|
||||
HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) {
|
||||
this.attributeName = attributeName;
|
||||
this.drawableName = drawableName;
|
||||
@@ -42,9 +52,8 @@ public class ChangeHeaderPatch {
|
||||
|
||||
final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
|
||||
if (identifier == 0) {
|
||||
// Identifier is zero if custom header setting was included in imported settings
|
||||
// and a custom image was not included during patching.
|
||||
Logger.printDebug(() -> "Could not find attribute: " + drawableName);
|
||||
// Should never happen.
|
||||
Logger.printException(() -> "Could not find attribute: " + drawableName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
@@ -63,12 +72,14 @@ public class ChangeHeaderPatch {
|
||||
: "_light");
|
||||
|
||||
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
|
||||
if (identifier == 0) {
|
||||
Logger.printDebug(() -> "Could not find drawable: " + drawableFullName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
if (identifier != 0) {
|
||||
return Utils.getContext().getDrawable(identifier);
|
||||
}
|
||||
return Utils.getContext().getDrawable(identifier);
|
||||
|
||||
// Should never happen.
|
||||
Logger.printException(() -> "Could not find drawable: " + drawableFullName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
"post_shelf_slim.e",
|
||||
"videos_post_responsive_root.e",
|
||||
"text_post_responsive_root.e",
|
||||
"poll_post_responsive_root.e"
|
||||
"poll_post_responsive_root.e",
|
||||
"shared_post_root.e"
|
||||
);
|
||||
|
||||
final var subscribersCommunityGuidelines = new StringFilterGroup(
|
||||
|
||||
@@ -38,9 +38,9 @@ public class SpoofVideoStreamsPatch {
|
||||
}
|
||||
|
||||
List<ClientType> availableClients = List.of(
|
||||
VISIONOS,
|
||||
ANDROID_CREATOR,
|
||||
ANDROID_VR_1_43_32,
|
||||
VISIONOS,
|
||||
IPADOS);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package app.revanced.extension.youtube.patches.theme;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.youtube.patches.HideSeekbarPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
/**
|
||||
* Used by {@link SeekbarColorPatch} change the color of the seekbar.
|
||||
* and {@link HideSeekbarPatch} to hide the seekbar of the feed and watch history.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ProgressBarDrawable extends Drawable {
|
||||
|
||||
private final Paint paint = new Paint();
|
||||
{
|
||||
paint.setColor(SeekbarColorPatch.getSeekbarColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.drawRect(getBounds(), paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
paint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
||||
paint.setColorFilter(colorFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +4,7 @@ import static app.revanced.extension.shared.StringRef.str;
|
||||
import static app.revanced.extension.shared.Utils.clamp;
|
||||
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
|
||||
@@ -15,7 +13,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Scanner;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
@@ -104,27 +101,6 @@ public final class SeekbarColorPatch {
|
||||
return customSeekbarColor;
|
||||
}
|
||||
|
||||
private static int colorChannelTo3Bits(int channel8Bits) {
|
||||
final float channel3Bits = channel8Bits * 7 / 255f;
|
||||
|
||||
// If a color channel is near zero, then allow rounding up so values between
|
||||
// 0x12 and 0x23 will show as 0x24. But always round down when the channel is
|
||||
// near full saturation, otherwise rounding to nearest will cause all values
|
||||
// between 0xEC and 0xFE to always show as full saturation (0xFF).
|
||||
return channel3Bits < 6
|
||||
? Math.round(channel3Bits)
|
||||
: (int) channel3Bits;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static String get9BitStyleIdentifier(int color24Bit) {
|
||||
final int r3 = colorChannelTo3Bits(Color.red(color24Bit));
|
||||
final int g3 = colorChannelTo3Bits(Color.green(color24Bit));
|
||||
final int b3 = colorChannelTo3Bits(Color.blue(color24Bit));
|
||||
|
||||
return String.format(Locale.US, "splash_seekbar_color_style_%d_%d_%d", r3, g3, b3);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point.
|
||||
*/
|
||||
@@ -135,36 +111,6 @@ public final class SeekbarColorPatch {
|
||||
return original; // false = drawable style, true = lottie style.
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Old drawable style launch screen.
|
||||
*/
|
||||
public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vectorDrawable) {
|
||||
// Alternatively a ColorMatrixColorFilter can be used to change the color of the drawable
|
||||
// without using any styles, but a color filter cannot selectively change the seekbar
|
||||
// while keeping the red YT logo untouched.
|
||||
// Even if the seekbar color xml value is changed to a completely different color (such as green),
|
||||
// a color filter still cannot be selectively applied when the drawable has more than 1 color.
|
||||
try {
|
||||
// Must set the color even if custom seekbar is off,
|
||||
// because the xml color was replaced with a themed value.
|
||||
String seekbarStyle = get9BitStyleIdentifier(customSeekbarColor);
|
||||
Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle);
|
||||
|
||||
final int styleIdentifierDefault = Utils.getResourceIdentifierOrThrow(
|
||||
seekbarStyle,
|
||||
"style"
|
||||
);
|
||||
|
||||
Resources.Theme theme = Utils.getContext().getResources().newTheme();
|
||||
theme.applyStyle(styleIdentifierDefault, true);
|
||||
|
||||
vectorDrawable.applyTheme(theme);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "setSplashAnimationDrawableTheme failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Modern Lottie style animation.
|
||||
|
||||
@@ -2,7 +2,6 @@ package app.revanced.extension.youtube.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.shared.settings.Setting.migrateOldSettingToNew;
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
import static app.revanced.extension.shared.settings.Setting.parentsAll;
|
||||
import static app.revanced.extension.shared.settings.Setting.parentsAny;
|
||||
@@ -17,7 +16,6 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerH
|
||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideSubtextsAvailability;
|
||||
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;
|
||||
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
|
||||
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
||||
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
|
||||
@@ -41,7 +39,6 @@ import app.revanced.extension.shared.settings.IntegerSetting;
|
||||
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;
|
||||
@@ -452,14 +449,7 @@ public class Settings extends BaseSettings {
|
||||
public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFFFF", false, false);
|
||||
|
||||
// Deprecated migrations
|
||||
private static final BooleanSetting DEPRECATED_AUTO_REPEAT = new BooleanSetting("revanced_auto_repeat", FALSE);
|
||||
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true);
|
||||
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE);
|
||||
private static final IntegerSetting DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127);
|
||||
private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033");
|
||||
private static final BooleanSetting DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE);
|
||||
private static final BooleanSetting DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
|
||||
private static final BooleanSetting DEPRECATED_AUTO_CAPTIONS = new BooleanSetting("revanced_auto_captions", FALSE);
|
||||
|
||||
private static final FloatSetting DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f, false, false);
|
||||
private static final FloatSetting DEPRECATED_SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f, false, false);
|
||||
@@ -475,17 +465,12 @@ public class Settings extends BaseSettings {
|
||||
static {
|
||||
// region Migration
|
||||
|
||||
migrateOldSettingToNew(DEPRECATED_AUTO_REPEAT, LOOP_VIDEO);
|
||||
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS);
|
||||
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER);
|
||||
migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO);
|
||||
migrateOldSettingToNew(DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU, ADVANCED_VIDEO_QUALITY_MENU);
|
||||
migrateOldSettingToNew(DEPRECATED_AUTO_CAPTIONS, DISABLE_AUTO_CAPTIONS);
|
||||
|
||||
// Migrate renamed enum.
|
||||
//noinspection deprecation
|
||||
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {
|
||||
MINIPLAYER_TYPE.save(MINIMAL);
|
||||
// Migrate renamed change header enums.
|
||||
if (HEADER_LOGO.get() == HeaderLogo.REVANCED) {
|
||||
HEADER_LOGO.save(HeaderLogo.ROUNDED);
|
||||
}
|
||||
if (HEADER_LOGO.get() == HeaderLogo.REVANCED_MINIMAL) {
|
||||
HEADER_LOGO.save(HeaderLogo.MINIMAL);
|
||||
}
|
||||
|
||||
// Migrate old single color seekbar with a slightly brighter accent color based on the primary.
|
||||
@@ -512,11 +497,6 @@ public class Settings extends BaseSettings {
|
||||
DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY.resetToDefault();
|
||||
}
|
||||
|
||||
if (!DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.isSetToDefault()) {
|
||||
SWIPE_OVERLAY_OPACITY.save(DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.get() / 255);
|
||||
DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.resetToDefault();
|
||||
}
|
||||
|
||||
// Old spoof versions that no longer work,
|
||||
// or is spoofing to a version the same or newer than this app.
|
||||
if (!SPOOF_APP_VERSION_TARGET.isSetToDefault() &&
|
||||
@@ -534,13 +514,7 @@ public class Settings extends BaseSettings {
|
||||
|
||||
// RYD requires manually migrating old settings since the lack of
|
||||
// a "revanced_" on the old setting causes duplicate key exceptions during export.
|
||||
SharedPrefCategory revancedPrefs = Setting.preferences;
|
||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_USER_ID, "ryd_user_id");
|
||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_ENABLED, "ryd_enabled");
|
||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_DISLIKE_PERCENTAGE, "ryd_dislike_percentage");
|
||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_COMPACT_LAYOUT, "ryd_compact_layout");
|
||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_ESTIMATED_LIKE, "ryd_estimated_like");
|
||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_TOAST_ON_CONNECTION_ERROR, "ryd_toast_on_connection_error");
|
||||
Setting.migrateFromOldPreferences(Setting.preferences, RYD_USER_ID, "ryd_user_id");
|
||||
|
||||
// Migrate old saved data. Must be done here before the settings can be used by any other code.
|
||||
applyOldSbOpacityToColor(SB_CATEGORY_SPONSOR_COLOR, DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY);
|
||||
|
||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
||||
org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
version = 5.43.0-dev.4
|
||||
version = 5.45.0-dev.3
|
||||
|
||||
@@ -60,6 +60,10 @@ public final class app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWi
|
||||
public static final fun getSpoofWifiPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/customcertificates/CustomCertificatesPatchKt {
|
||||
public static final fun getCustomNetworkSecurityPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatchKt {
|
||||
public static final fun getEnableAndroidDebuggingPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
}
|
||||
@@ -184,6 +188,10 @@ public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatchKt {
|
||||
public static final fun getEnableDebugMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatchKt {
|
||||
public static final fun getSkipEnergyRechargeAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatchKt {
|
||||
public static final fun getHideSponsoredStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -481,7 +489,9 @@ public final class app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatc
|
||||
|
||||
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
|
||||
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
public static final fun is_7_16_or_greater ()Z
|
||||
public static final fun is_7_33_or_greater ()Z
|
||||
public static final fun is_8_05_or_greater ()Z
|
||||
public static final fun is_8_10_or_greater ()Z
|
||||
public static final fun is_8_11_or_greater ()Z
|
||||
public static final fun is_8_15_or_greater ()Z
|
||||
@@ -762,6 +772,14 @@ public final class app/revanced/patches/reddit/misc/tracking/url/SanitizeUrlQuer
|
||||
public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatchKt {
|
||||
public static final fun getFixCrashPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatchKt {
|
||||
public static final fun getBypassDeviceChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt {
|
||||
public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -1170,6 +1188,10 @@ public final class app/revanced/patches/tiktok/misc/settings/SettingsPatchKt {
|
||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatchKt {
|
||||
public static final fun getSanitizeShareUrlsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt {
|
||||
public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package app.revanced.patches.all.misc.customcertificates
|
||||
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringsOption
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.util.getNode
|
||||
import org.w3c.dom.Element
|
||||
import java.io.File
|
||||
|
||||
|
||||
|
||||
|
||||
val customNetworkSecurityPatch = resourcePatch(
|
||||
name = "Custom network security",
|
||||
description = "Allows trusting custom certificate authorities for a specific domain.",
|
||||
use = false
|
||||
) {
|
||||
|
||||
val targetDomains by stringsOption(
|
||||
key = "targetDomains",
|
||||
title = "Target domains",
|
||||
description = "List of domains to which the custom trust configuration will be applied (one domain per entry).",
|
||||
default = listOf("example.com"),
|
||||
required = true
|
||||
)
|
||||
|
||||
val includeSubdomains by booleanOption(
|
||||
key = "includeSubdomains",
|
||||
title = "Include subdomains",
|
||||
description = "Applies the configuration to all subdomains of the target domains.",
|
||||
default = false,
|
||||
required = true
|
||||
)
|
||||
|
||||
val customCAFilePaths by stringsOption(
|
||||
key = "customCAFilePaths",
|
||||
title = "Custom CA file paths",
|
||||
description = """
|
||||
List of paths to files in PEM or DER format (one file path per entry).
|
||||
|
||||
Makes an app trust the provided custom certificate authorities (CAs),
|
||||
for the specified domains, and if the option "Include Subdomains" is enabled then also the subdomains.
|
||||
|
||||
|
||||
CA files will be bundled in res/raw/ of resulting APK
|
||||
""".trimIndentMultiline(),
|
||||
default = null,
|
||||
required = false
|
||||
)
|
||||
|
||||
val allowUserCerts by booleanOption(
|
||||
key = "allowUserCerts",
|
||||
title = "Trust user added CAs",
|
||||
description = "Makes an app trust certificates from the Android user store for the specified domains, and if the option \"Include Subdomains\" is enabled then also the subdomains.",
|
||||
|
||||
default = false,
|
||||
required = true
|
||||
)
|
||||
|
||||
val allowSystemCerts by booleanOption(
|
||||
key = "allowSystemCerts",
|
||||
title = "Trust system CAs",
|
||||
description = "Makes an app trust certificates from the Android system store for the specified domains, and and if the option \"Include Subdomains\" is enabled then also the subdomains.",
|
||||
|
||||
default = true,
|
||||
required = true
|
||||
)
|
||||
|
||||
val allowCleartextTraffic by booleanOption(
|
||||
key = "allowCleartextTraffic",
|
||||
title = "Allow cleartext traffic (HTTP)",
|
||||
description = "Allows unencrypted HTTP traffic for the specified domains, and if \"Include Subdomains\" is enabled then also the subdomains.",
|
||||
|
||||
default = false,
|
||||
required = true
|
||||
)
|
||||
|
||||
val overridePins by booleanOption(
|
||||
key = "overridePins",
|
||||
title = "Override certificate pinning",
|
||||
description = "Overrides certificate pinning for the specified domains and their subdomains if the option \"Include Subdomains\" is enabled to allow inspecting app traffic via a proxy.",
|
||||
|
||||
default = false,
|
||||
required = true
|
||||
)
|
||||
|
||||
fun generateNetworkSecurityConfig(): String {
|
||||
val targetDomains = targetDomains ?: emptyList()
|
||||
val includeSubdomains = includeSubdomains ?: false
|
||||
val customCAFilePaths = customCAFilePaths ?: emptyList()
|
||||
val allowUserCerts = allowUserCerts ?: false
|
||||
val allowSystemCerts = allowSystemCerts ?: true
|
||||
val allowCleartextTraffic = allowCleartextTraffic ?: false
|
||||
val overridePins = overridePins ?: false
|
||||
|
||||
val domainsXML = buildString {
|
||||
targetDomains.forEach {
|
||||
appendLine(""" <domain includeSubdomains="$includeSubdomains">$it</domain>""")
|
||||
}
|
||||
}.trimEnd()
|
||||
|
||||
val trustAnchorsXML = buildString {
|
||||
if (allowSystemCerts) {
|
||||
appendLine(""" <certificates src="system" overridePins="$overridePins" />""")
|
||||
}
|
||||
if (allowUserCerts) {
|
||||
appendLine(""" <certificates src="user" overridePins="$overridePins" />""")
|
||||
}
|
||||
customCAFilePaths.forEach { path ->
|
||||
val fileName = path.substringAfterLast('/').substringBeforeLast('.')
|
||||
appendLine(""" <certificates src="@raw/$fileName" overridePins="$overridePins" />""")
|
||||
}
|
||||
}
|
||||
|
||||
if (trustAnchorsXML.isBlank()) {
|
||||
throw PatchException("At least one trust anchor (System, User, or Custom CA) must be enabled.")
|
||||
}
|
||||
|
||||
return """
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="$allowCleartextTraffic">
|
||||
$domainsXML
|
||||
<trust-anchors>
|
||||
${trustAnchorsXML.trimEnd()}
|
||||
</trust-anchors>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
|
||||
execute {
|
||||
val nscFileNameBare = "network_security_config"
|
||||
val resXmlDir = "res/xml"
|
||||
val resRawDir = "res/raw"
|
||||
val nscFileNameWithSuffix = "$nscFileNameBare.xml"
|
||||
|
||||
|
||||
document("AndroidManifest.xml").use { document ->
|
||||
val applicationNode = document.getNode("application") as Element
|
||||
applicationNode.setAttribute("android:networkSecurityConfig", "@xml/$nscFileNameBare")
|
||||
}
|
||||
|
||||
|
||||
File(get(resXmlDir), nscFileNameWithSuffix).apply {
|
||||
writeText(generateNetworkSecurityConfig())
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (customCAFilePath in customCAFilePaths ?: emptyList()) {
|
||||
val file = File(customCAFilePath)
|
||||
if (!file.exists()) {
|
||||
throw PatchException(
|
||||
"The custom CA file path cannot be found: " +
|
||||
file.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
if (!file.isFile) {
|
||||
throw PatchException(
|
||||
"The custom CA file path must be a file: "
|
||||
+ file.absolutePath
|
||||
)
|
||||
}
|
||||
val caFileNameWithoutSuffix = customCAFilePath.substringAfterLast('/').substringBefore('.')
|
||||
val caFile = File(customCAFilePath)
|
||||
File(
|
||||
get(resRawDir),
|
||||
caFileNameWithoutSuffix
|
||||
).writeText(
|
||||
caFile.readText()
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,35 @@
|
||||
package app.revanced.patches.duolingo.debug
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import app.revanced.util.returnEarly
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
val enableDebugMenuPatch = bytecodePatch(
|
||||
name = "Enable debug menu",
|
||||
use = false,
|
||||
use = false
|
||||
) {
|
||||
compatibleWith("com.duolingo"("5.158.4"))
|
||||
compatibleWith("com.duolingo")
|
||||
|
||||
execute {
|
||||
initializeBuildConfigProviderFingerprint.method.apply {
|
||||
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex
|
||||
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
||||
// It seems all categories are allowed on release. Force this on anyway.
|
||||
debugCategoryAllowOnReleaseBuildsFingerprint.method.returnEarly(true)
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"const/4 v$register, 0x1",
|
||||
)
|
||||
// Change build config debug build flag.
|
||||
buildConfigProviderConstructorFingerprint.match(
|
||||
buildConfigProviderToStringFingerprint.classDef
|
||||
).let {
|
||||
val index = it.patternMatch!!.startIndex
|
||||
|
||||
it.method.apply {
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
addInstruction(
|
||||
index + 1,
|
||||
"const/4 v$register, 0x1"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,25 @@ import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
/**
|
||||
* The `BuildConfigProvider` class has two booleans:
|
||||
*
|
||||
* - `isChina`: (usually) compares "play" with "china"...except for builds in China
|
||||
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true`
|
||||
*/
|
||||
|
||||
internal val initializeBuildConfigProviderFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returns("V")
|
||||
opcodes(Opcode.IPUT_BOOLEAN)
|
||||
strings("debug", "release", "china")
|
||||
internal val debugCategoryAllowOnReleaseBuildsFingerprint = fingerprint {
|
||||
returns("Z")
|
||||
parameters()
|
||||
custom { method, classDef ->
|
||||
method.name == "getAllowOnReleaseBuilds" && classDef.type == "Lcom/duolingo/debug/DebugCategory;"
|
||||
}
|
||||
}
|
||||
|
||||
internal val buildConfigProviderConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
parameters()
|
||||
opcodes(Opcode.CONST_4)
|
||||
}
|
||||
|
||||
internal val buildConfigProviderToStringFingerprint = fingerprint {
|
||||
parameters()
|
||||
returns("Ljava/lang/String;")
|
||||
strings("BuildConfigProvider(") // Partial string match.
|
||||
custom { method, _ ->
|
||||
method.name == "toString"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package app.revanced.patches.duolingo.energy
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
/**
|
||||
* Matches the class found in [energyConfigToStringFingerprint].
|
||||
*/
|
||||
internal val initializeEnergyConfigFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
opcodes(Opcode.RETURN_VOID)
|
||||
}
|
||||
|
||||
// Class name currently is not obfuscated but it may be in the future.
|
||||
internal val energyConfigToStringFingerprint = fingerprint {
|
||||
parameters()
|
||||
returns("Ljava/lang/String;")
|
||||
strings("EnergyConfig(", "maxEnergy=") // Partial string matches.
|
||||
custom { method, _ -> method.name == "toString" }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.duolingo.energy
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.util.findFieldFromToString
|
||||
|
||||
@Suppress("unused")
|
||||
val skipEnergyRechargeAdsPatch = bytecodePatch(
|
||||
name = "Skip energy recharge ads",
|
||||
description = "Skips watching ads to recharge energy."
|
||||
) {
|
||||
compatibleWith("com.duolingo")
|
||||
|
||||
execute {
|
||||
initializeEnergyConfigFingerprint
|
||||
.match(energyConfigToStringFingerprint.classDef)
|
||||
.method.apply {
|
||||
val energyField = energyConfigToStringFingerprint.method
|
||||
.findFieldFromToString("energy=")
|
||||
val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"""
|
||||
const/16 v0, 99
|
||||
iput v0, p0, $energyField
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ val spoofFeaturesPatch = bytecodePatch(
|
||||
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
|
||||
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
|
||||
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
|
||||
"com.google.android.feature.PIXEL_2025_EXPERIENCE",
|
||||
),
|
||||
title = "Features to disable",
|
||||
description = "Google Pixel exclusive features to disable." +
|
||||
|
||||
@@ -3,9 +3,10 @@ package app.revanced.patches.instagram.hide.navigation
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val initializeNavigationButtonsListFingerprint = fingerprint {
|
||||
strings("Nav3")
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Lcom/instagram/common/session/UserSession;", "Z")
|
||||
returns("Ljava/util/List;")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ val enableDeveloperMenuPatch = bytecodePatch(
|
||||
with(clearNotificationReceiverFingerprint.method) {
|
||||
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) {
|
||||
val reference = getReference<MethodReference>()
|
||||
Opcode.INVOKE_STATIC == opcode &&
|
||||
opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
|
||||
reference?.parameterTypes?.size == 1 &&
|
||||
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
|
||||
reference.returnType == "Z"
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.literal
|
||||
|
||||
internal val constructCategoryBarFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
internal val chipCloudFingerprint = fingerprint {
|
||||
returns("V")
|
||||
parameters("Landroid/content/Context;", "L", "L", "L")
|
||||
opcodes(
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
)
|
||||
literal { chipCloud }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
@@ -8,10 +8,14 @@ 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.mapping.get
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.util.findFreeRegister
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
internal var chipCloud = -1L
|
||||
private set
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -33,28 +37,21 @@ val hideCategoryBar = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
chipCloud = resourceMappings["layout", "chip_cloud"]
|
||||
|
||||
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)
|
||||
chipCloudFingerprint.method.apply {
|
||||
val targetIndex = chipCloudFingerprint.patternMatch!!.endIndex
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
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
|
||||
"""
|
||||
addInstruction(
|
||||
targetIndex + 1,
|
||||
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar(Landroid/view/View;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ 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_16_or_greater
|
||||
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
|
||||
@@ -18,7 +19,7 @@ import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
|
||||
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
|
||||
fixMediaFetchHotConfig = { true },
|
||||
fixMediaFetchHotConfig = { is_7_16_or_greater },
|
||||
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
|
||||
|
||||
|
||||
@@ -3,14 +3,11 @@ package app.revanced.patches.music.misc.tracks
|
||||
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.music.playservice.is_8_10_or_greater
|
||||
import app.revanced.patches.music.playservice.is_8_05_or_greater
|
||||
import app.revanced.patches.music.playservice.versionCheckPatch
|
||||
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
|
||||
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
block = {
|
||||
@@ -27,8 +24,8 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
)
|
||||
)
|
||||
},
|
||||
fixUseLocalizedAudioTrackFlag = { is_8_10_or_greater },
|
||||
fixUseLocalizedAudioTrackFlag = { is_8_05_or_greater },
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
|
||||
subclassExtensionClassDescriptor = "Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;",
|
||||
preferenceScreen = PreferenceScreen.MISC,
|
||||
)
|
||||
|
||||
@@ -8,8 +8,12 @@ import kotlin.properties.Delegates
|
||||
|
||||
// Use notNull delegate so an exception is thrown if these fields are accessed before they are set.
|
||||
|
||||
var is_7_16_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_7_33_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_05_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_10_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_11_or_greater: Boolean by Delegates.notNull()
|
||||
@@ -26,8 +30,10 @@ val versionCheckPatch = resourcePatch(
|
||||
val playStoreServicesVersion = findPlayStoreServicesVersion()
|
||||
|
||||
// All bug fix releases always seem to use the same play store version as the minor version.
|
||||
is_7_16_or_greater = 243499000 <= playStoreServicesVersion
|
||||
is_7_33_or_greater = 245199000 <= playStoreServicesVersion
|
||||
is_8_10_or_greater = 244799000 <= playStoreServicesVersion
|
||||
is_8_05_or_greater = 250599000 <= playStoreServicesVersion
|
||||
is_8_10_or_greater = 251099000 <= playStoreServicesVersion
|
||||
is_8_11_or_greater = 251199000 <= playStoreServicesVersion
|
||||
is_8_15_or_greater = 251530000 <= playStoreServicesVersion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package app.revanced.patches.samsung.radio.misc.fix.crash
|
||||
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.util.asSequence
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Suppress("unused")
|
||||
internal val addManifestPermissionsPatch = resourcePatch {
|
||||
|
||||
val requiredPermissions = listOf(
|
||||
"android.permission.READ_PHONE_STATE",
|
||||
"android.permission.FOREGROUND_SERVICE_MICROPHONE",
|
||||
"android.permission.RECORD_AUDIO",
|
||||
)
|
||||
|
||||
execute {
|
||||
document("AndroidManifest.xml").use { document ->
|
||||
document.getElementsByTagName("manifest").item(0).let { manifestEl ->
|
||||
|
||||
// Check which permissions are missing
|
||||
val existingPermissionNames = document.getElementsByTagName("uses-permission").asSequence()
|
||||
.mapNotNull { (it as? Element)?.getAttribute("android:name") }.toSet()
|
||||
val missingPermissions = requiredPermissions.filterNot { it in existingPermissionNames }
|
||||
|
||||
// Then add them
|
||||
for (permission in missingPermissions) {
|
||||
val element = document.createElement("uses-permission")
|
||||
element.setAttribute("android:name", permission)
|
||||
manifestEl.appendChild(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package app.revanced.patches.samsung.radio.misc.fix.crash
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.fromMethodReference
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal val permissionRequestListFingerprint = fingerprint {
|
||||
strings(
|
||||
"android.permission.POST_NOTIFICATIONS",
|
||||
"android.permission.READ_MEDIA_AUDIO",
|
||||
"android.permission.RECORD_AUDIO"
|
||||
)
|
||||
custom { method, _ -> method.name == "<clinit>" }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package app.revanced.patches.samsung.radio.misc.fix.crash
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.samsung.radio.restrictions.device.bypassDeviceChecksPatch
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch;"
|
||||
|
||||
val fixCrashPatch = bytecodePatch(
|
||||
name = "Fix crashes", description = "Prevents the app from crashing because of missing system permissions."
|
||||
) {
|
||||
dependsOn(addManifestPermissionsPatch, bypassDeviceChecksPatch)
|
||||
extendWith("extensions/samsung/radio.rve")
|
||||
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
|
||||
|
||||
execute {
|
||||
permissionRequestListFingerprint.method.apply {
|
||||
findInstructionIndicesReversedOrThrow(Opcode.FILLED_NEW_ARRAY).forEach { filledNewArrayIndex ->
|
||||
val moveResultIndex = indexOfFirstInstruction(filledNewArrayIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
if (moveResultIndex < 0) return@forEach // No move-result-object found after the filled-new-array
|
||||
|
||||
// Get the register where the array is saved
|
||||
val arrayRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
|
||||
|
||||
// Invoke the method from the extension
|
||||
addInstructions(
|
||||
moveResultIndex + 1, """
|
||||
invoke-static { v$arrayRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->fixPermissionRequestList([Ljava/lang/String;)[Ljava/lang/String;
|
||||
move-result-object v$arrayRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package app.revanced.patches.samsung.radio.restrictions.device
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.util.findFreeRegister
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val bypassDeviceChecksPatch = bytecodePatch(
|
||||
name = "Bypass device checks",
|
||||
description = "Removes firmware and region blacklisting. " +
|
||||
"This patch will still not allow the app to run on devices that do not have the required hardware.",
|
||||
) {
|
||||
extendWith("extensions/samsung/radio.rve")
|
||||
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
|
||||
|
||||
execute {
|
||||
// Return false = The device is not blacklisted
|
||||
checkDeviceFingerprint.method.apply {
|
||||
// Find the first string that start with "SM-", that's the list of incompatible devices
|
||||
val firstStringIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.CONST_STRING &&
|
||||
getReference<StringReference>()?.string?.startsWith("SM-") == true
|
||||
}
|
||||
|
||||
// Find the following filled-new-array (or filled-new-array/range) instruction
|
||||
val filledNewArrayIndex = indexOfFirstInstructionOrThrow(firstStringIndex + 1) {
|
||||
opcode == Opcode.FILLED_NEW_ARRAY || opcode == Opcode.FILLED_NEW_ARRAY_RANGE
|
||||
}
|
||||
|
||||
// Find an available register for our use
|
||||
val resultRegister = findFreeRegister(filledNewArrayIndex + 1)
|
||||
|
||||
// Store the array there and invoke the method that we added to the class earlier
|
||||
addInstructions(
|
||||
filledNewArrayIndex + 1, """
|
||||
move-result-object v$resultRegister
|
||||
invoke-static { v$resultRegister }, $EXTENSION_CLASS_DESCRIPTOR->checkIfDeviceIsIncompatible([Ljava/lang/String;)Z
|
||||
move-result v$resultRegister
|
||||
return v$resultRegister
|
||||
"""
|
||||
)
|
||||
|
||||
// Remove the instructions before our strings
|
||||
removeInstructions(0, firstStringIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package app.revanced.patches.samsung.radio.restrictions.device
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.fromMethodReference
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal val checkDeviceFingerprint = fingerprint {
|
||||
returns("Z")
|
||||
custom { method, _ ->
|
||||
/* Check for methods call to:
|
||||
- Landroid/os/SemSystemProperties;->getSalesCode()Ljava/lang/String;
|
||||
- Landroid/os/SemSystemProperties;->getCountryIso()Ljava/lang/String;
|
||||
*/
|
||||
|
||||
val impl = method.implementation ?: return@custom false
|
||||
|
||||
// Track which target methods we've found
|
||||
val foundMethods = mutableSetOf<MethodCall>()
|
||||
|
||||
// Scan method instructions for calls to our target methods
|
||||
for (instr in impl.instructions) {
|
||||
val ref = instr.getReference<MethodReference>() ?: continue
|
||||
val mc = fromMethodReference<MethodCall>(ref) ?: continue
|
||||
|
||||
if (mc == MethodCall.GetSalesCode || mc == MethodCall.GetCountryIso) {
|
||||
foundMethods.add(mc)
|
||||
|
||||
// If we found both methods, return success
|
||||
if (foundMethods.size == 2) {
|
||||
return@custom true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only match if both methods are present
|
||||
return@custom false
|
||||
}
|
||||
}
|
||||
|
||||
// Information about method calls we want to replace
|
||||
private enum class MethodCall(
|
||||
override val definedClassName: String,
|
||||
override val methodName: String,
|
||||
override val methodParams: Array<String>,
|
||||
override val returnType: String,
|
||||
) : IMethodCall {
|
||||
GetSalesCode(
|
||||
"Landroid/os/SemSystemProperties;",
|
||||
"getSalesCode",
|
||||
arrayOf(),
|
||||
"Ljava/lang/String;",
|
||||
),
|
||||
GetCountryIso(
|
||||
"Landroid/os/SemSystemProperties;",
|
||||
"getCountryIso",
|
||||
arrayOf(),
|
||||
"Ljava/lang/String;",
|
||||
),
|
||||
}
|
||||
@@ -36,13 +36,13 @@ import org.w3c.dom.NodeList
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
|
||||
private val mipmapDirectories = arrayOf(
|
||||
private val mipmapDirectories = mapOf(
|
||||
// Target app does not have ldpi icons.
|
||||
"mipmap-mdpi",
|
||||
"mipmap-hdpi",
|
||||
"mipmap-xhdpi",
|
||||
"mipmap-xxhdpi",
|
||||
"mipmap-xxxhdpi"
|
||||
"mipmap-mdpi" to "108x108 px",
|
||||
"mipmap-hdpi" to "162x162 px",
|
||||
"mipmap-xhdpi" to "216x216 px",
|
||||
"mipmap-xxhdpi" to "324x324 px",
|
||||
"mipmap-xxxhdpi" to "432x432 px"
|
||||
)
|
||||
|
||||
private val iconStyleNames = arrayOf(
|
||||
@@ -104,10 +104,13 @@ internal fun baseCustomBrandingPatch(
|
||||
Folder with images to use as a custom icon.
|
||||
|
||||
The folder must contain one or more of the following folders, depending on the DPI of the device:
|
||||
${mipmapDirectories.joinToString("\n") { "- $it" }}
|
||||
${mipmapDirectories.keys.joinToString("\n") { "- $it" }}
|
||||
|
||||
Each of the folders must contain all of the following files:
|
||||
${USER_CUSTOM_ADAPTIVE_FILE_NAMES.joinToString("\n")}
|
||||
|
||||
The image dimensions must be as follows:
|
||||
${mipmapDirectories.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
|
||||
|
||||
Optionally, the path contains a 'drawable' folder with any of the monochrome icon files:
|
||||
$USER_CUSTOM_MONOCHROME_FILE_NAME
|
||||
@@ -249,7 +252,7 @@ internal fun baseCustomBrandingPatch(
|
||||
)
|
||||
|
||||
// Copy template icon files.
|
||||
mipmapDirectories.forEach { dpi ->
|
||||
mipmapDirectories.keys.forEach { dpi ->
|
||||
copyResources(
|
||||
"custom-branding",
|
||||
ResourceGroup(
|
||||
@@ -405,23 +408,24 @@ internal fun baseCustomBrandingPatch(
|
||||
)
|
||||
}
|
||||
|
||||
val sourceFolders = iconPathFile.listFiles { file -> file.isDirectory }
|
||||
?: throw PatchException("The custom icon path contains no subfolders: " +
|
||||
iconPathFile.absolutePath)
|
||||
|
||||
val resourceDirectory = get("res")
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
sourceFolders.forEach { dpiSourceFolder ->
|
||||
iconPathFile.listFiles {
|
||||
file -> file.isDirectory && file.name in mipmapDirectories
|
||||
}!!.forEach { dpiSourceFolder ->
|
||||
val targetDpiFolder = resourceDirectory.resolve(dpiSourceFolder.name)
|
||||
if (!targetDpiFolder.exists()) return@forEach
|
||||
if (!targetDpiFolder.exists()) {
|
||||
// Should never happen.
|
||||
throw IllegalStateException("Resource not found: $dpiSourceFolder")
|
||||
}
|
||||
|
||||
val customFiles = dpiSourceFolder.listFiles { file ->
|
||||
file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES
|
||||
}!!
|
||||
|
||||
if (customFiles.size > 0 && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
|
||||
if (customFiles.isNotEmpty() && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
|
||||
throw PatchException("Must include all required icon files " +
|
||||
"but only found " + customFiles.map { it.name })
|
||||
}
|
||||
@@ -451,8 +455,9 @@ internal fun baseCustomBrandingPatch(
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("Could not find any replacement images in " +
|
||||
"patch option path: " + iconPathFile.absolutePath)
|
||||
throw PatchException("Expected to find directories and files: "
|
||||
+ USER_CUSTOM_ADAPTIVE_FILE_NAMES.contentToString()
|
||||
+ "\nBut none were found in the provided option file path: " + iconPathFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package app.revanced.patches.shared.misc.audio
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.containsLiteralInstruction
|
||||
import app.revanced.util.literal
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val formatStreamModelToStringFingerprint = fingerprint {
|
||||
@@ -20,10 +20,7 @@ internal val formatStreamModelToStringFingerprint = fingerprint {
|
||||
internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L
|
||||
|
||||
internal val selectAudioStreamFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returns("L")
|
||||
custom { method, _ ->
|
||||
method.parameters.size > 2 // Method has a large number of parameters and may change.
|
||||
&& method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG)
|
||||
literal {
|
||||
AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
internal fun forceOriginalAudioPatch(
|
||||
block: BytecodePatchBuilder.() -> Unit = {},
|
||||
executeBlock: BytecodePatchContext.() -> Unit = {},
|
||||
fixUseLocalizedAudioTrackFlag: () -> Boolean,
|
||||
fixUseLocalizedAudioTrackFlag: BytecodePatchContext.() -> Boolean,
|
||||
mainActivityOnCreateFingerprint: Fingerprint,
|
||||
subclassExtensionClassDescriptor: String,
|
||||
preferenceScreen: BasePreferenceScreen.Screen
|
||||
|
||||
@@ -47,11 +47,15 @@ val changeLyricsProviderPatch = bytecodePatch(
|
||||
// may not allow network connections or the network may be down.
|
||||
try {
|
||||
InetAddress.getByName(host)
|
||||
} catch (e: UnknownHostException) {
|
||||
} catch (_: UnknownHostException) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Host \"$host\" did not resolve to any domain."
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
// Must ignore any kind of exception. Trying to resolve network
|
||||
// on Manager throws android.os.NetworkOnMainThreadException
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package app.revanced.patches.tiktok.misc.share
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val urlShorteningFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL)
|
||||
returns("LX/")
|
||||
parameters(
|
||||
"I",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;"
|
||||
)
|
||||
opcodes(Opcode.RETURN_OBJECT)
|
||||
|
||||
// Same Kotlin intrinsics literal on both variants.
|
||||
strings("getShortShareUrlObservab\u2026ongUrl, subBizSceneValue)")
|
||||
|
||||
custom { method, _ ->
|
||||
// LIZLLL is obfuscated by ProGuard/R8, but stable across both TikTok and Musically.
|
||||
method.name == "LIZLLL"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package app.revanced.patches.tiktok.misc.share
|
||||
|
||||
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.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
|
||||
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
|
||||
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.findFreeRegister
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/tiktok/share/ShareUrlSanitizer;"
|
||||
|
||||
@Suppress("unused")
|
||||
val sanitizeShareUrlsPatch = bytecodePatch(
|
||||
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||
) {
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
compatibleWith(
|
||||
"com.ss.android.ugc.trill"("36.5.4"),
|
||||
"com.zhiliaoapp.musically"("36.5.4"),
|
||||
)
|
||||
|
||||
execute {
|
||||
urlShorteningFingerprint.method.apply {
|
||||
val invokeIndex = indexOfFirstInstructionOrThrow {
|
||||
val ref = getReference<MethodReference>()
|
||||
ref?.name == "LIZ" && ref.definingClass.startsWith("LX/")
|
||||
}
|
||||
|
||||
val moveResultIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val urlRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
|
||||
|
||||
// Resolve Observable wrapper classes at runtime
|
||||
val observableWrapperIndex = indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE)
|
||||
val observableWrapperClass = getInstruction<ReferenceInstruction>(observableWrapperIndex)
|
||||
.reference.toString()
|
||||
|
||||
val observableFactoryIndex = indexOfFirstInstructionOrThrow {
|
||||
val ref = getReference<MethodReference>()
|
||||
ref?.name == "LJ" && ref.definingClass.startsWith("LX/")
|
||||
}
|
||||
val observableFactoryRef = getInstruction<ReferenceInstruction>(observableFactoryIndex)
|
||||
.reference as MethodReference
|
||||
|
||||
val observableFactoryClass = observableFactoryRef.definingClass
|
||||
val observableInterfaceType = observableFactoryRef.parameterTypes.first()
|
||||
val observableReturnType = observableFactoryRef.returnType
|
||||
|
||||
val wrapperRegister = findFreeRegister(moveResultIndex + 1, urlRegister)
|
||||
|
||||
// Check setting and conditionally sanitize share URL.
|
||||
addInstructionsWithLabels(
|
||||
moveResultIndex + 1,
|
||||
"""
|
||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldSanitize()Z
|
||||
move-result v$wrapperRegister
|
||||
if-eqz v$wrapperRegister, :skip_sanitization
|
||||
|
||||
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$urlRegister
|
||||
|
||||
# Wrap sanitized URL and return early to bypass ShareExtService
|
||||
new-instance v$wrapperRegister, $observableWrapperClass
|
||||
invoke-direct { v$wrapperRegister, v$urlRegister }, $observableWrapperClass-><init>(Ljava/lang/String;)V
|
||||
invoke-static { v$wrapperRegister }, $observableFactoryClass->LJ($observableInterfaceType)$observableReturnType
|
||||
move-result-object v$urlRegister
|
||||
return-object v$urlRegister
|
||||
|
||||
:skip_sanitization
|
||||
nop
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,26 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
|
||||
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
|
||||
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.returnEarly
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.util.logging.Logger
|
||||
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;"
|
||||
|
||||
internal val domainNameOption by stringOption(
|
||||
internal val domainNameOption = stringOption(
|
||||
key = "domainName",
|
||||
default = "https://fxtwitter.com",
|
||||
default = "fxtwitter.com",
|
||||
title = "Domain name",
|
||||
description = "The domain name to use when sharing links.",
|
||||
required = true,
|
||||
@@ -28,23 +31,25 @@ internal val domainNameOption by stringOption(
|
||||
// may not allow network connections or the network may be down.
|
||||
try {
|
||||
InetAddress.getByName(it)
|
||||
} catch (e: UnknownHostException) {
|
||||
} catch (_: UnknownHostException) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Host \"$it\" did not resolve to any domain."
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
// Must ignore any kind of exception. Trying to resolve network
|
||||
// on Manager throws android.os.NetworkOnMainThreadException
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// TODO restore this once Manager uses a fixed version of Patcher
|
||||
/*
|
||||
internal val changeLinkSharingDomainResourcePatch = resourcePatch {
|
||||
execute {
|
||||
val domainName = domainNameOption!!
|
||||
val domainName = domainNameOption.value!!
|
||||
|
||||
val shareLinkTemplate = if (domainName.endsWith("/")) {
|
||||
"$domainName%1\$s/status/%2\$s"
|
||||
} else {
|
||||
"$domainName/%1\$s/status/%2\$s"
|
||||
}
|
||||
val shareLinkTemplate = "https://$domainName/%1\$s/status/%2\$s"
|
||||
|
||||
document("res/values/strings.xml").use { document ->
|
||||
document.documentElement.childNodes.findElementByAttributeValueOrThrow(
|
||||
@@ -54,14 +59,15 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@Suppress("unused")
|
||||
val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
|
||||
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
|
||||
description = "$PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN Including this patch can prevent making posts that quote other posts.",
|
||||
use = false
|
||||
) {
|
||||
dependsOn(
|
||||
changeLinkSharingDomainResourcePatch,
|
||||
sharedExtensionPatch,
|
||||
)
|
||||
|
||||
@@ -72,11 +78,11 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
val domainName = domainNameOption!!
|
||||
val domainName by domainNameOption()
|
||||
|
||||
execute {
|
||||
// Replace the domain name in the link sharing extension methods.
|
||||
linkSharingDomainHelperFingerprint.method.returnEarly(domainName)
|
||||
linkSharingDomainHelperFingerprint.method.returnEarly(domainName!!)
|
||||
|
||||
// Replace the domain name when copying a link with "Copy link" button.
|
||||
linkBuilderFingerprint.method.addInstructions(
|
||||
@@ -87,5 +93,22 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
return-object p0
|
||||
"""
|
||||
)
|
||||
|
||||
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
|
||||
// Replace the domain name in the "Share via..." dialog.
|
||||
linkResourceGetterFingerprint.method.apply {
|
||||
val templateIdConstIndex = indexOfFirstInstructionOrThrow(Opcode.CONST)
|
||||
|
||||
// Format the link with the new domain name register (1 instruction below the const).
|
||||
val formatLinkCallIndex = templateIdConstIndex + 1
|
||||
val register = getInstruction<FiveRegisterInstruction>(formatLinkCallIndex).registerE
|
||||
|
||||
// Replace the original method call with the new method call.
|
||||
replaceInstruction(
|
||||
formatLinkCallIndex,
|
||||
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val openLinkFingerprint = fingerprint {
|
||||
returns("V")
|
||||
@@ -17,6 +18,18 @@ internal val linkBuilderFingerprint = fingerprint {
|
||||
strings("/%1\$s/status/%2\$d")
|
||||
}
|
||||
|
||||
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
|
||||
// Returns a shareable link for the "Share via..." dialog.
|
||||
internal val linkResourceGetterFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Landroid/content/res/Resources;")
|
||||
custom { _, classDef ->
|
||||
classDef.fields.any { field ->
|
||||
field.type.startsWith("Lcom/twitter/model/core/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal val linkSharingDomainHelperFingerprint = fingerprint {
|
||||
custom { method, classDef ->
|
||||
method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
|
||||
|
||||
@@ -24,15 +24,40 @@ import java.io.File
|
||||
|
||||
private val variants = arrayOf("light", "dark")
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;"
|
||||
private val targetResourceDirectoryNames = mapOf(
|
||||
"drawable-hdpi" to "194x72 px",
|
||||
"drawable-xhdpi" to "258x96 px",
|
||||
"drawable-xxhdpi" to "387x144 px",
|
||||
"drawable-xxxhdpi" to "512x192 px"
|
||||
)
|
||||
|
||||
/**
|
||||
* Header logos built into this patch.
|
||||
*/
|
||||
private val logoResourceNames = arrayOf(
|
||||
"revanced_header_minimal",
|
||||
"revanced_header_rounded",
|
||||
)
|
||||
|
||||
/**
|
||||
* Custom header resource/file name.
|
||||
*/
|
||||
private const val CUSTOM_HEADER_RESOURCE_NAME = "revanced_header_custom"
|
||||
|
||||
/**
|
||||
* Custom header resource/file names.
|
||||
*/
|
||||
private val customHeaderResourceFileNames = variants.map { variant ->
|
||||
"${CUSTOM_HEADER_RESOURCE_NAME}_$variant.png"
|
||||
}.toTypedArray()
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;"
|
||||
|
||||
private val changeHeaderBytecodePatch = bytecodePatch {
|
||||
dependsOn(resourceMappingPatch)
|
||||
|
||||
execute {
|
||||
// Resources are not used during patching, but extension code uses these
|
||||
// images so verify they exist.
|
||||
// Verify images exist. Resources are not used during patching but extension code does.
|
||||
arrayOf(
|
||||
"yt_ringo2_wordmark_header",
|
||||
"yt_ringo2_premium_wordmark_header"
|
||||
@@ -62,28 +87,6 @@ private val changeHeaderBytecodePatch = bytecodePatch {
|
||||
}
|
||||
}
|
||||
|
||||
private val targetResourceDirectoryNames = mapOf(
|
||||
"xxxhdpi" to "512px x 192px",
|
||||
"xxhdpi" to "387px x 144px",
|
||||
"xhdpi" to "258px x 96px",
|
||||
"hdpi" to "194px x 72px",
|
||||
"mdpi" to "129px x 48px"
|
||||
).mapKeys { (dpi, _) -> "drawable-$dpi" }
|
||||
|
||||
|
||||
/**
|
||||
* Header logos built into this patch.
|
||||
*/
|
||||
private val logoResourceNames = arrayOf(
|
||||
"revanced_header_logo_minimal",
|
||||
"revanced_header_logo",
|
||||
)
|
||||
|
||||
/**
|
||||
* Custom header resource/file name.
|
||||
*/
|
||||
private const val CUSTOM_HEADER_RESOURCE_NAME = "custom_header"
|
||||
|
||||
@Suppress("unused")
|
||||
val changeHeaderPatch = resourcePatch(
|
||||
name = "Change header",
|
||||
@@ -110,7 +113,7 @@ val changeHeaderPatch = resourcePatch(
|
||||
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
|
||||
|
||||
Each of the folders must contain all of the following files:
|
||||
${variants.joinToString("\n") { variant -> "- ${CUSTOM_HEADER_RESOURCE_NAME}_$variant.png" }}
|
||||
${customHeaderResourceFileNames.joinToString("\n")}
|
||||
|
||||
The image dimensions must be as follows:
|
||||
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
|
||||
@@ -120,67 +123,41 @@ val changeHeaderPatch = resourcePatch(
|
||||
execute {
|
||||
addResources("youtube", "layout.branding.changeHeaderPatch")
|
||||
|
||||
fun getLightDarkFileNames(vararg resourceNames: String): Array<String> =
|
||||
variants.flatMap { variant ->
|
||||
resourceNames.map { resource -> "${resource}_$variant.png" }
|
||||
}.toTypedArray()
|
||||
|
||||
val logoResourceFileNames = getLightDarkFileNames(*logoResourceNames)
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup("drawable-hdpi", *logoResourceFileNames),
|
||||
ResourceGroup("drawable-mdpi", *logoResourceFileNames),
|
||||
ResourceGroup("drawable-xhdpi", *logoResourceFileNames),
|
||||
ResourceGroup("drawable-xxhdpi", *logoResourceFileNames),
|
||||
ResourceGroup("drawable-xxxhdpi", *logoResourceFileNames),
|
||||
)
|
||||
|
||||
if (custom != null) {
|
||||
val customFile = File(custom!!)
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException("The custom icon path cannot be found: " +
|
||||
customFile.absolutePath
|
||||
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
if (custom == null) {
|
||||
ListPreference("revanced_header_logo")
|
||||
} else {
|
||||
ListPreference(
|
||||
key = "revanced_header_logo",
|
||||
entriesKey = "revanced_header_logo_custom_entries",
|
||||
entryValuesKey = "revanced_header_logo_custom_entry_values"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException("The custom icon path must be a folder: "
|
||||
+ customFile.absolutePath)
|
||||
logoResourceNames.forEach { logo ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
"drawable",
|
||||
logo + "_" + variant + ".xml"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val sourceFolders = customFile.listFiles { file -> file.isDirectory }
|
||||
?: throw PatchException("The custom icon path contains no subfolders: " +
|
||||
customFile.absolutePath)
|
||||
|
||||
val customResourceFileNames = getLightDarkFileNames(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
sourceFolders.forEach { dpiSourceFolder ->
|
||||
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name)
|
||||
if (!targetDpiFolder.exists()) return@forEach
|
||||
|
||||
val customFiles = dpiSourceFolder.listFiles { file ->
|
||||
file.isFile && file.name in customResourceFileNames
|
||||
}!!
|
||||
|
||||
if (customFiles.size > 0 && customFiles.size != variants.size) {
|
||||
throw PatchException("Both light/dark mode images " +
|
||||
"must be specified but only found: " + customFiles.map { it.name })
|
||||
}
|
||||
|
||||
customFiles.forEach { imgSourceFile ->
|
||||
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
|
||||
imgSourceFile.copyTo(imgTargetFile)
|
||||
|
||||
copiedFiles = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("No custom header images found in " +
|
||||
"the provided path: " + customFile.absolutePath)
|
||||
// Copy custom template. Images are only used if settings
|
||||
// are imported and a custom header is enabled.
|
||||
targetResourceDirectoryNames.keys.forEach { dpi ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
dpi,
|
||||
*customHeaderResourceFileNames
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,9 +176,7 @@ val changeHeaderPatch = resourcePatch(
|
||||
addAttributeReference(logoName)
|
||||
}
|
||||
|
||||
if (custom != null) {
|
||||
addAttributeReference(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
}
|
||||
addAttributeReference(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
}
|
||||
|
||||
// Add custom drawables to all styles that use the regular and premium logo.
|
||||
@@ -227,22 +202,58 @@ val changeHeaderPatch = resourcePatch(
|
||||
addDrawableElement(document, logoName, mode)
|
||||
}
|
||||
|
||||
if (custom != null) {
|
||||
addDrawableElement(document, CUSTOM_HEADER_RESOURCE_NAME, mode)
|
||||
}
|
||||
addDrawableElement(document, CUSTOM_HEADER_RESOURCE_NAME, mode)
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
if (custom == null) {
|
||||
ListPreference("revanced_header_logo")
|
||||
} else {
|
||||
ListPreference(
|
||||
key = "revanced_header_logo",
|
||||
entriesKey = "revanced_header_logo_custom_entries",
|
||||
entryValuesKey = "revanced_header_logo_custom_entry_values"
|
||||
// Copy user provided images last, so if an exception is thrown due to bad input.
|
||||
if (custom != null) {
|
||||
val customFile = File(custom!!.trim())
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException("The custom header path cannot be found: " +
|
||||
customFile.absolutePath
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException("The custom header path must be a folder: "
|
||||
+ customFile.absolutePath)
|
||||
}
|
||||
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
customFile.listFiles {
|
||||
file -> file.isDirectory && file.name in targetResourceDirectoryNames
|
||||
}!!.forEach { dpiSourceFolder ->
|
||||
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name)
|
||||
if (!targetDpiFolder.exists()) {
|
||||
// Should never happen.
|
||||
throw IllegalStateException("Resource not found: $dpiSourceFolder")
|
||||
}
|
||||
|
||||
val customFiles = dpiSourceFolder.listFiles { file ->
|
||||
file.isFile && file.name in customHeaderResourceFileNames
|
||||
}!!
|
||||
|
||||
if (customFiles.isNotEmpty() && customFiles.size != variants.size) {
|
||||
throw PatchException("Both light/dark mode images " +
|
||||
"must be specified but only found: " + customFiles.map { it.name })
|
||||
}
|
||||
|
||||
customFiles.forEach { imgSourceFile ->
|
||||
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
|
||||
imgSourceFile.copyTo(target = imgTargetFile, overwrite = true)
|
||||
|
||||
copiedFiles = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("Expected to find directories and files: "
|
||||
+ customHeaderResourceFileNames.contentToString()
|
||||
+ "\nBut none were found in the provided option file path: " + customFile.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package app.revanced.patches.youtube.layout.seekbar
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
@@ -17,17 +15,13 @@ import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
import app.revanced.util.copyXmlNode
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.inputStreamFromBundledResource
|
||||
import app.revanced.util.insertLiteralOverride
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@@ -38,9 +32,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import org.w3c.dom.Element
|
||||
import java.io.ByteArrayInputStream
|
||||
import kotlin.use
|
||||
|
||||
internal var reelTimeBarPlayedColorId = -1L
|
||||
private set
|
||||
@@ -57,8 +48,6 @@ internal var ytTextSecondaryId = -1L
|
||||
internal var inlineTimeBarLiveSeekableRangeId = -1L
|
||||
private set
|
||||
|
||||
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
|
||||
|
||||
private val seekbarColorResourcePatch = resourcePatch {
|
||||
dependsOn(
|
||||
settingsPatch,
|
||||
@@ -92,21 +81,6 @@ private val seekbarColorResourcePatch = resourcePatch {
|
||||
"inline_time_bar_live_seekable_range"
|
||||
]
|
||||
|
||||
// Modify the resume playback drawable and replace the progress bar with a custom drawable.
|
||||
document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
|
||||
val layerList = document.getElementsByTagName("layer-list").item(0) as Element
|
||||
val progressNode = layerList.getElementsByTagName("item").item(1) as Element
|
||||
if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {
|
||||
throw PatchException("Could not find progress bar")
|
||||
}
|
||||
val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element
|
||||
val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element
|
||||
val replacementNode = document.createElement(
|
||||
"app.revanced.extension.youtube.patches.theme.ProgressBarDrawable",
|
||||
)
|
||||
scaleNode.replaceChild(replacementNode, shapeNode)
|
||||
}
|
||||
|
||||
ytYoutubeMagentaColorId = resourceMappings[
|
||||
"color",
|
||||
"yt_youtube_magenta",
|
||||
@@ -115,99 +89,9 @@ private val seekbarColorResourcePatch = resourcePatch {
|
||||
"attr",
|
||||
"ytStaticBrandRed",
|
||||
]
|
||||
|
||||
// Add attribute and styles for splash screen custom color.
|
||||
// Using a style is the only way to selectively change just the seekbar fill color.
|
||||
//
|
||||
// Because the style colors must be hard coded for all color possibilities,
|
||||
// instead of allowing 24 bit color the style is restricted to 9-bit (3 bits per color channel)
|
||||
// and the style color closest to the users custom color is used for the splash screen.
|
||||
arrayOf(
|
||||
inputStreamFromBundledResource("seekbar/values", "attrs.xml")!! to "res/values/attrs.xml",
|
||||
ByteArrayInputStream(create9BitSeekbarColorStyles().toByteArray()) to "res/values/styles.xml"
|
||||
).forEach { (source, destination) ->
|
||||
"resources".copyXmlNode(
|
||||
document(source),
|
||||
document(destination),
|
||||
).close()
|
||||
}
|
||||
|
||||
fun setSplashDrawablePathFillColor(xmlFileNames: Iterable<String>, vararg resourceNames: String) {
|
||||
xmlFileNames.forEach { xmlFileName ->
|
||||
document(xmlFileName).use { document ->
|
||||
val childNodes = document.childNodes
|
||||
|
||||
resourceNames.forEach { elementId ->
|
||||
val element = childNodes.findElementByAttributeValueOrThrow(
|
||||
"android:name",
|
||||
elementId
|
||||
)
|
||||
|
||||
val attribute = "android:fillColor"
|
||||
if (!element.hasAttribute(attribute)) {
|
||||
throw PatchException("Could not find $attribute for $elementId")
|
||||
}
|
||||
|
||||
element.setAttribute(attribute, "?attr/$splashSeekbarColorAttributeName")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSplashDrawablePathFillColor(
|
||||
listOf(
|
||||
"res/drawable/\$startup_animation_light__0.xml",
|
||||
"res/drawable/\$startup_animation_dark__0.xml"
|
||||
),
|
||||
"_R_G_L_10_G_D_0_P_0"
|
||||
)
|
||||
|
||||
if (!is_19_46_or_greater) {
|
||||
// Resources removed in 19.46+
|
||||
setSplashDrawablePathFillColor(
|
||||
listOf(
|
||||
"res/drawable/\$buenos_aires_animation_light__0.xml",
|
||||
"res/drawable/\$buenos_aires_animation_dark__0.xml"
|
||||
),
|
||||
"_R_G_L_8_G_D_0_P_0"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a style xml with all combinations of 9-bit colors.
|
||||
*/
|
||||
private fun create9BitSeekbarColorStyles(): String = StringBuilder().apply {
|
||||
append("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
|
||||
append("<resources>\n")
|
||||
|
||||
for (red in 0..7) {
|
||||
for (green in 0..7) {
|
||||
for (blue in 0..7) {
|
||||
val name = "${red}_${green}_${blue}"
|
||||
|
||||
fun roundTo3BitHex(channel8Bits: Int) =
|
||||
(channel8Bits * 255 / 7).toString(16).padStart(2, '0')
|
||||
val r = roundTo3BitHex(red)
|
||||
val g = roundTo3BitHex(green)
|
||||
val b = roundTo3BitHex(blue)
|
||||
val color = "#ff$r$g$b"
|
||||
|
||||
append(
|
||||
"""
|
||||
<style name="splash_seekbar_color_style_$name">
|
||||
<item name="$splashSeekbarColorAttributeName">$color</item>
|
||||
</style>
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
append("</resources>")
|
||||
}.toString()
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;"
|
||||
|
||||
val seekbarColorPatch = bytecodePatch(
|
||||
@@ -344,21 +228,6 @@ val seekbarColorPatch = bytecodePatch(
|
||||
|
||||
// Hook the splash animation to set the a seekbar color.
|
||||
mainActivityOnCreateFingerprint.method.apply {
|
||||
val drawableIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == "Landroid/widget/ImageView;"
|
||||
&& reference.name == "getDrawable"
|
||||
}
|
||||
val checkCastIndex = indexOfFirstInstructionOrThrow(drawableIndex, Opcode.CHECK_CAST)
|
||||
val drawableRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
checkCastIndex + 1,
|
||||
"invoke-static { v$drawableRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"setSplashAnimationDrawableTheme(Landroid/graphics/drawable/AnimatedVectorDrawable;)V"
|
||||
)
|
||||
|
||||
// Replace the Lottie animation view setAnimation(int) call.
|
||||
val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name
|
||||
|
||||
findInstructionIndicesReversedOrThrow {
|
||||
@@ -371,13 +240,11 @@ val seekbarColorPatch = bytecodePatch(
|
||||
replaceInstruction(
|
||||
index,
|
||||
"invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" +
|
||||
"(Lcom/airbnb/lottie/LottieAnimationView;I)V"
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie(Lcom/airbnb/lottie/LottieAnimationView;I)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add non obfuscated method aliases for `setAnimation(int)`
|
||||
// and `setAnimation(InputStream, String)` so extension code can call them.
|
||||
lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply {
|
||||
|
||||
@@ -8,9 +8,6 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
block = {
|
||||
@@ -31,6 +28,6 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
},
|
||||
fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater },
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
|
||||
subclassExtensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;",
|
||||
preferenceScreen = PreferenceScreen.VIDEO,
|
||||
)
|
||||
|
||||
@@ -218,9 +218,9 @@ Hər halda, bunu aktivləşdirmə IP ünvanınız kimi bəzi istifadəçi məlum
|
||||
<string name="revanced_hide_community_posts_title">İcma elanların gizlət</string>
|
||||
<string name="revanced_hide_community_posts_summary_on">İcma elanları gizlədilib</string>
|
||||
<string name="revanced_hide_community_posts_summary_off">İcma elanları göstərilir</string>
|
||||
<string name="revanced_hide_compact_banner_title">Yığcam etiketləri gizlət</string>
|
||||
<string name="revanced_hide_compact_banner_summary_on">Yığcam etiketlər gizlidir</string>
|
||||
<string name="revanced_hide_compact_banner_summary_off">Yığcam etiketlər göstərilir</string>
|
||||
<string name="revanced_hide_compact_banner_title">Yığcam afişaları gizlət</string>
|
||||
<string name="revanced_hide_compact_banner_summary_on">Yığcam afişalar gizlidir</string>
|
||||
<string name="revanced_hide_compact_banner_summary_off">Yığcam afişalar görünür</string>
|
||||
<string name="revanced_hide_crowdfunding_box_title">İanə qutusunu gizlət</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_on">İanə qutusu gizlidir</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_off">İanə qutusu göstərilir</string>
|
||||
@@ -471,9 +471,9 @@ Məhdudiyyətlər
|
||||
<string name="revanced_hide_creator_store_shelf_title">Yaradıcı mağaza bölümün gizlət</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">Yaradıcı alış-veriş cərgəsi video oynadıcı altında gizlidir</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">Yaradıcı alış-veriş cərgəsi video oynadıcı altında görünür</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza etiketini gizlət</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran alış-veriş etiketi gizlədilib</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran alış-veriş etiketi görünür</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza afişasın gizlət</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran mağaza afişası gizlidir</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran mağaza afişası görünür</string>
|
||||
<string name="revanced_hide_fullscreen_ads_title">Tam ekran reklamlarını gizlət</string>
|
||||
<string name="revanced_hide_fullscreen_ads_summary_on">"Tam ekran reklamları gizlidir
|
||||
|
||||
@@ -484,9 +484,9 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
|
||||
<string name="revanced_hide_general_ads_title">Ümumi reklamları gizlət</string>
|
||||
<string name="revanced_hide_general_ads_summary_on">Ümumi reklamlar gizlidir</string>
|
||||
<string name="revanced_hide_general_ads_summary_off">Ümumi reklamlar göstərilir</string>
|
||||
<string name="revanced_hide_merchandise_banners_title">Məhsul etiketlərini gizlət</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul etiketləri gizlədilir</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul etiketləri göstərilir</string>
|
||||
<string name="revanced_hide_merchandise_banners_title">Məhsul afişaların gizlət</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul afişaları gizlədilir</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul afişaları görünür</string>
|
||||
<string name="revanced_hide_paid_promotion_label_title">Ödənişli tanıtım etiketini gizlət</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_on">Ödənişli reklam etiketi gizlədilib</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_off">Ödənişli reklam etiketi göstərilir</string>
|
||||
@@ -496,7 +496,7 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
|
||||
<string name="revanced_hide_shopping_links_title">Alış-veriş linklərini gizlət</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">Alış-veriş linkləri video təsvirdə gizlidir</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">Alış-veriş linkləri video təsvirdə görünür</string>
|
||||
<string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” panelin gizlət</string>
|
||||
<string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” afişasın gizlət</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_on">Məhsullara baxış etiketi video örtüyündə gizlidir</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_off">Məhsullara baxış etiketi video örtüyündə görünür</string>
|
||||
<string name="revanced_hide_web_search_results_title">Veb axtarış nəticələrini gizlət</string>
|
||||
|
||||
@@ -1158,13 +1158,13 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
|
||||
<string name="revanced_sb_segments_highlight_sum">Se osa videota, jota useimmat ihmiset etsivät</string>
|
||||
<string name="revanced_sb_segments_intro">Tauko/Introanimaatio</string>
|
||||
<string name="revanced_sb_segments_intro_sum">Aikaväli ilman varsinaista sisältöä. Voi olla tauko, staattinen kehys tai toistuva animaatio. Ei sisällä siirtymiä, jotka sisältävät tietoa</string>
|
||||
<string name="revanced_sb_segments_outro">Loppukortit / Tekijätiedot</string>
|
||||
<string name="revanced_sb_segments_outro">Loppukortit / -tekstit</string>
|
||||
<string name="revanced_sb_segments_outro_sum">Lopputekstit tai kun YouTuben loppukortit tulevat näkyviin. Ei lopetuksille, joissa on tietoa</string>
|
||||
<string name="revanced_sb_segments_hook">Koukku / Tervehdykset</string>
|
||||
<string name="revanced_sb_segments_hook_sum">Kertovat trailerit tulevasta videosta, tervehdykset ja hyvästelyt. Ei sisällä osioita, jotka lisäävät lisäsisältöä</string>
|
||||
<string name="revanced_sb_segments_preview">Esikatselu / Yhteenveto</string>
|
||||
<string name="revanced_sb_segments_preview">Esikatselu / Kertaus</string>
|
||||
<string name="revanced_sb_segments_preview_sum">Kokoelma leikkeitä, jotka osoittavat, mitä on tulossa tai mitä tapahtui videossa tai muissa sarjan videoissa, joiden kaikki informaatio toistuu muualla</string>
|
||||
<string name="revanced_sb_segments_filler">Tangentti / Vitsit</string>
|
||||
<string name="revanced_sb_segments_filler">Toissijaiset kohtaukset / Vitsit</string>
|
||||
<string name="revanced_sb_segments_filler_sum">Epäolennaiset kohtaukset tai vitsit, joita ei tarvita videon pääsisällön ymmärtämiseen. Ei sisällä osioita, jotka tarjoavat kontekstia tai taustatietoja</string>
|
||||
<string name="revanced_sb_segments_nomusic">Musiikki: Musiikiton osa</string>
|
||||
<string name="revanced_sb_segments_nomusic_sum">Vain musiikkivideoille. Musiikkivideoiden osiot ilman musiikkia, jotka eivät jo kuulu toiseen kategoriaan</string>
|
||||
@@ -1182,7 +1182,7 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
|
||||
<string name="revanced_sb_skip_button_preview_beginning">Ohita esikatselu</string>
|
||||
<string name="revanced_sb_skip_button_preview_middle">Ohita esikatselu</string>
|
||||
<string name="revanced_sb_skip_button_preview_end">Ohita kertaus</string>
|
||||
<string name="revanced_sb_skip_button_filler">Ohita Tangentti</string>
|
||||
<string name="revanced_sb_skip_button_filler">Ohita toissijainen kohtaus</string>
|
||||
<string name="revanced_sb_skip_button_nomusic">Ohita musiikiton</string>
|
||||
<string name="revanced_sb_skip_button_unsubmitted">Ohita osio</string>
|
||||
<string name="revanced_sb_skipped_sponsor">Sponsori ohitettiin</string>
|
||||
@@ -1193,11 +1193,11 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
|
||||
<string name="revanced_sb_skipped_intro_middle">Tauko ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_intro_end">Tauko ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_outro">Outro ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_hook">Ohitettu koukku</string>
|
||||
<string name="revanced_sb_skipped_hook">Koukku ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_preview_beginning">Esikatselu ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_preview_middle">Esikatselu ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_preview_end">Kertaus ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_filler">Ohitettu tangentti</string>
|
||||
<string name="revanced_sb_skipped_filler">Toissijainen kohtaus ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_nomusic">Musiikiton osio ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_unsubmitted">Lähettämätön osio ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_multiple_segments">Useita osioita ohitettiin</string>
|
||||
@@ -1254,7 +1254,7 @@ Oletko valmis lähettämään?"</string>
|
||||
<string name="revanced_sb_new_segment_edit_by_hand_parse_error">Annettu aika on virheellinen</string>
|
||||
<string name="revanced_sb_stats_title">Tilastot</string>
|
||||
<!-- Shown in the settings preferences, and translations can be any text length. -->
|
||||
<string name="revanced_sb_stats_connection_failure">Tilastot eivät tilapäisesti saatavilla (API ei ole käytettävissä)</string>
|
||||
<string name="revanced_sb_stats_connection_failure">Tilastot eivät ole tilapäisesti saatavilla (API ei ole käytettävissä)</string>
|
||||
<string name="revanced_sb_stats_loading">Ladataan...</string>
|
||||
<string name="revanced_sb_stats_sb_disabled">SponsorBlock ei ole käytössä</string>
|
||||
<string name="revanced_sb_stats_username">Käyttäjänimesi: <b>%s</b></string>
|
||||
@@ -1265,11 +1265,11 @@ Oletko valmis lähettämään?"</string>
|
||||
<string name="revanced_sb_stats_submissions">Olet luonut <b>%s</b> osiota</string>
|
||||
<string name="revanced_sb_stats_submissions_sum">Napauta tästä nähdäksesi osiosi</string>
|
||||
<string name="revanced_sb_stats_saved_zero">SponsorBlock-tulostaulu</string>
|
||||
<string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä <b>%s</b> segmentiltä</string>
|
||||
<string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä <b>%s</b> osiolta</string>
|
||||
<string name="revanced_sb_stats_saved_sum_zero">Napauta tästä nähdäksesi globaalit tilastot ja parhaat osallistujat</string>
|
||||
<string name="revanced_sb_stats_saved_sum">Se on <b>%s</b> heidän elämistään.<br>Napauta tästä nähdäksesi tulostaulun</string>
|
||||
<string name="revanced_sb_stats_self_saved">Olet ohittanut <b>%s</b> osiota</string>
|
||||
<string name="revanced_sb_stats_self_saved_sum">Tuo on <b>%s</b></string>
|
||||
<string name="revanced_sb_stats_self_saved_sum">Se on <b>%s</b></string>
|
||||
<string name="revanced_sb_stats_self_saved_reset_title">Nollataanko ohitettujen osioiden laskuri?</string>
|
||||
<string name="revanced_sb_stats_saved_hour_format">%1$s tuntia %2$s minuuttia</string>
|
||||
<string name="revanced_sb_stats_saved_minute_format">%1$s minuuttia %2$s sekuntia</string>
|
||||
|
||||
@@ -26,12 +26,12 @@ Second \"item\" text"</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Personnalisé</string>
|
||||
<string name="revanced_custom_branding_icon_title">Icône de l\'application</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Original</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Originale</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimaliste</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced mis à l\'échelle</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced mise à l\'échelle</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Personnalisé</string>
|
||||
<string name="revanced_custom_branding_icon_entry_5">Personnalisée</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Les vérifications ont échoué</string>
|
||||
@@ -1363,7 +1363,7 @@ Limitation : Il se peut que le bouton Retour dans la barre d'outils ne fonction
|
||||
</patch>
|
||||
<patch id="layout.miniplayer.miniplayerPatch">
|
||||
<string name="revanced_miniplayer_screen_title">Lecteur réduit</string>
|
||||
<string name="revanced_miniplayer_screen_summary">Modifier le style du lecteur réduit à l\'intérieur de l\'application</string>
|
||||
<string name="revanced_miniplayer_screen_summary">Modifiez le style du lecteur réduit intégré à l\'application</string>
|
||||
<string name="revanced_miniplayer_type_title">Type de lecteur réduit</string>
|
||||
<string name="revanced_miniplayer_type_entry_0">Désactivé</string>
|
||||
<string name="revanced_miniplayer_type_entry_1">Par défaut</string>
|
||||
@@ -1623,11 +1623,11 @@ Limitations :
|
||||
<string name="revanced_spoof_video_streams_av1_title">Autoriser Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Le codec vidéo est AVC (H.264), VP9 ou AV1
|
||||
|
||||
La lecture peut saccader ou perdre des images"</string>
|
||||
La lecture peut être saccadée et des images peuvent être perdues"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Le codec vidéo est AVC (H.264) ou VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"L'activation de ce paramètre peut utiliser le décodage AV1 logiciel.
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"L'activation de ce paramètre permet l'utilisation du décodage AV1 logiciel.
|
||||
|
||||
La lecture vidéo avec AV1 peut saccader ou perdre des images."</string>
|
||||
La lecture vidéo avec AV1 peut être saccadée et des images peuvent être perdues."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Effets secondaires de la falsification</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Client expérimental, peut cesser de fonctionner à tout moment</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Les vidéos sont susceptibles de s\'arrêter à 1:00, ou de ne pas être disponibles dans certaines régions</string>
|
||||
|
||||
@@ -28,8 +28,8 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_custom_branding_icon_title">アプリアイコン</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">オリジナル</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced (シンプル)</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced (ロゴ拡大)</string>
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced(シンプル)</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced(ロゴ拡大)</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">カスタム</string>
|
||||
</patch>
|
||||
@@ -304,8 +304,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_hide_medical_panels_summary_on">医療情報パネルは表示されません</string>
|
||||
<string name="revanced_hide_medical_panels_summary_off">医療情報パネルは表示されます</string>
|
||||
<string name="revanced_hide_quick_actions_title">クイック アクションを非表示</string>
|
||||
<string name="revanced_hide_quick_actions_summary_on">全画面表示のクイック アクションは表示されません</string>
|
||||
<string name="revanced_hide_quick_actions_summary_off">全画面表示のクイック アクションは表示されます</string>
|
||||
<string name="revanced_hide_quick_actions_summary_on">全画面表示モードのクイック アクションは表示されません</string>
|
||||
<string name="revanced_hide_quick_actions_summary_off">全画面表示モードのクイック アクションは表示されます</string>
|
||||
<string name="revanced_hide_related_videos_title">関連動画を非表示</string>
|
||||
<string name="revanced_hide_related_videos_summary_on">クイック アクション内の関連動画は表示されません</string>
|
||||
<string name="revanced_hide_related_videos_summary_off">クイック アクション内の関連動画は表示されます</string>
|
||||
@@ -342,8 +342,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_hide_transcript_section_title">文字起こしセクションを非表示</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">文字起こしセクションは表示されません</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">文字起こしセクションは表示されます</string>
|
||||
<string name="revanced_hide_description_components_screen_title">動画の概要欄</string>
|
||||
<string name="revanced_hide_description_components_screen_summary">動画の概要欄のコンポーネントを表示または非表示にします</string>
|
||||
<string name="revanced_hide_description_components_screen_title">概要欄</string>
|
||||
<string name="revanced_hide_description_components_screen_summary">概要欄のコンポーネントを表示または非表示にします</string>
|
||||
<string name="revanced_hide_filter_bar_screen_title">フィルタバー</string>
|
||||
<string name="revanced_hide_filter_bar_screen_summary">フィード、関連動画、検索結果、および再生履歴でフィルタバーを表示または非表示にします</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_title">フィードで非表示</string>
|
||||
@@ -496,8 +496,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_on">自己スポンサー カードは表示されません</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_off">自己スポンサー カードは表示されます</string>
|
||||
<string name="revanced_hide_shopping_links_title">商品へのリンクを非表示</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">動画の概要欄にある商品へのリンクは表示されません</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">動画の概要欄にある商品へのリンクは表示されます</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">動画の概要欄の商品へのリンクは表示されません</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">動画の概要欄の商品へのリンクは表示されます</string>
|
||||
<string name="revanced_hide_view_products_banner_title">「商品を表示」バナーを非表示</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_on">動画オーバーレイの「商品を表示」バナーは表示されません</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_off">動画オーバーレイの「商品を表示」バナーは表示されます</string>
|
||||
@@ -614,12 +614,12 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_swipe_volume_sensitivity_summary">スワイプによる音量の変化量</string>
|
||||
<string name="revanced_swipe_overlay_style_title">オーバーレイのスタイル</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_1">横型</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_2">横型 (シンプル - 画面上部)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_3">横型 (シンプル - 画面中央)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_2">横型(シンプル - 画面上部)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_3">横型(シンプル - 画面中央)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_4">円形</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_5">円形 (シンプル)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_5">円形(シンプル)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_6">縦型</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_7">縦型 (シンプル)</string>
|
||||
<string name="revanced_swipe_overlay_style_entry_7">縦型(シンプル)</string>
|
||||
<string name="revanced_swipe_change_video_title">スワイプによる動画の切り替えを有効化</string>
|
||||
<string name="revanced_swipe_change_video_summary_on">全画面表示中に左 / 右にスワイプすると、前 / 次の動画に切り替わります</string>
|
||||
<string name="revanced_swipe_change_video_summary_off">全画面表示中に左 / 右にスワイプしても、前 / 次の動画に切り替わりません</string>
|
||||
@@ -967,13 +967,13 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_end_screen_suggested_video_summary_on">"終了画面の「関連動画」は表示されませんが、自動再生がオンの場合は関連動画が自動で再生されます
|
||||
|
||||
自動再生の設定は YouTube の設定で変更できます:
|
||||
[設定] → [再生] → [次の動画を自動再生]"</string>
|
||||
[設定] > [再生] > [次の動画を自動再生]"</string>
|
||||
<string name="revanced_end_screen_suggested_video_summary_off">終了画面の「関連動画」は表示されます</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch">
|
||||
<string name="revanced_hide_related_videos_overlay_title">関連動画オーバーレイを非表示</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">全画面表示の関連動画オーバーレイは表示されません</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">全画面表示の関連動画オーバーレイは表示されます</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">全画面表示モードの関連動画オーバーレイは表示されません</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">全画面表示モードの関連動画オーバーレイは表示されます</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.time.hideTimestampPatch">
|
||||
<string name="revanced_hide_timestamp_title">動画のタイムスタンプを非表示</string>
|
||||
@@ -1159,9 +1159,9 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_sb_segments_interaction_sum">動画内に挿入される視聴者への高評価、チャンネル登録、フォローなどの時間的に短い催促。時間的に長い催促またはイベントなどの個別具体的なものに関する催促は、「視聴者への催促」ではなく「自己宣伝」に分類すべきです</string>
|
||||
<string name="revanced_sb_segments_highlight">ハイライト</string>
|
||||
<string name="revanced_sb_segments_highlight_sum">動画の中で最も重要な場面</string>
|
||||
<string name="revanced_sb_segments_intro">幕間 / オープニング</string>
|
||||
<string name="revanced_sb_segments_intro">幕間 / オープニング (OP)</string>
|
||||
<string name="revanced_sb_segments_intro_sum">実際のコンテンツを含まない区間。一時停止、静止画、繰り返しアニメーションなど。情報を含むトランジッション (場面転換) は、このカテゴリーではありません</string>
|
||||
<string name="revanced_sb_segments_outro">終了画面 / クレジット</string>
|
||||
<string name="revanced_sb_segments_outro">終了画面 / クレジット (ED)</string>
|
||||
<string name="revanced_sb_segments_outro_sum">クレジット、または YouTube の終了画面が表示される場面。情報を含む結論、まとめ部分は、このカテゴリーには含まれません</string>
|
||||
<string name="revanced_sb_segments_hook">フック / あいさつ</string>
|
||||
<string name="revanced_sb_segments_hook_sum">今後の動画のナレーション付きの予告編、および開幕と別れのあいさつ。重複しない内容や情報を追加する場面は含まれません</string>
|
||||
@@ -1177,10 +1177,10 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_sb_skip_button_selfpromo">自己宣伝をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_interaction">催促をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_highlight">ハイライトまでスキップ</string>
|
||||
<string name="revanced_sb_skip_button_intro_beginning">オープニングをスキップ</string>
|
||||
<string name="revanced_sb_skip_button_intro_beginning">OP をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_intro_middle">幕間をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_intro_end">幕間をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_outro">エンディングをスキップ</string>
|
||||
<string name="revanced_sb_skip_button_outro">ED をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_hook">フックをスキップ</string>
|
||||
<string name="revanced_sb_skip_button_preview_beginning">予告編をスキップ</string>
|
||||
<string name="revanced_sb_skip_button_preview_middle">予告編をスキップ</string>
|
||||
@@ -1192,10 +1192,10 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が
|
||||
<string name="revanced_sb_skipped_selfpromo">自己宣伝をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_interaction">催促をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_highlight">ハイライトまでスキップしました</string>
|
||||
<string name="revanced_sb_skipped_intro_beginning">オープニングをスキップしました</string>
|
||||
<string name="revanced_sb_skipped_intro_beginning">OP をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_intro_middle">幕間をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_intro_end">幕間をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_outro">エンディングをスキップしました</string>
|
||||
<string name="revanced_sb_skipped_outro">ED をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_hook">フックをスキップしました</string>
|
||||
<string name="revanced_sb_skipped_preview_beginning">予告編をスキップしました</string>
|
||||
<string name="revanced_sb_skipped_preview_middle">予告編をスキップしました</string>
|
||||
@@ -1309,7 +1309,7 @@ Automotive レイアウト
|
||||
<string name="revanced_spoof_app_version_target_title">アプリバージョンの偽装先</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_1">20.13.41 - アクション ボタンの文字表示を復元</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_2">20.05.46 - 文字起こし機能を復元</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_3">19.35.36 - 古いショート プレーヤーのアイコンを復元</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_3">19.35.36 - ショート プレーヤーの古いアイコンを復元</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_4">19.01.34 - 古いナビゲーション アイコンを復元</string>
|
||||
</patch>
|
||||
<patch id="layout.startpage.changeStartPagePatch">
|
||||
@@ -1359,7 +1359,7 @@ Automotive レイアウト
|
||||
<string name="revanced_shorts_autoplay_title">ショート動画の自動再生</string>
|
||||
<string name="revanced_shorts_autoplay_summary_on">ショート動画は自動再生されます</string>
|
||||
<string name="revanced_shorts_autoplay_summary_off">ショート動画はループ再生されます</string>
|
||||
<string name="revanced_shorts_autoplay_background_title">ショート動画の自動再生(バックグラウンド)</string>
|
||||
<string name="revanced_shorts_autoplay_background_title">ショート動画の自動再生 (バックグラウンド)</string>
|
||||
<string name="revanced_shorts_autoplay_background_summary_on">バックグラウンドのショート動画は自動再生されます</string>
|
||||
<string name="revanced_shorts_autoplay_background_summary_off">バックグラウンドのショート動画はループ再生されます</string>
|
||||
</patch>
|
||||
@@ -1433,7 +1433,7 @@ Automotive レイアウト
|
||||
<string name="revanced_header_logo_entry_1">デフォルト</string>
|
||||
<string name="revanced_header_logo_entry_2">標準</string>
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced (シンプル)</string>
|
||||
<string name="revanced_header_logo_entry_5">ReVanced(シンプル)</string>
|
||||
<string name="revanced_header_logo_entry_6">カスタム</string>
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
@@ -1546,13 +1546,13 @@ Automotive レイアウト
|
||||
<string name="revanced_remember_video_quality_last_selected_toast_title">画質の変更時にトーストを表示</string>
|
||||
<string name="revanced_remember_video_quality_last_selected_toast_summary_on">デフォルトの画質が変更された場合にトースト通知が表示されます</string>
|
||||
<string name="revanced_remember_video_quality_last_selected_toast_summary_off">デフォルトの画質が変更された場合にトースト通知は表示されません</string>
|
||||
<string name="revanced_video_quality_default_wifi_title">デフォルトの画質(Wi-Fi)</string>
|
||||
<string name="revanced_video_quality_default_mobile_title">デフォルトの画質(携帯回線)</string>
|
||||
<string name="revanced_video_quality_default_wifi_title">デフォルトの画質 (Wi-Fi)</string>
|
||||
<string name="revanced_video_quality_default_mobile_title">デフォルトの画質 (携帯回線)</string>
|
||||
<string name="revanced_remember_shorts_quality_last_selected_title">ショートの画質の変更を保存</string>
|
||||
<string name="revanced_remember_shorts_quality_last_selected_summary_on">画質の変更はすべてのショート動画に適用されます</string>
|
||||
<string name="revanced_remember_shorts_quality_last_selected_summary_off">画質の変更は現在のショート動画にのみ適用されます</string>
|
||||
<string name="revanced_shorts_quality_default_wifi_title">デフォルトのショートの画質(Wi-Fi)</string>
|
||||
<string name="revanced_shorts_quality_default_mobile_title">デフォルトのショートの画質(携帯回線)</string>
|
||||
<string name="revanced_shorts_quality_default_wifi_title">デフォルトのショートの画質 (Wi-Fi)</string>
|
||||
<string name="revanced_shorts_quality_default_mobile_title">デフォルトのショートの画質 (携帯回線)</string>
|
||||
<string name="revanced_remember_video_quality_mobile">携帯回線</string>
|
||||
<string name="revanced_remember_video_quality_wifi">Wi-Fi</string>
|
||||
<string name="revanced_remember_video_quality_toast">デフォルトの画質の変更 (%1$s): %2$s</string>
|
||||
|
||||
@@ -885,8 +885,8 @@ YouTube Premium 사용자라면 이 설정은 필요하지 않을 수 있습니
|
||||
<string name="revanced_hide_shorts_new_posts_button_summary_on">새로운 게시물 버튼이 숨겨집니다</string>
|
||||
<string name="revanced_hide_shorts_new_posts_button_summary_off">새로운 게시물 버튼이 표시됩니다</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_title">일시 정지 오버레이 버튼 숨기기</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_on">일시 정지 오버레이 버튼이 숨겨집니다</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_off">일시 정지 오버레이 버튼이 표시됩니다</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_on">플레이어 왼쪽 상단에서 다음 버튼들이 숨겨집니다\n• 구독 & 라이브 & 렌즈 & 트렌드 & 쇼핑</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_off">플레이어 왼쪽 상단에서 다음 버튼들이 표시됩니다\n• 구독 & 라이브 & 렌즈 & 트렌드 & 쇼핑</string>
|
||||
<string name="revanced_hide_shorts_preview_comment_title">댓글 미리보기 숨기기</string>
|
||||
<string name="revanced_hide_shorts_preview_comment_summary_on">댓글 미리보기가 숨겨집니다</string>
|
||||
<string name="revanced_hide_shorts_preview_comment_summary_off">댓글 미리보기가 표시됩니다</string>
|
||||
|
||||
@@ -397,8 +397,8 @@
|
||||
<item>DEFAULT</item>
|
||||
<item>REGULAR</item>
|
||||
<item>PREMIUM</item>
|
||||
<item>REVANCED</item>
|
||||
<item>REVANCED_MINIMAL</item>
|
||||
<item>ROUNDED</item>
|
||||
<item>MINIMAL</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_header_logo_custom_entries">
|
||||
<item>@string/revanced_header_logo_entry_1</item>
|
||||
@@ -412,8 +412,8 @@
|
||||
<item>DEFAULT</item>
|
||||
<item>REGULAR</item>
|
||||
<item>PREMIUM</item>
|
||||
<item>REVANCED</item>
|
||||
<item>REVANCED_MINIMAL</item>
|
||||
<item>ROUNDED</item>
|
||||
<item>MINIMAL</item>
|
||||
<item>CUSTOM</item>
|
||||
</string-array>
|
||||
</patch>
|
||||
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1,39 @@
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="129dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="129"
|
||||
android:viewportHeight="48">
|
||||
|
||||
<path
|
||||
android:fillColor="#1B1B1B"
|
||||
android:pathData="M23,11.5C29.9,11.5 35.5,17.1 35.5,24C35.5,30.9 29.9,36.5 23,36.5C16.1,36.5 10.5,30.9 10.5,24C10.5,17.1 16.1,11.5 23,11.5ZM23,11.5" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M27.34,19.93C27.38,19.83 27.37,19.71 27.31,19.61C27.25,19.51 27.14,19.45 27.02,19.45C26.86,19.45 26.7,19.45 26.58,19.45C26.48,19.45 26.39,19.51 26.36,19.6C25.96,20.49 23.91,25.17 23.22,26.73C23.18,26.82 23.1,26.88 23,26.88C22.9,26.88 22.82,26.82 22.78,26.73C22.09,25.17 20.04,20.49 19.64,19.6C19.61,19.51 19.52,19.45 19.42,19.45C19.3,19.45 19.14,19.45 18.98,19.45C18.86,19.45 18.75,19.51 18.69,19.61C18.63,19.71 18.62,19.83 18.66,19.93C19.4,21.61 21.85,27.2 22.35,28.34C22.4,28.46 22.52,28.55 22.66,28.55C22.86,28.55 23.14,28.55 23.34,28.55C23.48,28.55 23.6,28.46 23.65,28.34C24.15,27.2 26.6,21.61 27.34,19.93ZM27.34,19.93" />
|
||||
<path
|
||||
android:pathData="M23.25,23.85C23.2,23.95 23.11,24 23,24C22.89,24 22.8,23.95 22.75,23.85C22.21,22.93 20.99,20.81 20.46,19.89C20.41,19.8 20.41,19.69 20.46,19.6C20.51,19.51 20.61,19.45 20.71,19.45L25.29,19.45C25.39,19.45 25.49,19.51 25.54,19.6C25.59,19.69 25.59,19.8 25.54,19.89C25.01,20.81 23.79,22.93 23.25,23.85ZM23.25,23.85">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="23"
|
||||
android:startY="19.45"
|
||||
android:endX="23"
|
||||
android:endY="28.5"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:offset="0"
|
||||
android:color="#F04E98"/>
|
||||
<item
|
||||
android:offset="0.5"
|
||||
android:color="#5F65D4"/>
|
||||
<item
|
||||
android:offset="1"
|
||||
android:color="#4E98F0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M39.89,29.96L39.89,17.84L45.04,17.84C46.34,17.84 47.28,17.95 47.86,18.17C48.45,18.39 48.93,18.77 49.28,19.33C49.63,19.89 49.8,20.52 49.8,21.24C49.8,22.15 49.54,22.9 49,23.5C48.47,24.09 47.67,24.46 46.61,24.61C47.14,24.92 47.57,25.26 47.91,25.63C48.26,26 48.73,26.65 49.31,27.6L50.79,29.96L47.86,29.96L46.09,27.32C45.46,26.38 45.04,25.79 44.8,25.55C44.57,25.3 44.33,25.13 44.07,25.04C43.81,24.95 43.4,24.9 42.84,24.9L42.34,24.9L42.34,29.96ZM42.34,22.97L44.15,22.97C45.32,22.97 46.06,22.92 46.35,22.82C46.64,22.72 46.87,22.55 47.04,22.3C47.2,22.06 47.29,21.76 47.29,21.39C47.29,20.99 47.18,20.66 46.95,20.41C46.74,20.16 46.43,20 46.04,19.93C45.84,19.91 45.24,19.89 44.25,19.89L42.34,19.89ZM57.18,27.17L59.49,27.55C59.2,28.4 58.72,29.05 58.08,29.5C57.44,29.94 56.64,30.16 55.68,30.16C54.15,30.16 53.02,29.66 52.29,28.66C51.71,27.86 51.42,26.86 51.42,25.64C51.42,24.18 51.8,23.04 52.56,22.22C53.32,21.39 54.28,20.98 55.44,20.98C56.75,20.98 57.78,21.41 58.54,22.28C59.29,23.14 59.65,24.46 59.62,26.24L53.8,26.24C53.81,26.93 54,27.46 54.36,27.85C54.72,28.23 55.16,28.42 55.7,28.42C56.06,28.42 56.37,28.32 56.62,28.13C56.86,27.93 57.05,27.61 57.18,27.17ZM57.31,24.82C57.29,24.14 57.12,23.64 56.79,23.29C56.46,22.94 56.06,22.76 55.58,22.76C55.08,22.76 54.66,22.95 54.33,23.31C54,23.68 53.83,24.18 53.84,24.82ZM64.62,29.96L60.29,17.84L62.94,17.84L66.01,26.81L68.97,17.84L71.57,17.84L67.23,29.96ZM73.6,23.86L71.5,23.48C71.73,22.63 72.14,22 72.72,21.59C73.3,21.19 74.16,20.98 75.3,20.98C76.33,20.98 77.11,21.11 77.61,21.36C78.12,21.6 78.47,21.91 78.68,22.29C78.89,22.66 78.99,23.36 78.99,24.36L78.97,27.07C78.97,27.85 79,28.42 79.07,28.79C79.15,29.15 79.29,29.54 79.5,29.96L77.2,29.96C77.14,29.8 77.06,29.58 76.98,29.27C76.94,29.14 76.91,29.05 76.89,29C76.5,29.39 76.07,29.68 75.62,29.87C75.17,30.06 74.68,30.16 74.17,30.16C73.27,30.16 72.55,29.91 72.03,29.42C71.52,28.93 71.25,28.31 71.25,27.56C71.25,27.07 71.38,26.63 71.61,26.24C71.85,25.85 72.18,25.55 72.6,25.35C73.03,25.14 73.65,24.96 74.45,24.8C75.54,24.6 76.29,24.41 76.71,24.23L76.71,24C76.71,23.55 76.6,23.24 76.38,23.05C76.16,22.86 75.74,22.76 75.13,22.76C74.72,22.76 74.39,22.84 74.16,23.01C73.93,23.17 73.75,23.45 73.6,23.86ZM76.71,25.75C76.41,25.84 75.94,25.96 75.3,26.1C74.65,26.24 74.23,26.37 74.03,26.5C73.73,26.72 73.58,26.99 73.58,27.32C73.58,27.65 73.7,27.93 73.94,28.17C74.18,28.4 74.49,28.52 74.87,28.52C75.29,28.52 75.68,28.38 76.07,28.11C76.35,27.9 76.53,27.64 76.62,27.34C76.68,27.14 76.71,26.77 76.71,26.21ZM89.27,29.96L86.94,29.96L86.94,25.48C86.94,24.53 86.89,23.92 86.79,23.64C86.7,23.36 86.53,23.14 86.31,22.99C86.09,22.84 85.82,22.76 85.5,22.76C85.1,22.76 84.74,22.87 84.42,23.09C84.1,23.31 83.88,23.6 83.76,23.97C83.64,24.33 83.59,25 83.59,25.98L83.59,29.96L81.27,29.96L81.27,21.18L83.42,21.18L83.42,22.47C84.19,21.48 85.15,20.98 86.32,20.98C86.83,20.98 87.3,21.08 87.72,21.27C88.14,21.45 88.46,21.68 88.68,21.96C88.9,22.25 89.05,22.58 89.13,22.94C89.22,23.3 89.27,23.83 89.27,24.5ZM99.28,23.78L96.98,24.19C96.91,23.73 96.73,23.39 96.46,23.16C96.19,22.93 95.84,22.81 95.4,22.81C94.82,22.81 94.36,23.01 94.01,23.41C93.67,23.81 93.5,24.48 93.5,25.41C93.5,26.46 93.67,27.19 94.02,27.62C94.37,28.05 94.84,28.27 95.43,28.27C95.87,28.27 96.23,28.14 96.52,27.89C96.8,27.64 97,27.21 97.11,26.6L99.39,26.98C99.16,28.03 98.7,28.82 98.03,29.36C97.36,29.89 96.45,30.16 95.32,30.16C94.04,30.16 93.02,29.75 92.25,28.94C91.49,28.13 91.11,27.01 91.11,25.58C91.11,24.13 91.49,23 92.26,22.2C93.02,21.39 94.06,20.98 95.37,20.98C96.43,20.98 97.29,21.21 97.91,21.68C98.55,22.14 99,22.84 99.28,23.78ZM106.12,27.17L108.43,27.55C108.14,28.4 107.66,29.05 107.02,29.5C106.38,29.94 105.58,30.16 104.62,30.16C103.09,30.16 101.96,29.66 101.23,28.66C100.65,27.86 100.36,26.86 100.36,25.64C100.36,24.18 100.74,23.04 101.5,22.22C102.26,21.39 103.22,20.98 104.38,20.98C105.69,20.98 106.72,21.41 107.48,22.28C108.23,23.14 108.59,24.46 108.56,26.24L102.74,26.24C102.75,26.93 102.94,27.46 103.3,27.85C103.66,28.23 104.11,28.42 104.64,28.42C105,28.42 105.31,28.32 105.56,28.13C105.8,27.93 105.99,27.61 106.12,27.17ZM106.25,24.82C106.23,24.14 106.06,23.64 105.73,23.29C105.4,22.94 105,22.76 104.52,22.76C104.02,22.76 103.6,22.95 103.27,23.31C102.94,23.68 102.77,24.18 102.78,24.82ZM118.5,29.96L116.34,29.96L116.34,28.67C115.98,29.17 115.56,29.55 115.07,29.79C114.59,30.04 114.1,30.16 113.6,30.16C112.59,30.16 111.73,29.75 111,28.94C110.29,28.13 109.93,26.99 109.93,25.54C109.93,24.05 110.28,22.92 110.98,22.15C111.68,21.37 112.56,20.98 113.63,20.98C114.61,20.98 115.46,21.39 116.18,22.21L116.18,17.84L118.5,17.84ZM112.3,25.38C112.3,26.32 112.43,27 112.69,27.41C113.07,28.02 113.59,28.32 114.26,28.32C114.8,28.32 115.25,28.1 115.63,27.64C116,27.19 116.19,26.51 116.19,25.61C116.19,24.59 116,23.87 115.64,23.43C115.28,22.98 114.81,22.76 114.25,22.76C113.7,22.76 113.23,22.98 112.86,23.42C112.49,23.86 112.3,24.51 112.3,25.38ZM112.3,25.38" />
|
||||
</vector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="129dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="129"
|
||||
android:viewportHeight="48">
|
||||
|
||||
<path
|
||||
android:fillColor="#1B1B1B"
|
||||
android:pathData="M23,11.5C29.9,11.5 35.5,17.1 35.5,24C35.5,30.9 29.9,36.5 23,36.5C16.1,36.5 10.5,30.9 10.5,24C10.5,17.1 16.1,11.5 23,11.5ZM23,11.5" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M27.34,19.93C27.38,19.83 27.37,19.71 27.31,19.61C27.25,19.51 27.14,19.45 27.02,19.45C26.86,19.45 26.7,19.45 26.58,19.45C26.48,19.45 26.39,19.51 26.36,19.6C25.96,20.49 23.91,25.17 23.22,26.73C23.18,26.82 23.1,26.88 23,26.88C22.9,26.88 22.82,26.82 22.78,26.73C22.09,25.17 20.04,20.49 19.64,19.6C19.61,19.51 19.52,19.45 19.42,19.45C19.3,19.45 19.14,19.45 18.98,19.45C18.86,19.45 18.75,19.51 18.69,19.61C18.63,19.71 18.62,19.83 18.66,19.93C19.4,21.61 21.85,27.2 22.35,28.34C22.4,28.46 22.52,28.55 22.66,28.55C22.86,28.55 23.14,28.55 23.34,28.55C23.48,28.55 23.6,28.46 23.65,28.34C24.15,27.2 26.6,21.61 27.34,19.93ZM27.34,19.93" />
|
||||
<path
|
||||
android:pathData="M23.25,23.85C23.2,23.95 23.11,24 23,24C22.89,24 22.8,23.95 22.75,23.85C22.21,22.93 20.99,20.81 20.46,19.89C20.41,19.8 20.41,19.69 20.46,19.6C20.51,19.51 20.61,19.45 20.71,19.45L25.29,19.45C25.39,19.45 25.49,19.51 25.54,19.6C25.59,19.69 25.59,19.8 25.54,19.89C25.01,20.81 23.79,22.93 23.25,23.85ZM23.25,23.85">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="23"
|
||||
android:startY="19.45"
|
||||
android:endX="23"
|
||||
android:endY="28.5"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:offset="0"
|
||||
android:color="#F04E98"/>
|
||||
<item
|
||||
android:offset="0.5"
|
||||
android:color="#5F65D4"/>
|
||||
<item
|
||||
android:offset="1"
|
||||
android:color="#4E98F0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M39.89,29.96L39.89,17.84L45.04,17.84C46.34,17.84 47.28,17.95 47.86,18.17C48.45,18.39 48.93,18.77 49.28,19.33C49.63,19.89 49.8,20.52 49.8,21.24C49.8,22.15 49.54,22.9 49,23.5C48.47,24.09 47.67,24.46 46.61,24.61C47.14,24.92 47.57,25.26 47.91,25.63C48.26,26 48.73,26.65 49.31,27.6L50.79,29.96L47.86,29.96L46.09,27.32C45.46,26.38 45.04,25.79 44.8,25.55C44.57,25.3 44.33,25.13 44.07,25.04C43.81,24.95 43.4,24.9 42.84,24.9L42.34,24.9L42.34,29.96ZM42.34,22.97L44.15,22.97C45.32,22.97 46.06,22.92 46.35,22.82C46.64,22.72 46.87,22.55 47.04,22.3C47.2,22.06 47.29,21.76 47.29,21.39C47.29,20.99 47.18,20.66 46.95,20.41C46.74,20.16 46.43,20 46.04,19.93C45.84,19.91 45.24,19.89 44.25,19.89L42.34,19.89ZM57.18,27.17L59.49,27.55C59.2,28.4 58.72,29.05 58.08,29.5C57.44,29.94 56.64,30.16 55.68,30.16C54.15,30.16 53.02,29.66 52.29,28.66C51.71,27.86 51.42,26.86 51.42,25.64C51.42,24.18 51.8,23.04 52.56,22.22C53.32,21.39 54.28,20.98 55.44,20.98C56.75,20.98 57.78,21.41 58.54,22.28C59.29,23.14 59.65,24.46 59.62,26.24L53.8,26.24C53.81,26.93 54,27.46 54.36,27.85C54.72,28.23 55.16,28.42 55.7,28.42C56.06,28.42 56.37,28.32 56.62,28.13C56.86,27.93 57.05,27.61 57.18,27.17ZM57.31,24.82C57.29,24.14 57.12,23.64 56.79,23.29C56.46,22.94 56.06,22.76 55.58,22.76C55.08,22.76 54.66,22.95 54.33,23.31C54,23.68 53.83,24.18 53.84,24.82ZM64.62,29.96L60.29,17.84L62.94,17.84L66.01,26.81L68.97,17.84L71.57,17.84L67.23,29.96ZM73.6,23.86L71.5,23.48C71.73,22.63 72.14,22 72.72,21.59C73.3,21.19 74.16,20.98 75.3,20.98C76.33,20.98 77.11,21.11 77.61,21.36C78.12,21.6 78.47,21.91 78.68,22.29C78.89,22.66 78.99,23.36 78.99,24.36L78.97,27.07C78.97,27.85 79,28.42 79.07,28.79C79.15,29.15 79.29,29.54 79.5,29.96L77.2,29.96C77.14,29.8 77.06,29.58 76.98,29.27C76.94,29.14 76.91,29.05 76.89,29C76.5,29.39 76.07,29.68 75.62,29.87C75.17,30.06 74.68,30.16 74.17,30.16C73.27,30.16 72.55,29.91 72.03,29.42C71.52,28.93 71.25,28.31 71.25,27.56C71.25,27.07 71.38,26.63 71.61,26.24C71.85,25.85 72.18,25.55 72.6,25.35C73.03,25.14 73.65,24.96 74.45,24.8C75.54,24.6 76.29,24.41 76.71,24.23L76.71,24C76.71,23.55 76.6,23.24 76.38,23.05C76.16,22.86 75.74,22.76 75.13,22.76C74.72,22.76 74.39,22.84 74.16,23.01C73.93,23.17 73.75,23.45 73.6,23.86ZM76.71,25.75C76.41,25.84 75.94,25.96 75.3,26.1C74.65,26.24 74.23,26.37 74.03,26.5C73.73,26.72 73.58,26.99 73.58,27.32C73.58,27.65 73.7,27.93 73.94,28.17C74.18,28.4 74.49,28.52 74.87,28.52C75.29,28.52 75.68,28.38 76.07,28.11C76.35,27.9 76.53,27.64 76.62,27.34C76.68,27.14 76.71,26.77 76.71,26.21ZM89.27,29.96L86.94,29.96L86.94,25.48C86.94,24.53 86.89,23.92 86.79,23.64C86.7,23.36 86.53,23.14 86.31,22.99C86.09,22.84 85.82,22.76 85.5,22.76C85.1,22.76 84.74,22.87 84.42,23.09C84.1,23.31 83.88,23.6 83.76,23.97C83.64,24.33 83.59,25 83.59,25.98L83.59,29.96L81.27,29.96L81.27,21.18L83.42,21.18L83.42,22.47C84.19,21.48 85.15,20.98 86.32,20.98C86.83,20.98 87.3,21.08 87.72,21.27C88.14,21.45 88.46,21.68 88.68,21.96C88.9,22.25 89.05,22.58 89.13,22.94C89.22,23.3 89.27,23.83 89.27,24.5ZM99.28,23.78L96.98,24.19C96.91,23.73 96.73,23.39 96.46,23.16C96.19,22.93 95.84,22.81 95.4,22.81C94.82,22.81 94.36,23.01 94.01,23.41C93.67,23.81 93.5,24.48 93.5,25.41C93.5,26.46 93.67,27.19 94.02,27.62C94.37,28.05 94.84,28.27 95.43,28.27C95.87,28.27 96.23,28.14 96.52,27.89C96.8,27.64 97,27.21 97.11,26.6L99.39,26.98C99.16,28.03 98.7,28.82 98.03,29.36C97.36,29.89 96.45,30.16 95.32,30.16C94.04,30.16 93.02,29.75 92.25,28.94C91.49,28.13 91.11,27.01 91.11,25.58C91.11,24.13 91.49,23 92.26,22.2C93.02,21.39 94.06,20.98 95.37,20.98C96.43,20.98 97.29,21.21 97.91,21.68C98.55,22.14 99,22.84 99.28,23.78ZM106.12,27.17L108.43,27.55C108.14,28.4 107.66,29.05 107.02,29.5C106.38,29.94 105.58,30.16 104.62,30.16C103.09,30.16 101.96,29.66 101.23,28.66C100.65,27.86 100.36,26.86 100.36,25.64C100.36,24.18 100.74,23.04 101.5,22.22C102.26,21.39 103.22,20.98 104.38,20.98C105.69,20.98 106.72,21.41 107.48,22.28C108.23,23.14 108.59,24.46 108.56,26.24L102.74,26.24C102.75,26.93 102.94,27.46 103.3,27.85C103.66,28.23 104.11,28.42 104.64,28.42C105,28.42 105.31,28.32 105.56,28.13C105.8,27.93 105.99,27.61 106.12,27.17ZM106.25,24.82C106.23,24.14 106.06,23.64 105.73,23.29C105.4,22.94 105,22.76 104.52,22.76C104.02,22.76 103.6,22.95 103.27,23.31C102.94,23.68 102.77,24.18 102.78,24.82ZM118.5,29.96L116.34,29.96L116.34,28.67C115.98,29.17 115.56,29.55 115.07,29.79C114.59,30.04 114.1,30.16 113.6,30.16C112.59,30.16 111.73,29.75 111,28.94C110.29,28.13 109.93,26.99 109.93,25.54C109.93,24.05 110.28,22.92 110.98,22.15C111.68,21.37 112.56,20.98 113.63,20.98C114.61,20.98 115.46,21.39 116.18,22.21L116.18,17.84L118.5,17.84ZM112.3,25.38C112.3,26.32 112.43,27 112.69,27.41C113.07,28.02 113.59,28.32 114.26,28.32C114.8,28.32 115.25,28.1 115.63,27.64C116,27.19 116.19,26.51 116.19,25.61C116.19,24.59 116,23.87 115.64,23.43C115.28,22.98 114.81,22.76 114.25,22.76C113.7,22.76 113.23,22.98 112.86,23.42C112.49,23.86 112.3,24.51 112.3,25.38ZM112.3,25.38" />
|
||||
</vector>
|
||||
@@ -0,0 +1,60 @@
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="129dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="129"
|
||||
android:viewportHeight="48">
|
||||
|
||||
<path
|
||||
android:fillColor="#1B1B1B"
|
||||
android:pathData="M23,11.5C29.9,11.5 35.5,17.1 35.5,24C35.5,30.9 29.9,36.5 23,36.5C16.1,36.5 10.5,30.9 10.5,24C10.5,17.1 16.1,11.5 23,11.5ZM23,11.5" />
|
||||
<path
|
||||
android:pathData="M23,11.5C29.9,11.5 35.5,17.1 35.5,24C35.5,30.9 29.9,36.5 23,36.5C16.1,36.5 10.5,30.9 10.5,24C10.5,17.1 16.1,11.5 23,11.5ZM23,12.63C16.72,12.63 11.63,17.72 11.63,24C11.63,30.28 16.72,35.38 23,35.38C29.28,35.38 34.38,30.28 34.38,24C34.38,17.72 29.28,12.63 23,12.63ZM23,12.63">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="23"
|
||||
android:startY="11.5"
|
||||
android:endX="23"
|
||||
android:endY="36.5"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:offset="0"
|
||||
android:color="#F04E98"/>
|
||||
<item
|
||||
android:offset="0.5"
|
||||
android:color="#5F65D4"/>
|
||||
<item
|
||||
android:offset="1"
|
||||
android:color="#4E98F0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M27.34,19.93C27.38,19.83 27.37,19.71 27.31,19.61C27.25,19.51 27.14,19.45 27.02,19.45C26.86,19.45 26.7,19.45 26.58,19.45C26.48,19.45 26.39,19.51 26.36,19.6C25.96,20.49 23.91,25.17 23.22,26.73C23.18,26.82 23.1,26.88 23,26.88C22.9,26.88 22.82,26.82 22.78,26.73C22.09,25.17 20.04,20.49 19.64,19.6C19.61,19.51 19.52,19.45 19.42,19.45C19.3,19.45 19.14,19.45 18.98,19.45C18.86,19.45 18.75,19.51 18.69,19.61C18.63,19.71 18.62,19.83 18.66,19.93C19.4,21.61 21.85,27.2 22.35,28.34C22.4,28.46 22.52,28.55 22.66,28.55C22.86,28.55 23.14,28.55 23.34,28.55C23.48,28.55 23.6,28.46 23.65,28.34C24.15,27.2 26.6,21.61 27.34,19.93ZM27.34,19.93" />
|
||||
<path
|
||||
android:pathData="M23.25,23.85C23.2,23.95 23.11,24 23,24C22.89,24 22.8,23.95 22.75,23.85C22.21,22.93 20.99,20.81 20.46,19.89C20.41,19.8 20.41,19.69 20.46,19.6C20.51,19.51 20.61,19.45 20.71,19.45L25.29,19.45C25.39,19.45 25.49,19.51 25.54,19.6C25.59,19.69 25.59,19.8 25.54,19.89C25.01,20.81 23.79,22.93 23.25,23.85ZM23.25,23.85">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="23"
|
||||
android:startY="19.45"
|
||||
android:endX="23"
|
||||
android:endY="28.5"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:offset="0"
|
||||
android:color="#F04E98"/>
|
||||
<item
|
||||
android:offset="0.5"
|
||||
android:color="#5F65D4"/>
|
||||
<item
|
||||
android:offset="1"
|
||||
android:color="#4E98F0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M39.89,29.96L39.89,17.84L45.04,17.84C46.34,17.84 47.28,17.95 47.86,18.17C48.45,18.39 48.93,18.77 49.28,19.33C49.63,19.89 49.8,20.52 49.8,21.24C49.8,22.15 49.54,22.9 49,23.5C48.47,24.09 47.67,24.46 46.61,24.61C47.14,24.92 47.57,25.26 47.91,25.63C48.26,26 48.73,26.65 49.31,27.6L50.79,29.96L47.86,29.96L46.09,27.32C45.46,26.38 45.04,25.79 44.8,25.55C44.57,25.3 44.33,25.13 44.07,25.04C43.81,24.95 43.4,24.9 42.84,24.9L42.34,24.9L42.34,29.96ZM42.34,22.97L44.15,22.97C45.32,22.97 46.06,22.92 46.35,22.82C46.64,22.72 46.87,22.55 47.04,22.3C47.2,22.06 47.29,21.76 47.29,21.39C47.29,20.99 47.18,20.66 46.95,20.41C46.74,20.16 46.43,20 46.04,19.93C45.84,19.91 45.24,19.89 44.25,19.89L42.34,19.89ZM57.18,27.17L59.49,27.55C59.2,28.4 58.72,29.05 58.08,29.5C57.44,29.94 56.64,30.16 55.68,30.16C54.15,30.16 53.02,29.66 52.29,28.66C51.71,27.86 51.42,26.86 51.42,25.64C51.42,24.18 51.8,23.04 52.56,22.22C53.32,21.39 54.28,20.98 55.44,20.98C56.75,20.98 57.78,21.41 58.54,22.28C59.29,23.14 59.65,24.46 59.62,26.24L53.8,26.24C53.81,26.93 54,27.46 54.36,27.85C54.72,28.23 55.16,28.42 55.7,28.42C56.06,28.42 56.37,28.32 56.62,28.13C56.86,27.93 57.05,27.61 57.18,27.17ZM57.31,24.82C57.29,24.14 57.12,23.64 56.79,23.29C56.46,22.94 56.06,22.76 55.58,22.76C55.08,22.76 54.66,22.95 54.33,23.31C54,23.68 53.83,24.18 53.84,24.82ZM64.62,29.96L60.29,17.84L62.94,17.84L66.01,26.81L68.97,17.84L71.57,17.84L67.23,29.96ZM73.6,23.86L71.5,23.48C71.73,22.63 72.14,22 72.72,21.59C73.3,21.19 74.16,20.98 75.3,20.98C76.33,20.98 77.11,21.11 77.61,21.36C78.12,21.6 78.47,21.91 78.68,22.29C78.89,22.66 78.99,23.36 78.99,24.36L78.97,27.07C78.97,27.85 79,28.42 79.07,28.79C79.15,29.15 79.29,29.54 79.5,29.96L77.2,29.96C77.14,29.8 77.06,29.58 76.98,29.27C76.94,29.14 76.91,29.05 76.89,29C76.5,29.39 76.07,29.68 75.62,29.87C75.17,30.06 74.68,30.16 74.17,30.16C73.27,30.16 72.55,29.91 72.03,29.42C71.52,28.93 71.25,28.31 71.25,27.56C71.25,27.07 71.38,26.63 71.61,26.24C71.85,25.85 72.18,25.55 72.6,25.35C73.03,25.14 73.65,24.96 74.45,24.8C75.54,24.6 76.29,24.41 76.71,24.23L76.71,24C76.71,23.55 76.6,23.24 76.38,23.05C76.16,22.86 75.74,22.76 75.13,22.76C74.72,22.76 74.39,22.84 74.16,23.01C73.93,23.17 73.75,23.45 73.6,23.86ZM76.71,25.75C76.41,25.84 75.94,25.96 75.3,26.1C74.65,26.24 74.23,26.37 74.03,26.5C73.73,26.72 73.58,26.99 73.58,27.32C73.58,27.65 73.7,27.93 73.94,28.17C74.18,28.4 74.49,28.52 74.87,28.52C75.29,28.52 75.68,28.38 76.07,28.11C76.35,27.9 76.53,27.64 76.62,27.34C76.68,27.14 76.71,26.77 76.71,26.21ZM89.27,29.96L86.94,29.96L86.94,25.48C86.94,24.53 86.89,23.92 86.79,23.64C86.7,23.36 86.53,23.14 86.31,22.99C86.09,22.84 85.82,22.76 85.5,22.76C85.1,22.76 84.74,22.87 84.42,23.09C84.1,23.31 83.88,23.6 83.76,23.97C83.64,24.33 83.59,25 83.59,25.98L83.59,29.96L81.27,29.96L81.27,21.18L83.42,21.18L83.42,22.47C84.19,21.48 85.15,20.98 86.32,20.98C86.83,20.98 87.3,21.08 87.72,21.27C88.14,21.45 88.46,21.68 88.68,21.96C88.9,22.25 89.05,22.58 89.13,22.94C89.22,23.3 89.27,23.83 89.27,24.5ZM99.28,23.78L96.98,24.19C96.91,23.73 96.73,23.39 96.46,23.16C96.19,22.93 95.84,22.81 95.4,22.81C94.82,22.81 94.36,23.01 94.01,23.41C93.67,23.81 93.5,24.48 93.5,25.41C93.5,26.46 93.67,27.19 94.02,27.62C94.37,28.05 94.84,28.27 95.43,28.27C95.87,28.27 96.23,28.14 96.52,27.89C96.8,27.64 97,27.21 97.11,26.6L99.39,26.98C99.16,28.03 98.7,28.82 98.03,29.36C97.36,29.89 96.45,30.16 95.32,30.16C94.04,30.16 93.02,29.75 92.25,28.94C91.49,28.13 91.11,27.01 91.11,25.58C91.11,24.13 91.49,23 92.26,22.2C93.02,21.39 94.06,20.98 95.37,20.98C96.43,20.98 97.29,21.21 97.91,21.68C98.55,22.14 99,22.84 99.28,23.78ZM106.12,27.17L108.43,27.55C108.14,28.4 107.66,29.05 107.02,29.5C106.38,29.94 105.58,30.16 104.62,30.16C103.09,30.16 101.96,29.66 101.23,28.66C100.65,27.86 100.36,26.86 100.36,25.64C100.36,24.18 100.74,23.04 101.5,22.22C102.26,21.39 103.22,20.98 104.38,20.98C105.69,20.98 106.72,21.41 107.48,22.28C108.23,23.14 108.59,24.46 108.56,26.24L102.74,26.24C102.75,26.93 102.94,27.46 103.3,27.85C103.66,28.23 104.11,28.42 104.64,28.42C105,28.42 105.31,28.32 105.56,28.13C105.8,27.93 105.99,27.61 106.12,27.17ZM106.25,24.82C106.23,24.14 106.06,23.64 105.73,23.29C105.4,22.94 105,22.76 104.52,22.76C104.02,22.76 103.6,22.95 103.27,23.31C102.94,23.68 102.77,24.18 102.78,24.82ZM118.5,29.96L116.34,29.96L116.34,28.67C115.98,29.17 115.56,29.55 115.07,29.79C114.59,30.04 114.1,30.16 113.6,30.16C112.59,30.16 111.73,29.75 111,28.94C110.29,28.13 109.93,26.99 109.93,25.54C109.93,24.05 110.28,22.92 110.98,22.15C111.68,21.37 112.56,20.98 113.63,20.98C114.61,20.98 115.46,21.39 116.18,22.21L116.18,17.84L118.5,17.84ZM112.3,25.38C112.3,26.32 112.43,27 112.69,27.41C113.07,28.02 113.59,28.32 114.26,28.32C114.8,28.32 115.25,28.1 115.63,27.64C116,27.19 116.19,26.51 116.19,25.61C116.19,24.59 116,23.87 115.64,23.43C115.28,22.98 114.81,22.76 114.25,22.76C113.7,22.76 113.23,22.98 112.86,23.42C112.49,23.86 112.3,24.51 112.3,25.38ZM112.3,25.38" />
|
||||
</vector>
|
||||
@@ -0,0 +1,60 @@
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="129dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="129"
|
||||
android:viewportHeight="48">
|
||||
|
||||
<path
|
||||
android:fillColor="#1B1B1B"
|
||||
android:pathData="M23,11.5C29.9,11.5 35.5,17.1 35.5,24C35.5,30.9 29.9,36.5 23,36.5C16.1,36.5 10.5,30.9 10.5,24C10.5,17.1 16.1,11.5 23,11.5ZM23,11.5" />
|
||||
<path
|
||||
android:pathData="M23,11.5C29.9,11.5 35.5,17.1 35.5,24C35.5,30.9 29.9,36.5 23,36.5C16.1,36.5 10.5,30.9 10.5,24C10.5,17.1 16.1,11.5 23,11.5ZM23,12.63C16.72,12.63 11.63,17.72 11.63,24C11.63,30.28 16.72,35.38 23,35.38C29.28,35.38 34.38,30.28 34.38,24C34.38,17.72 29.28,12.63 23,12.63ZM23,12.63">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="23"
|
||||
android:startY="11.5"
|
||||
android:endX="23"
|
||||
android:endY="36.5"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:offset="0"
|
||||
android:color="#F04E98"/>
|
||||
<item
|
||||
android:offset="0.5"
|
||||
android:color="#5F65D4"/>
|
||||
<item
|
||||
android:offset="1"
|
||||
android:color="#4E98F0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M27.34,19.93C27.38,19.83 27.37,19.71 27.31,19.61C27.25,19.51 27.14,19.45 27.02,19.45C26.86,19.45 26.7,19.45 26.58,19.45C26.48,19.45 26.39,19.51 26.36,19.6C25.96,20.49 23.91,25.17 23.22,26.73C23.18,26.82 23.1,26.88 23,26.88C22.9,26.88 22.82,26.82 22.78,26.73C22.09,25.17 20.04,20.49 19.64,19.6C19.61,19.51 19.52,19.45 19.42,19.45C19.3,19.45 19.14,19.45 18.98,19.45C18.86,19.45 18.75,19.51 18.69,19.61C18.63,19.71 18.62,19.83 18.66,19.93C19.4,21.61 21.85,27.2 22.35,28.34C22.4,28.46 22.52,28.55 22.66,28.55C22.86,28.55 23.14,28.55 23.34,28.55C23.48,28.55 23.6,28.46 23.65,28.34C24.15,27.2 26.6,21.61 27.34,19.93ZM27.34,19.93" />
|
||||
<path
|
||||
android:pathData="M23.25,23.85C23.2,23.95 23.11,24 23,24C22.89,24 22.8,23.95 22.75,23.85C22.21,22.93 20.99,20.81 20.46,19.89C20.41,19.8 20.41,19.69 20.46,19.6C20.51,19.51 20.61,19.45 20.71,19.45L25.29,19.45C25.39,19.45 25.49,19.51 25.54,19.6C25.59,19.69 25.59,19.8 25.54,19.89C25.01,20.81 23.79,22.93 23.25,23.85ZM23.25,23.85">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="23"
|
||||
android:startY="19.45"
|
||||
android:endX="23"
|
||||
android:endY="28.5"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:offset="0"
|
||||
android:color="#F04E98"/>
|
||||
<item
|
||||
android:offset="0.5"
|
||||
android:color="#5F65D4"/>
|
||||
<item
|
||||
android:offset="1"
|
||||
android:color="#4E98F0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M39.89,29.96L39.89,17.84L45.04,17.84C46.34,17.84 47.28,17.95 47.86,18.17C48.45,18.39 48.93,18.77 49.28,19.33C49.63,19.89 49.8,20.52 49.8,21.24C49.8,22.15 49.54,22.9 49,23.5C48.47,24.09 47.67,24.46 46.61,24.61C47.14,24.92 47.57,25.26 47.91,25.63C48.26,26 48.73,26.65 49.31,27.6L50.79,29.96L47.86,29.96L46.09,27.32C45.46,26.38 45.04,25.79 44.8,25.55C44.57,25.3 44.33,25.13 44.07,25.04C43.81,24.95 43.4,24.9 42.84,24.9L42.34,24.9L42.34,29.96ZM42.34,22.97L44.15,22.97C45.32,22.97 46.06,22.92 46.35,22.82C46.64,22.72 46.87,22.55 47.04,22.3C47.2,22.06 47.29,21.76 47.29,21.39C47.29,20.99 47.18,20.66 46.95,20.41C46.74,20.16 46.43,20 46.04,19.93C45.84,19.91 45.24,19.89 44.25,19.89L42.34,19.89ZM57.18,27.17L59.49,27.55C59.2,28.4 58.72,29.05 58.08,29.5C57.44,29.94 56.64,30.16 55.68,30.16C54.15,30.16 53.02,29.66 52.29,28.66C51.71,27.86 51.42,26.86 51.42,25.64C51.42,24.18 51.8,23.04 52.56,22.22C53.32,21.39 54.28,20.98 55.44,20.98C56.75,20.98 57.78,21.41 58.54,22.28C59.29,23.14 59.65,24.46 59.62,26.24L53.8,26.24C53.81,26.93 54,27.46 54.36,27.85C54.72,28.23 55.16,28.42 55.7,28.42C56.06,28.42 56.37,28.32 56.62,28.13C56.86,27.93 57.05,27.61 57.18,27.17ZM57.31,24.82C57.29,24.14 57.12,23.64 56.79,23.29C56.46,22.94 56.06,22.76 55.58,22.76C55.08,22.76 54.66,22.95 54.33,23.31C54,23.68 53.83,24.18 53.84,24.82ZM64.62,29.96L60.29,17.84L62.94,17.84L66.01,26.81L68.97,17.84L71.57,17.84L67.23,29.96ZM73.6,23.86L71.5,23.48C71.73,22.63 72.14,22 72.72,21.59C73.3,21.19 74.16,20.98 75.3,20.98C76.33,20.98 77.11,21.11 77.61,21.36C78.12,21.6 78.47,21.91 78.68,22.29C78.89,22.66 78.99,23.36 78.99,24.36L78.97,27.07C78.97,27.85 79,28.42 79.07,28.79C79.15,29.15 79.29,29.54 79.5,29.96L77.2,29.96C77.14,29.8 77.06,29.58 76.98,29.27C76.94,29.14 76.91,29.05 76.89,29C76.5,29.39 76.07,29.68 75.62,29.87C75.17,30.06 74.68,30.16 74.17,30.16C73.27,30.16 72.55,29.91 72.03,29.42C71.52,28.93 71.25,28.31 71.25,27.56C71.25,27.07 71.38,26.63 71.61,26.24C71.85,25.85 72.18,25.55 72.6,25.35C73.03,25.14 73.65,24.96 74.45,24.8C75.54,24.6 76.29,24.41 76.71,24.23L76.71,24C76.71,23.55 76.6,23.24 76.38,23.05C76.16,22.86 75.74,22.76 75.13,22.76C74.72,22.76 74.39,22.84 74.16,23.01C73.93,23.17 73.75,23.45 73.6,23.86ZM76.71,25.75C76.41,25.84 75.94,25.96 75.3,26.1C74.65,26.24 74.23,26.37 74.03,26.5C73.73,26.72 73.58,26.99 73.58,27.32C73.58,27.65 73.7,27.93 73.94,28.17C74.18,28.4 74.49,28.52 74.87,28.52C75.29,28.52 75.68,28.38 76.07,28.11C76.35,27.9 76.53,27.64 76.62,27.34C76.68,27.14 76.71,26.77 76.71,26.21ZM89.27,29.96L86.94,29.96L86.94,25.48C86.94,24.53 86.89,23.92 86.79,23.64C86.7,23.36 86.53,23.14 86.31,22.99C86.09,22.84 85.82,22.76 85.5,22.76C85.1,22.76 84.74,22.87 84.42,23.09C84.1,23.31 83.88,23.6 83.76,23.97C83.64,24.33 83.59,25 83.59,25.98L83.59,29.96L81.27,29.96L81.27,21.18L83.42,21.18L83.42,22.47C84.19,21.48 85.15,20.98 86.32,20.98C86.83,20.98 87.3,21.08 87.72,21.27C88.14,21.45 88.46,21.68 88.68,21.96C88.9,22.25 89.05,22.58 89.13,22.94C89.22,23.3 89.27,23.83 89.27,24.5ZM99.28,23.78L96.98,24.19C96.91,23.73 96.73,23.39 96.46,23.16C96.19,22.93 95.84,22.81 95.4,22.81C94.82,22.81 94.36,23.01 94.01,23.41C93.67,23.81 93.5,24.48 93.5,25.41C93.5,26.46 93.67,27.19 94.02,27.62C94.37,28.05 94.84,28.27 95.43,28.27C95.87,28.27 96.23,28.14 96.52,27.89C96.8,27.64 97,27.21 97.11,26.6L99.39,26.98C99.16,28.03 98.7,28.82 98.03,29.36C97.36,29.89 96.45,30.16 95.32,30.16C94.04,30.16 93.02,29.75 92.25,28.94C91.49,28.13 91.11,27.01 91.11,25.58C91.11,24.13 91.49,23 92.26,22.2C93.02,21.39 94.06,20.98 95.37,20.98C96.43,20.98 97.29,21.21 97.91,21.68C98.55,22.14 99,22.84 99.28,23.78ZM106.12,27.17L108.43,27.55C108.14,28.4 107.66,29.05 107.02,29.5C106.38,29.94 105.58,30.16 104.62,30.16C103.09,30.16 101.96,29.66 101.23,28.66C100.65,27.86 100.36,26.86 100.36,25.64C100.36,24.18 100.74,23.04 101.5,22.22C102.26,21.39 103.22,20.98 104.38,20.98C105.69,20.98 106.72,21.41 107.48,22.28C108.23,23.14 108.59,24.46 108.56,26.24L102.74,26.24C102.75,26.93 102.94,27.46 103.3,27.85C103.66,28.23 104.11,28.42 104.64,28.42C105,28.42 105.31,28.32 105.56,28.13C105.8,27.93 105.99,27.61 106.12,27.17ZM106.25,24.82C106.23,24.14 106.06,23.64 105.73,23.29C105.4,22.94 105,22.76 104.52,22.76C104.02,22.76 103.6,22.95 103.27,23.31C102.94,23.68 102.77,24.18 102.78,24.82ZM118.5,29.96L116.34,29.96L116.34,28.67C115.98,29.17 115.56,29.55 115.07,29.79C114.59,30.04 114.1,30.16 113.6,30.16C112.59,30.16 111.73,29.75 111,28.94C110.29,28.13 109.93,26.99 109.93,25.54C109.93,24.05 110.28,22.92 110.98,22.15C111.68,21.37 112.56,20.98 113.63,20.98C114.61,20.98 115.46,21.39 116.18,22.21L116.18,17.84L118.5,17.84ZM112.3,25.38C112.3,26.32 112.43,27 112.69,27.41C113.07,28.02 113.59,28.32 114.26,28.32C114.8,28.32 115.25,28.1 115.63,27.64C116,27.19 116.19,26.51 116.19,25.61C116.19,24.59 116,23.87 115.64,23.43C115.28,22.98 114.81,22.76 114.25,22.76C113.7,22.76 113.23,22.98 112.86,23.42C112.49,23.86 112.3,24.51 112.3,25.38ZM112.3,25.38" />
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<attr format="reference|color" name="splash_custom_seekbar_color"/>
|
||||
</resources>
|
||||