1
mirror of https://github.com/revanced/revanced-integrations synced 2025-11-21 18:35:37 +01:00

Compare commits

..

34 Commits

Author SHA1 Message Date
semantic-release-bot
910b03e9a3 chore(release): 1.5.0-dev.9 [skip ci]
# [1.5.0-dev.9](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.8...v1.5.0-dev.9) (2024-03-27)

### Bug Fixes

* Check index of pattern in string instead of the other way around ([96a1e46](96a1e4680d))
* **YouTube - Hide layout components:** Correctly hide Join button ([b945e2f](b945e2f44b))
* **YouTube - Hide Shorts components:** Correctly hide join button ([b7a8995](b7a8995f79))
* **YouTube:** Fix video playback by switching to ReVanced GmsCore vendor ([#589](https://github.com/ReVanced/revanced-integrations/issues/589)) ([6e947e2](6e947e24c2))

### Features

* **YouTube - Hide layout components:** Filter home/search results by keywords ([#584](https://github.com/ReVanced/revanced-integrations/issues/584)) ([0cbad98](0cbad98205))
* **YouTube - Hide Shorts components:** Hide like and dislike buttons ([2a08e5a](2a08e5a98e))
* **YouTube - Hide Shorts components:** Hide sound metadata label ([46d8ef6](46d8ef6f88))
* **YouTube - Hide Shorts components:** Hide title and full video link label ([59165de](59165de801))
2024-03-27 13:12:43 +00:00
LisoUseInAIKyrios
0cbad98205 feat(YouTube - Hide layout components): Filter home/search results by keywords (#584)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-03-27 14:07:36 +01:00
oSumAtrIX
6e947e24c2 fix(YouTube): Fix video playback by switching to ReVanced GmsCore vendor (#589) 2024-03-27 14:07:36 +01:00
oSumAtrIX
96a1e4680d fix: Check index of pattern in string instead of the other way around 2024-03-27 14:07:35 +01:00
oSumAtrIX
46d8ef6f88 feat(YouTube - Hide Shorts components): Hide sound metadata label 2024-03-26 04:46:32 +01:00
oSumAtrIX
b7a8995f79 fix(YouTube - Hide Shorts components): Correctly hide join button 2024-03-26 04:46:32 +01:00
oSumAtrIX
59165de801 feat(YouTube - Hide Shorts components): Hide title and full video link label 2024-03-26 02:18:36 +01:00
oSumAtrIX
2a08e5a98e feat(YouTube - Hide Shorts components): Hide like and dislike buttons 2024-03-26 02:18:10 +01:00
oSumAtrIX
b945e2f44b fix(YouTube - Hide layout components): Correctly hide Join button 2024-03-26 01:36:41 +01:00
oSumAtrIX
bed8f9f640 chore: Remove unnecessary consumer parameter (#591)
The query parameter was introduced for future use. It turns out that it is unnecessary and can be removed therefor.
2024-03-25 21:11:36 +01:00
semantic-release-bot
32a14efe6f chore(release): 1.5.0-dev.8 [skip ci]
# [1.5.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.7...v1.5.0-dev.8) (2024-03-25)

### Bug Fixes

* **YouTube - Hide ads:** Prevent app crash if hiding fullscreen ads is not possible ([#590](https://github.com/ReVanced/revanced-integrations/issues/590)) ([4ec955f](4ec955fd01))
2024-03-25 16:16:13 +00:00
LisoUseInAIKyrios
4ec955fd01 fix(YouTube - Hide ads): Prevent app crash if hiding fullscreen ads is not possible (#590) 2024-03-25 20:13:06 +04:00
semantic-release-bot
f47495ccd8 chore(release): 1.5.0-dev.7 [skip ci]
# [1.5.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.6...v1.5.0-dev.7) (2024-03-18)

### Bug Fixes

* **TikTok:** Hook application context earlier to prevent crash ([#588](https://github.com/ReVanced/revanced-integrations/issues/588)) ([9ac2d63](9ac2d63489))
2024-03-18 00:24:14 +00:00
LisoUseInAIKyrios
9ac2d63489 fix(TikTok): Hook application context earlier to prevent crash (#588) 2024-03-18 04:21:16 +04:00
semantic-release-bot
74b6ab8712 chore(release): 1.5.0-dev.6 [skip ci]
# [1.5.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.5...v1.5.0-dev.6) (2024-03-16)

### Bug Fixes

* Handle custom preferences ([#586](https://github.com/ReVanced/revanced-integrations/issues/586)) ([ad477e4](ad477e4859))
2024-03-16 15:57:16 +00:00
oSumAtrIX
ad477e4859 fix: Handle custom preferences (#586)
* fix: Handle custom preferences
2024-03-16 19:53:53 +04:00
semantic-release-bot
6f1ac5d073 chore(release): 1.5.0-dev.5 [skip ci]
# [1.5.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.4...v1.5.0-dev.5) (2024-03-15)

### Features

* **YouTube - Downloads:** Use external downloader when selecting 'Download' in home feed flyout menu ([#587](https://github.com/ReVanced/revanced-integrations/issues/587)) ([254da31](254da31d16))
2024-03-15 12:35:56 +00:00
LisoUseInAIKyrios
254da31d16 feat(YouTube - Downloads): Use external downloader when selecting 'Download' in home feed flyout menu (#587)
fix(YouTube - Downloads): Use external downloader when selecting 'Download' from home feed flyout menu
2024-03-15 16:32:48 +04:00
oSumAtrIX
7c40c947ef chore: Log intent to be opened by chooser 2024-03-12 13:55:35 +01:00
semantic-release-bot
4be65be414 chore(release): 1.5.0-dev.4 [skip ci]
# [1.5.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.3...v1.5.0-dev.4) (2024-03-11)

### Bug Fixes

* **YouTube - HDR auto brightness:** Remove non functional and obsolete patch ([#585](https://github.com/ReVanced/revanced-integrations/issues/585)) ([b060732](b060732e86))
2024-03-11 09:36:16 +00:00
LisoUseInAIKyrios
b060732e86 fix(YouTube - HDR auto brightness): Remove non functional and obsolete patch (#585) 2024-03-11 13:33:08 +04:00
semantic-release-bot
da8ec49589 chore(release): 1.5.0-dev.3 [skip ci]
# [1.5.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.2...v1.5.0-dev.3) (2024-03-09)

### Bug Fixes

* **YouTube - Disable suggested video end screen:** Disable by default to fix autoplay issues ([#578](https://github.com/ReVanced/revanced-integrations/issues/578)) ([b9c1eec](b9c1eec69f))
2024-03-09 04:20:20 +00:00
oSumAtrIX
b9c1eec69f fix(YouTube - Disable suggested video end screen): Disable by default to fix autoplay issues (#578) 2024-03-09 05:17:27 +01:00
semantic-release-bot
d6032216e4 chore(release): 1.5.0-dev.2 [skip ci]
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2024-03-08)

### Bug Fixes

* **YouTube - Downloads:** Use new task context ([#583](https://github.com/ReVanced/revanced-integrations/issues/583)) ([468dfac](468dfac054))
2024-03-08 05:13:03 +00:00
LisoUseInAIKyrios
468dfac054 fix(YouTube - Downloads): Use new task context (#583)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-03-08 09:10:06 +04:00
semantic-release-bot
75a494e09b chore(release): 1.5.0-dev.1 [skip ci]
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.4...v1.5.0-dev.1) (2024-03-04)

### Features

* **YouTube - External downloader:** Add ability to use in-app download button ([771a0de](771a0de3bc))
2024-03-04 19:40:00 +00:00
oSumAtrIX
771a0de3bc feat(YouTube - External downloader): Add ability to use in-app download button 2024-03-04 20:36:24 +01:00
semantic-release-bot
6aacd1a225 chore(release): 1.4.1-dev.4 [skip ci]
## [1.4.1-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.3...v1.4.1-dev.4) (2024-03-04)

### Bug Fixes

* **YouTube - Hide seekbar:** Use original seekbar color if Theme patch is not included ([#580](https://github.com/ReVanced/revanced-integrations/issues/580)) ([8d48a90](8d48a90a8b))
2024-03-04 11:47:49 +00:00
LisoUseInAIKyrios
8d48a90a8b fix(YouTube - Hide seekbar): Use original seekbar color if Theme patch is not included (#580) 2024-03-04 15:44:56 +04:00
semantic-release-bot
6188fa75c6 chore(release): 1.4.1-dev.3 [skip ci]
## [1.4.1-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.2...v1.4.1-dev.3) (2024-03-04)

### Bug Fixes

* Revert AGP dependency update ([ab07a56](ab07a563b9))
2024-03-04 09:42:57 +00:00
LisoUseInAIKyrios
ab07a563b9 fix: Revert AGP dependency update 2024-03-04 13:33:09 +04:00
semantic-release-bot
c7ae3355a1 chore(release): 1.4.1-dev.2 [skip ci]
## [1.4.1-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.1...v1.4.1-dev.2) (2024-03-04)

### Bug Fixes

* **YouTube - Client spoof:**  Allow playback for links with timestamp ([#582](https://github.com/ReVanced/revanced-integrations/issues/582)) ([eee3f35](eee3f352c5))
2024-03-04 06:55:30 +00:00
Hoàng Gia Bảo
eee3f352c5 fix(YouTube - Client spoof): Allow playback for links with timestamp (#582) 2024-03-04 07:52:18 +01:00
oSumAtrIX
36aa6c9aa8 chore: Lint code 2024-03-03 00:26:34 +01:00
71 changed files with 1221 additions and 418 deletions

3
.editorconfig Normal file
View File

@@ -0,0 +1,3 @@
[*.{kt,kts}]
ktlint_code_style = intellij_idea
ktlint_standard_no-wildcard-imports = disabled

View File

@@ -1,3 +1,98 @@
# [1.5.0-dev.9](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.8...v1.5.0-dev.9) (2024-03-27)
### Bug Fixes
* Check index of pattern in string instead of the other way around ([96a1e46](https://github.com/ReVanced/revanced-integrations/commit/96a1e4680d23be7154bb83290b1887fcd1a22f53))
* **YouTube - Hide layout components:** Correctly hide Join button ([b945e2f](https://github.com/ReVanced/revanced-integrations/commit/b945e2f44b1a62326e6d45345c1467668d803f53))
* **YouTube - Hide Shorts components:** Correctly hide join button ([b7a8995](https://github.com/ReVanced/revanced-integrations/commit/b7a8995f798e386ee1d9ab5bbd857c1736cc5a29))
* **YouTube:** Fix video playback by switching to ReVanced GmsCore vendor ([#589](https://github.com/ReVanced/revanced-integrations/issues/589)) ([6e947e2](https://github.com/ReVanced/revanced-integrations/commit/6e947e24c2ac36e1bddcd25412870a36aa6c85c8))
### Features
* **YouTube - Hide layout components:** Filter home/search results by keywords ([#584](https://github.com/ReVanced/revanced-integrations/issues/584)) ([0cbad98](https://github.com/ReVanced/revanced-integrations/commit/0cbad9820577c476f1f29b6ac77611b38afbb950))
* **YouTube - Hide Shorts components:** Hide like and dislike buttons ([2a08e5a](https://github.com/ReVanced/revanced-integrations/commit/2a08e5a98e9e9a00bb306313ff487d67c042a92e))
* **YouTube - Hide Shorts components:** Hide sound metadata label ([46d8ef6](https://github.com/ReVanced/revanced-integrations/commit/46d8ef6f88bd4c912a45357541291af38b5fc81f))
* **YouTube - Hide Shorts components:** Hide title and full video link label ([59165de](https://github.com/ReVanced/revanced-integrations/commit/59165de801a5481fa4055dcf1797fe84dce235c0))
# [1.5.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.7...v1.5.0-dev.8) (2024-03-25)
### Bug Fixes
* **YouTube - Hide ads:** Prevent app crash if hiding fullscreen ads is not possible ([#590](https://github.com/ReVanced/revanced-integrations/issues/590)) ([4ec955f](https://github.com/ReVanced/revanced-integrations/commit/4ec955fd0133643826e47be7089fbfa07fd9a089))
# [1.5.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.6...v1.5.0-dev.7) (2024-03-18)
### Bug Fixes
* **TikTok:** Hook application context earlier to prevent crash ([#588](https://github.com/ReVanced/revanced-integrations/issues/588)) ([9ac2d63](https://github.com/ReVanced/revanced-integrations/commit/9ac2d634897d961eba1b704f2722ea757bb83e0a))
# [1.5.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.5...v1.5.0-dev.6) (2024-03-16)
### Bug Fixes
* Handle custom preferences ([#586](https://github.com/ReVanced/revanced-integrations/issues/586)) ([ad477e4](https://github.com/ReVanced/revanced-integrations/commit/ad477e4859ef69beda297f7a2a6c29a918077628))
# [1.5.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.4...v1.5.0-dev.5) (2024-03-15)
### Features
* **YouTube - Downloads:** Use external downloader when selecting 'Download' in home feed flyout menu ([#587](https://github.com/ReVanced/revanced-integrations/issues/587)) ([254da31](https://github.com/ReVanced/revanced-integrations/commit/254da31d16c39781f46e1cdea1e9ba22e2fce6d1))
# [1.5.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.3...v1.5.0-dev.4) (2024-03-11)
### Bug Fixes
* **YouTube - HDR auto brightness:** Remove non functional and obsolete patch ([#585](https://github.com/ReVanced/revanced-integrations/issues/585)) ([b060732](https://github.com/ReVanced/revanced-integrations/commit/b060732e861b011cac8737ed597385a3315f6057))
# [1.5.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.2...v1.5.0-dev.3) (2024-03-09)
### Bug Fixes
* **YouTube - Disable suggested video end screen:** Disable by default to fix autoplay issues ([#578](https://github.com/ReVanced/revanced-integrations/issues/578)) ([b9c1eec](https://github.com/ReVanced/revanced-integrations/commit/b9c1eec69fab64f213dd77d1f932e3244d81ab2d))
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2024-03-08)
### Bug Fixes
* **YouTube - Downloads:** Use new task context ([#583](https://github.com/ReVanced/revanced-integrations/issues/583)) ([468dfac](https://github.com/ReVanced/revanced-integrations/commit/468dfac0544e282658675a8be65b4e43aa351068))
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.4...v1.5.0-dev.1) (2024-03-04)
### Features
* **YouTube - External downloader:** Add ability to use in-app download button ([771a0de](https://github.com/ReVanced/revanced-integrations/commit/771a0de3bc9bec3ec5a8e4f8b02edfa9df7b1997))
## [1.4.1-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.3...v1.4.1-dev.4) (2024-03-04)
### Bug Fixes
* **YouTube - Hide seekbar:** Use original seekbar color if Theme patch is not included ([#580](https://github.com/ReVanced/revanced-integrations/issues/580)) ([8d48a90](https://github.com/ReVanced/revanced-integrations/commit/8d48a90a8b8bc7ce9e22580b7a66c4c12fd6d54f))
## [1.4.1-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.2...v1.4.1-dev.3) (2024-03-04)
### Bug Fixes
* Revert AGP dependency update ([ab07a56](https://github.com/ReVanced/revanced-integrations/commit/ab07a563b9ef890dc8a673eeb4268ce1c9f15a69))
## [1.4.1-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.4.1-dev.1...v1.4.1-dev.2) (2024-03-04)
### Bug Fixes
* **YouTube - Client spoof:** Allow playback for links with timestamp ([#582](https://github.com/ReVanced/revanced-integrations/issues/582)) ([eee3f35](https://github.com/ReVanced/revanced-integrations/commit/eee3f352c59141f47f6bda6c6cd350f1a16f1450))
## [1.4.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.4.0...v1.4.1-dev.1) (2024-03-02)

View File

@@ -5,14 +5,15 @@ import static app.revanced.integrations.shared.settings.BaseSettings.DEBUG_STACK
import static app.revanced.integrations.shared.settings.BaseSettings.DEBUG_TOAST_ON_ERROR;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.integrations.shared.settings.BaseSettings;
import java.io.PrintWriter;
import java.io.StringWriter;
import app.revanced.integrations.shared.settings.BaseSettings;
public class Logger {
/**
@@ -24,7 +25,7 @@ public class Logger {
/**
* @return For outer classes, this returns {@link Class#getSimpleName()}.
* For inner, static, or anonymous classes, this returns the simple name of the enclosing class.<br>
* For static, inner, or anonymous classes, this returns the simple name of the enclosing class.
* <br>
* For example, each of these classes return 'SomethingView':
* <code>
@@ -38,13 +39,13 @@ public class Logger {
String fullClassName = selfClass.getName();
final int dollarSignIndex = fullClassName.indexOf('$');
if (dollarSignIndex == -1) {
return selfClass.getSimpleName(); // already an outer class
if (dollarSignIndex < 0) {
return selfClass.getSimpleName(); // Already an outer class.
}
// class is inner, static, or anonymous
// parse the simple name full name
// a class with no package returns index of -1, but incrementing gives index zero which is correct
// Class is inner, static, or anonymous.
// Parse the simple name full name.
// A class with no package returns index of -1, but incrementing gives index zero which is correct.
final int simpleClassNameStartIndex = fullClassName.lastIndexOf('.') + 1;
return fullClassName.substring(simpleClassNameStartIndex, dollarSignIndex);
}
@@ -137,11 +138,19 @@ public class Logger {
}
/**
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#context} may not be initialized.
* Always logs even if Debugging is not enabled.
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
* Normally this method should not be used.
*/
public static void initializationError(@NonNull Class<?> callingClass, @NonNull String message, @Nullable Exception ex) {
public static void initializationInfo(@NonNull Class<?> callingClass, @NonNull String message) {
Log.i(REVANCED_LOG_PREFIX + callingClass.getSimpleName(), message);
}
/**
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
* Normally this method should not be used.
*/
public static void initializationException(@NonNull Class<?> callingClass, @NonNull String message,
@Nullable Exception ex) {
Log.e(REVANCED_LOG_PREFIX + callingClass.getSimpleName(), message, ex);
}

View File

@@ -40,7 +40,7 @@ import kotlin.text.Regex;
public class Utils {
@SuppressLint("StaticFieldLeak")
public static Context context;
private static Context context;
private static String versionName;
@@ -54,13 +54,14 @@ public class Utils {
try {
final var packageName = Objects.requireNonNull(getContext()).getPackageName();
PackageManager packageManager = context.getPackageManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
packageInfo = context.getPackageManager().getPackageInfo(
packageInfo = packageManager.getPackageInfo(
packageName,
PackageManager.PackageInfoFlags.of(0)
);
else
packageInfo = context.getPackageManager().getPackageInfo(
packageInfo = packageManager.getPackageInfo(
packageName,
0
);
@@ -195,18 +196,29 @@ public class Utils {
return getContext().getResources().getDimension(getResourceIdentifier(resourceIdentifierName, "dimen"));
}
public interface MatchFilter<T> {
boolean matches(T object);
}
/**
* @param searchRecursively If children ViewGroups should also be
* recursively searched using depth first search.
* @return The first child view that matches the filter.
*/
@Nullable
public static <T extends View> T getChildView(@NonNull ViewGroup viewGroup, @NonNull MatchFilter filter) {
public static <T extends View> T getChildView(@NonNull ViewGroup viewGroup, boolean searchRecursively,
@NonNull MatchFilter<View> filter) {
for (int i = 0, childCount = viewGroup.getChildCount(); i < childCount; i++) {
View childAt = viewGroup.getChildAt(i);
//noinspection unchecked
if (filter.matches(childAt)) {
//noinspection unchecked
return (T) childAt;
}
// Must do recursive after filter check, in case the filter is looking for a ViewGroup.
if (searchRecursively && childAt instanceof ViewGroup) {
T match = getChildView((ViewGroup) childAt, true, filter);
if (match != null) return match;
}
}
return null;
}
@@ -222,17 +234,27 @@ public class Utils {
System.exit(0);
}
public interface MatchFilter<T> {
boolean matches(T object);
}
public static Context getContext() {
if (context == null) {
Logger.initializationError(Utils.class, "Context is null, returning null!", null);
Logger.initializationException(Utils.class, "Context is null, returning null!", null);
}
return context;
}
public static void setContext(Context appContext) {
context = appContext;
// In some apps like TikTok, the Setting classes can load in weird orders due to cyclic class dependencies.
// Calling the regular printDebug method here can cause a Settings context null pointer exception,
// even though the context is already set before the call.
//
// The initialization logger methods do not directly or indirectly
// reference the Context or any Settings and are unaffected by this problem.
//
// Info level also helps debug if a patch hook is called before
// the context is set since debug logging is off by default.
Logger.initializationInfo(Utils.class, "Set context: " + appContext);
}
public static void setClipboard(@NonNull String text) {
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
android.content.ClipData clip = android.content.ClipData.newPlainText("ReVanced", text);
@@ -275,7 +297,7 @@ public class Utils {
Objects.requireNonNull(messageToToast);
runOnMainThreadNowOrLater(() -> {
if (context == null) {
Logger.initializationError(Utils.class, "Cannot show toast (context is null): " + messageToToast, null);
Logger.initializationException(Utils.class, "Cannot show toast (context is null): " + messageToToast, null);
} else {
Logger.printDebug(() -> "Showing toast: " + messageToToast);
Toast.makeText(context, messageToToast, toastDuration).show();

View File

@@ -152,47 +152,60 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
}
/**
* Updates a UI Preference with the {@link Setting} that backs it.
* Handles syncing a UI Preference with the {@link Setting} that backs it.
* If needed, subclasses can override this to handle additional UI Preference types.
*
* @param applySettingToPreference If true, then apply {@link Setting} -> Preference.
* If false, then apply {@link Setting} <- Preference.
*/
protected void syncSettingWithPreference(@NonNull Preference pref,
@NonNull Setting<?> setting,
boolean applySettingToPreference) {
if (pref instanceof SwitchPreference) {
SwitchPreference switchPref = (SwitchPreference) pref;
BooleanSetting boolSetting = (BooleanSetting) setting;
if (applySettingToPreference) {
switchPref.setChecked(boolSetting.get());
} else {
BooleanSetting.privateSetValue(boolSetting, switchPref.isChecked());
}
} else if (pref instanceof EditTextPreference) {
EditTextPreference editPreference = (EditTextPreference) pref;
if (applySettingToPreference) {
editPreference.setText(setting.get().toString());
} else {
Setting.privateSetValueFromString(setting, editPreference.getText());
}
} else if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
if (applySettingToPreference) {
listPref.setValue(setting.get().toString());
} else {
Setting.privateSetValueFromString(setting, listPref.getValue());
}
updateListPreferenceSummary(listPref, setting);
} else {
Logger.printException(() -> "Setting cannot be handled: " + pref.getClass() + ": " + pref);
}
}
/**
* Updates a UI Preference with the {@link Setting} that backs it.
*
* @param syncSetting If the UI should be synced {@link Setting} <-> Preference
* @param applySettingToPreference If true, then apply {@link Setting} -> Preference.
* If false, then apply {@link Setting} <- Preference.
*/
protected void updatePreference(@NonNull Preference pref, @NonNull Setting<?> setting,
boolean syncSetting, boolean applySettingToPreference) {
private void updatePreference(@NonNull Preference pref, @NonNull Setting<?> setting,
boolean syncSetting, boolean applySettingToPreference) {
if (!syncSetting && applySettingToPreference) {
throw new IllegalArgumentException();
}
if (syncSetting) {
if (pref instanceof SwitchPreference) {
SwitchPreference switchPref = (SwitchPreference) pref;
BooleanSetting boolSetting = (BooleanSetting) setting;
if (applySettingToPreference) {
switchPref.setChecked(boolSetting.get());
} else {
BooleanSetting.privateSetValue(boolSetting, switchPref.isChecked());
}
} else if (pref instanceof EditTextPreference) {
EditTextPreference editPreference = (EditTextPreference) pref;
if (applySettingToPreference) {
editPreference.setText(setting.get().toString());
} else {
Setting.privateSetValueFromString(setting, editPreference.getText());
}
} else if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
if (applySettingToPreference) {
listPref.setValue(setting.get().toString());
} else {
Setting.privateSetValueFromString(setting, listPref.getValue());
}
updateListPreferenceSummary(listPref, setting);
} else {
Logger.printException(() -> "Setting cannot be handled: " + pref.getClass() + ": " + pref);
return;
}
syncSettingWithPreference(pref, setting, applySettingToPreference);
}
updatePreferenceAvailability(pref, setting);
}

View File

@@ -1,11 +1,15 @@
package app.revanced.integrations.tiktok.settings.preference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import androidx.annotation.NonNull;
import app.revanced.integrations.shared.settings.Setting;
import app.revanced.integrations.shared.settings.preference.AbstractPreferenceFragment;
import app.revanced.integrations.tiktok.settings.preference.categories.DownloadsPreferenceCategory;
import app.revanced.integrations.tiktok.settings.preference.categories.FeedFilterPreferenceCategory;
import app.revanced.integrations.tiktok.settings.preference.categories.IntegrationsPreferenceCategory;
import app.revanced.integrations.tiktok.settings.preference.categories.SimSpoofPreferenceCategory;
import org.jetbrains.annotations.NotNull;
/**
* Preference fragment for ReVanced settings
@@ -13,6 +17,21 @@ import app.revanced.integrations.tiktok.settings.preference.categories.SimSpoofP
@SuppressWarnings("deprecation")
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
@Override
protected void syncSettingWithPreference(@NonNull @NotNull Preference pref,
@NonNull @NotNull Setting<?> setting,
boolean applySettingToPreference) {
if (pref instanceof RangeValuePreference) {
RangeValuePreference rangeValuePref = (RangeValuePreference) pref;
Setting.privateSetValueFromString(setting, rangeValuePref.getValue());
} else if (pref instanceof DownloadPathPreference) {
DownloadPathPreference downloadPathPref = (DownloadPathPreference) pref;
Setting.privateSetValueFromString(setting, downloadPathPref.getValue());
} else {
super.syncSettingWithPreference(pref, setting, applySettingToPreference);
}
}
@Override
protected void initialize() {
final var context = getContext();

View File

@@ -1,32 +1,37 @@
package app.revanced.integrations.tiktok.spoof.sim;
import app.revanced.integrations.shared.Logger;
import app.revanced.integrations.tiktok.settings.Settings;
@SuppressWarnings("unused")
public class SpoofSimPatch {
public static boolean isEnable() {
return Settings.SIM_SPOOF.get();
}
public static String getCountryIso(String value) {
if (isEnable()) {
return Settings.SIM_SPOOF_ISO.get();
} else {
return value;
}
private static final Boolean ENABLED = Settings.SIM_SPOOF.get();
public static String getCountryIso(String value) {
if (ENABLED) {
String iso = Settings.SIM_SPOOF_ISO.get();
Logger.printDebug(() -> "Spoofing sim ISO from: " + value + " to: " + iso);
return iso;
}
return value;
}
public static String getOperator(String value) {
if (isEnable()) {
return Settings.SIMSPOOF_MCCMNC.get();
} else {
return value;
if (ENABLED) {
String mcc_mnc = Settings.SIMSPOOF_MCCMNC.get();
Logger.printDebug(() -> "Spoofing sim MCC-MNC from: " + value + " to: " + mcc_mnc);
return mcc_mnc;
}
return value;
}
public static String getOperatorName(String value) {
if (isEnable()) {
return Settings.SIMSPOOF_OP_NAME.get();
} else {
return value;
if (ENABLED) {
String operator = Settings.SIMSPOOF_OP_NAME.get();
Logger.printDebug(() -> "Spoofing sim operator from: " + value + " to: " + operator);
return operator;
}
return value;
}
}

View File

@@ -6,4 +6,4 @@ abstract class BaseJsonHook : JsonHook {
abstract fun apply(json: JSONObject)
override fun transform(json: JSONObject) = json.apply { apply(json) }
}
}

View File

@@ -12,4 +12,4 @@ interface JsonHook : Hook<JSONObject> {
fun transform(json: JSONObject): JSONObject
override fun hook(type: JSONObject) = transform(type)
}
}

View File

@@ -27,4 +27,4 @@ object JsonHookPatch {
return StreamUtils.fromString(jsonObject.toString())
}
}
}

View File

@@ -6,4 +6,4 @@ interface Hook<T> {
* @param type The type to hook
*/
fun hook(type: T): T
}
}

View File

@@ -4,7 +4,6 @@ import app.revanced.integrations.twitter.patches.hook.json.BaseJsonHook
import app.revanced.integrations.twitter.patches.hook.twifucker.TwiFucker
import org.json.JSONObject
object AdsHook : BaseJsonHook() {
/**
* Strips JSONObject from promoted ads.
@@ -12,4 +11,4 @@ object AdsHook : BaseJsonHook() {
* @param json The JSONObject.
*/
override fun apply(json: JSONObject) = TwiFucker.hidePromotedAds(json)
}
}

View File

@@ -11,4 +11,4 @@ object DummyHook : BaseJsonHook() {
override fun apply(json: JSONObject) {
// Do nothing.
}
}
}

View File

@@ -4,7 +4,6 @@ import app.revanced.integrations.twitter.patches.hook.json.BaseJsonHook
import app.revanced.integrations.twitter.patches.hook.twifucker.TwiFucker
import org.json.JSONObject
object RecommendedUsersHook : BaseJsonHook() {
/**
* Strips JSONObject from recommended users.
@@ -12,4 +11,4 @@ object RecommendedUsersHook : BaseJsonHook() {
* @param json The JSONObject.
*/
override fun apply(json: JSONObject) = TwiFucker.hideRecommendedUsers(json)
}
}

View File

@@ -2,9 +2,12 @@ package app.revanced.integrations.twitter.patches.links;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public final class OpenLinksWithAppChooserPatch {
public static void openWithChooser(final Context context, final Intent intent) {
Log.d("ReVanced", "Opening intent with chooser: " + intent);
intent.setAction("android.intent.action.VIEW");
context.startActivity(Intent.createChooser(intent, null));

View File

@@ -10,4 +10,4 @@ object JsonUtils {
@JvmStatic
@Throws(IOException::class, JSONException::class)
fun parseJson(jsonInputStream: InputStream) = JSONObject(StreamUtils.toString(jsonInputStream))
}
}

View File

@@ -21,4 +21,4 @@ object StreamUtils {
fun fromString(string: String): InputStream {
return ByteArrayInputStream(string.toByteArray())
}
}
}

View File

@@ -1,5 +1,9 @@
package app.revanced.integrations.youtube;
import androidx.annotation.NonNull;
import java.nio.charset.StandardCharsets;
public final class ByteTrieSearch extends TrieSearch<byte[]> {
private static final class ByteTrieNode extends TrieNode<byte[]> {
@@ -24,18 +28,18 @@ public final class ByteTrieSearch extends TrieSearch<byte[]> {
}
/**
* @return If the pattern is valid to add to this instance.
* Helper method for the common usage of converting Strings to raw UTF-8 bytes.
*/
public static boolean isValidPattern(byte[] pattern) {
for (byte b : pattern) {
if (TrieNode.isInvalidRange((char) b)) {
return false;
}
public static byte[][] convertStringsToBytes(String... strings) {
final int length = strings.length;
byte[][] replacement = new byte[length][];
for (int i = 0; i < length; i++) {
replacement[i] = strings[i].getBytes(StandardCharsets.UTF_8);
}
return true;
return replacement;
}
public ByteTrieSearch() {
super(new ByteTrieNode());
public ByteTrieSearch(@NonNull byte[]... patterns) {
super(new ByteTrieNode(), patterns);
}
}

View File

@@ -27,4 +27,3 @@ class Event<T> {
observer.invoke(value)
}
}

View File

@@ -1,5 +1,7 @@
package app.revanced.integrations.youtube;
import androidx.annotation.NonNull;
/**
* Text pattern searching using a prefix tree (trie).
*/
@@ -26,19 +28,7 @@ public final class StringTrieSearch extends TrieSearch<String> {
}
}
/**
* @return If the pattern is valid to add to this instance.
*/
public static boolean isValidPattern(String pattern) {
for (int i = 0, length = pattern.length(); i < length; i++) {
if (TrieNode.isInvalidRange(pattern.charAt(i))) {
return false;
}
}
return true;
}
public StringTrieSearch() {
super(new StringTrieNode());
public StringTrieSearch(@NonNull String... patterns) {
super(new StringTrieNode(), patterns);
}
}

View File

@@ -11,9 +11,6 @@ import java.util.Objects;
/**
* Searches for a group of different patterns using a trie (prefix tree).
* Can significantly speed up searching for multiple patterns.
*
* Currently only supports ASCII non-control characters (letters/numbers/symbols).
* But could be modified to also support UTF-8 unicode.
*/
public abstract class TrieSearch<T> {
@@ -45,14 +42,14 @@ public abstract class TrieSearch<T> {
*/
private static final class TrieCompressedPath<T> {
final T pattern;
final int patternLength;
final int patternStartIndex;
final int patternLength;
final TriePatternMatchedCallback<T> callback;
TrieCompressedPath(T pattern, int patternLength, int patternStartIndex, TriePatternMatchedCallback<T> callback) {
TrieCompressedPath(T pattern, int patternStartIndex, int patternLength, TriePatternMatchedCallback<T> callback) {
this.pattern = pattern;
this.patternLength = patternLength;
this.patternStartIndex = patternStartIndex;
this.patternLength = patternLength;
this.callback = callback;
}
boolean matches(TrieNode<T> enclosingNode, // Used only for the get character method.
@@ -76,19 +73,10 @@ public abstract class TrieSearch<T> {
*/
private static final char ROOT_NODE_CHARACTER_VALUE = 0; // ASCII null character.
// Support only ASCII letters/numbers/symbols and filter out all control characters.
private static final char MIN_VALID_CHAR = 32; // Space character.
private static final char MAX_VALID_CHAR = 126; // 127 = delete character.
/**
* How much to expand the children array when resizing.
*/
private static final int CHILDREN_ARRAY_INCREASE_SIZE_INCREMENT = 2;
private static final int CHILDREN_ARRAY_MAX_SIZE = MAX_VALID_CHAR - MIN_VALID_CHAR + 1;
static boolean isInvalidRange(char character) {
return character < MIN_VALID_CHAR || character > MAX_VALID_CHAR;
}
/**
* Character this node represents.
@@ -144,11 +132,11 @@ public abstract class TrieSearch<T> {
/**
* @param pattern Pattern to add.
* @param patternLength Length of the pattern.
* @param patternIndex Current recursive index of the pattern.
* @param patternLength Length of the pattern.
* @param callback Callback, where a value of NULL indicates to always accept a pattern match.
*/
private void addPattern(@NonNull T pattern, int patternLength, int patternIndex,
private void addPattern(@NonNull T pattern, int patternIndex, int patternLength,
@Nullable TriePatternMatchedCallback<T> callback) {
if (patternIndex == patternLength) { // Reached the end of the pattern.
if (endOfPatternCallback == null) {
@@ -165,16 +153,13 @@ public abstract class TrieSearch<T> {
children = new TrieNode[1];
TrieCompressedPath<T> temp = leaf;
leaf = null;
addPattern(temp.pattern, temp.patternLength, temp.patternStartIndex, temp.callback);
addPattern(temp.pattern, temp.patternStartIndex, temp.patternLength, temp.callback);
// Continue onward and add the parameter pattern.
} else if (children == null) {
leaf = new TrieCompressedPath<>(pattern, patternLength, patternIndex, callback);
leaf = new TrieCompressedPath<>(pattern, patternIndex, patternLength, callback);
return;
}
final char character = getCharValue(pattern, patternIndex);
if (isInvalidRange(character)) {
throw new IllegalArgumentException("invalid character at index " + patternIndex + ": " + pattern);
}
final int arrayIndex = hashIndexForTableSize(children.length, character);
TrieNode<T> child = children[arrayIndex];
if (child == null) {
@@ -185,12 +170,11 @@ public abstract class TrieSearch<T> {
child = createNode(character);
expandChildArray(child);
}
child.addPattern(pattern, patternLength, patternIndex + 1, callback);
child.addPattern(pattern, patternIndex + 1, patternLength, callback);
}
/**
* Resizes the children table until all nodes hash to exactly one array index.
* Worse case, this will resize the array to {@link #CHILDREN_ARRAY_MAX_SIZE} elements.
*/
private void expandChildArray(TrieNode<T> child) {
int replacementArraySize = Objects.requireNonNull(children).length;
@@ -209,7 +193,6 @@ public abstract class TrieSearch<T> {
}
}
if (collision) {
if (replacementArraySize > CHILDREN_ARRAY_MAX_SIZE) throw new IllegalStateException();
continue;
}
children = replacement;
@@ -232,22 +215,23 @@ public abstract class TrieSearch<T> {
/**
* This method is static and uses a loop to avoid all recursion.
* This is done for performance since the JVM does not do tail recursion optimization.
* This is done for performance since the JVM does not optimize tail recursion.
*
* @param startNode Node to start the search from.
* @param searchText Text to search for patterns in.
* @param searchTextLength Length of the search text.
* @param searchTextIndex Current recursive search text index. Also, the end index of the current pattern match.
* @param searchTextIndex Start index, inclusive.
* @param searchTextEndIndex End index, exclusive.
* @return If any pattern matches, and it's associated callback halted the search.
*/
private static <T> boolean matches(final TrieNode<T> startNode, final T searchText, final int searchTextLength,
int searchTextIndex, final Object callbackParameter) {
private static <T> boolean matches(final TrieNode<T> startNode, final T searchText,
int searchTextIndex, final int searchTextEndIndex,
final Object callbackParameter) {
TrieNode<T> node = startNode;
int currentMatchLength = 0;
while (true) {
TrieCompressedPath<T> leaf = node.leaf;
if (leaf != null && leaf.matches(node, searchText, searchTextLength, searchTextIndex, callbackParameter)) {
if (leaf != null && leaf.matches(startNode, searchText, searchTextEndIndex, searchTextIndex, callbackParameter)) {
return true; // Leaf exists and it matched the search text.
}
List<TriePatternMatchedCallback<T>> endOfPatternCallback = node.endOfPatternCallback;
@@ -266,7 +250,7 @@ public abstract class TrieSearch<T> {
if (children == null) {
return false; // Reached a graph end point and there's no further patterns to search.
}
if (searchTextIndex == searchTextLength) {
if (searchTextIndex == searchTextEndIndex) {
return false; // Reached end of the search text and found no matches.
}
@@ -323,8 +307,10 @@ public abstract class TrieSearch<T> {
*/
private final List<T> patterns = new ArrayList<>();
TrieSearch(@NonNull TrieNode<T> root) {
@SafeVarargs
TrieSearch(@NonNull TrieNode<T> root, @NonNull T... patterns) {
this.root = Objects.requireNonNull(root);
addPatterns(patterns);
}
@SafeVarargs
@@ -355,7 +341,7 @@ public abstract class TrieSearch<T> {
if (patternLength == 0) return; // Nothing to match
patterns.add(pattern);
root.addPattern(pattern, patternLength, 0, callback);
root.addPattern(pattern, 0, patternLength, callback);
}
public final boolean matches(@NonNull T textToSearch) {
@@ -398,7 +384,7 @@ public abstract class TrieSearch<T> {
return false; // No patterns were added.
}
for (int i = startIndex; i < endIndex; i++) {
if (TrieNode.matches(root, textToSearch, endIndex, i, callbackParameter)) return true;
if (TrieNode.matches(root, textToSearch, i, endIndex, callbackParameter)) return true;
}
return false;
}

View File

@@ -0,0 +1,103 @@
package app.revanced.integrations.youtube.patches;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import java.lang.ref.WeakReference;
import java.util.Objects;
import app.revanced.integrations.shared.Logger;
import app.revanced.integrations.shared.StringRef;
import app.revanced.integrations.shared.Utils;
import app.revanced.integrations.youtube.settings.Settings;
@SuppressWarnings("unused")
public final class DownloadsPatch {
private static WeakReference<Activity> activityRef = new WeakReference<>(null);
/**
* Injection point.
*/
public static void activityCreated(Activity mainActivity) {
activityRef = new WeakReference<>(mainActivity);
}
/**
* Injection point.
*
* Called from the in app download hook,
* for both the player action button (below the video)
* and the 'Download video' flyout option for feed videos.
*
* Appears to always be called from the main thread.
*/
public static boolean inAppDownloadButtonOnClick(@NonNull String videoId) {
try {
if (!Settings.EXTERNAL_DOWNLOADER_ACTION_BUTTON.get()) {
return false;
}
// If possible, use the main activity as the context.
// Otherwise fall back on using the application context.
Context context = activityRef.get();
boolean isActivityContext = true;
if (context == null) {
// Utils context is the application context, and not an activity context.
context = Utils.getContext();
isActivityContext = false;
}
launchExternalDownloader(videoId, context, isActivityContext);
return true;
} catch (Exception ex) {
Logger.printException(() -> "inAppDownloadButtonOnClick failure", ex);
}
return false;
}
/**
* @param isActivityContext If the context parameter is for an Activity. If this is false, then
* the downloader is opened as a new task (which forces YT to minimize).
*/
public static void launchExternalDownloader(@NonNull String videoId,
@NonNull Context context, boolean isActivityContext) {
try {
Objects.requireNonNull(videoId);
Logger.printDebug(() -> "Launching external downloader with context: " + context);
// Trim string to avoid any accidental whitespace.
var downloaderPackageName = Settings.EXTERNAL_DOWNLOADER_PACKAGE_NAME.get().trim();
boolean packageEnabled = false;
try {
packageEnabled = context.getPackageManager().getApplicationInfo(downloaderPackageName, 0).enabled;
} catch (PackageManager.NameNotFoundException error) {
Logger.printDebug(() -> "External downloader could not be found: " + error);
}
// If the package is not installed, show the toast
if (!packageEnabled) {
Utils.showToastLong(StringRef.str("revanced_external_downloader_not_installed_warning", downloaderPackageName));
return;
}
String content = "https://youtu.be/" + videoId;
Intent intent = new Intent("android.intent.action.SEND");
intent.setType("text/plain");
intent.setPackage(downloaderPackageName);
intent.putExtra("android.intent.extra.TEXT", content);
if (!isActivityContext) {
Logger.printDebug(() -> "Using new task intent");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
} catch (Exception ex) {
Logger.printException(() -> "launchExternalDownloader failure", ex);
}
}
}

View File

@@ -1,20 +1,18 @@
package app.revanced.integrations.youtube.patches;
import static app.revanced.integrations.shared.StringRef.str;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import androidx.annotation.RequiresApi;
import app.revanced.integrations.shared.Logger;
import app.revanced.integrations.shared.Utils;
import java.util.Objects;
import app.revanced.integrations.shared.Logger;
import app.revanced.integrations.shared.Utils;
import static app.revanced.integrations.shared.StringRef.str;
/**
* @noinspection unused
@@ -61,9 +59,8 @@ public class GmsCoreSupport {
private static String getGmsCoreDownloadLink() {
final var vendor = getGmsCoreVendor();
//noinspection SwitchStatementWithTooFewBranches
switch (vendor) {
case "com.mgoogle":
return "https://github.com/TeamVanced/VancedMicroG/releases/latest";
case "app.revanced":
return "https://github.com/revanced/gmscore/releases/latest";
default:

View File

@@ -6,8 +6,12 @@ import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.swipecontrols.SwipeControlsHostActivity;
/**
* Patch class for 'hdr-auto-brightness' patch
* Patch class for 'hdr-auto-brightness' patch.
*
* Edit: This patch no longer does anything, as YT already uses BRIGHTNESS_OVERRIDE_NONE
* as the default brightness level. The hooked code was also removed from YT 19.09+ as well.
*/
@Deprecated
@SuppressWarnings("unused")
public class HDRAutoBrightnessPatch {
/**

View File

@@ -16,7 +16,7 @@ public class HideBreakingNewsPatch {
* Breaking news does not appear to be present in these older versions anyways.
*/
private static final boolean isSpoofingOldVersionWithHorizontalCardListWatchHistory =
SpoofAppVersionPatch.isSpoofingToEqualOrLessThan("17.31.00");
SpoofAppVersionPatch.isSpoofingToLessThan("18.01.00");
/**
* Injection point.

View File

@@ -1,40 +1,41 @@
package app.revanced.integrations.youtube.patches;
import static app.revanced.integrations.youtube.shared.NavigationBar.NavigationButton;
import android.view.View;
import java.util.EnumMap;
import java.util.Map;
import app.revanced.integrations.youtube.settings.Settings;
@SuppressWarnings("unused")
public final class NavigationButtonsPatch {
public static Enum lastNavigationButton;
public static void hideCreateButton(final View view) {
view.setVisibility(Settings.HIDE_CREATE_BUTTON.get() ? View.GONE : View.VISIBLE);
}
private static final Map<NavigationButton, Boolean> shouldHideMap = new EnumMap<>(NavigationButton.class) {
{
put(NavigationButton.HOME, Settings.HIDE_HOME_BUTTON.get());
put(NavigationButton.CREATE, Settings.HIDE_CREATE_BUTTON.get());
put(NavigationButton.SHORTS, Settings.HIDE_SHORTS_BUTTON.get());
}
};
private static final Boolean SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON
= Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get();
/**
* Injection point.
*/
public static boolean switchCreateWithNotificationButton() {
return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get();
return SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON;
}
public static void hideButton(final View buttonView) {
if (lastNavigationButton == null) return;
for (NavigationButton button : NavigationButton.values())
if (button.name.equals(lastNavigationButton.name()))
if (button.enabled) buttonView.setVisibility(View.GONE);
}
private enum NavigationButton {
HOME("PIVOT_HOME", Settings.HIDE_HOME_BUTTON.get()),
SHORTS("TAB_SHORTS", Settings.HIDE_SHORTS_BUTTON.get()),
SUBSCRIPTIONS("PIVOT_SUBSCRIPTIONS", Settings.HIDE_SUBSCRIPTIONS_BUTTON.get());
private final boolean enabled;
private final String name;
NavigationButton(final String name, final boolean enabled) {
this.name = name;
this.enabled = enabled;
/**
* Injection point.
*/
public static void navigationTabCreated(NavigationButton button, View tabView) {
if (Boolean.TRUE.equals(shouldHideMap.get(button))) {
tabView.setVisibility(View.GONE);
}
}
}

View File

@@ -6,24 +6,12 @@ import androidx.annotation.Nullable;
import app.revanced.integrations.youtube.shared.PlayerOverlays;
/**
* Hook receiver class for 'player-overlays-hook' patch
*
* @usedBy app.revanced.patches.youtube.misc.playeroverlay.patch.PlayerOverlaysHookPatch
* @smali Lapp/revanced/integrations/patches/PlayerOverlaysHookPatch;
*/
@SuppressWarnings("unused")
public class PlayerOverlaysHookPatch {
/**
* Injection point.
*
* @param thisRef reference to the view
* @smali YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava / lang / Object ;)V
*/
public static void YouTubePlayerOverlaysLayout_onFinishInflateHook(@Nullable Object thisRef) {
if (thisRef == null) return;
if (thisRef instanceof ViewGroup) {
PlayerOverlays.attach((ViewGroup) thisRef);
}
public static void playerOverlayInflated(ViewGroup group) {
PlayerOverlays.attach(group);
}
}

View File

@@ -46,7 +46,7 @@ import static app.revanced.integrations.youtube.returnyoutubedislike.ReturnYouTu
public class ReturnYouTubeDislikePatch {
public static final boolean IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER =
SpoofAppVersionPatch.isSpoofingToEqualOrLessThan("18.33.40");
SpoofAppVersionPatch.isSpoofingToLessThan("18.34.00");
/**
* RYD data for the current video on screen.

View File

@@ -18,7 +18,6 @@ import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Locale;
import java.util.UUID;
import static android.text.Html.FROM_HTML_MODE_COMPACT;
import static app.revanced.integrations.shared.StringRef.str;
@@ -26,8 +25,6 @@ import static app.revanced.integrations.youtube.patches.announcements.requests.A
@SuppressWarnings("unused")
public final class AnnouncementsPatch {
private final static String CONSUMER = getOrSetConsumer();
private AnnouncementsPatch() {
}
@@ -41,7 +38,7 @@ public final class AnnouncementsPatch {
Utils.runOnBackgroundThread(() -> {
try {
HttpURLConnection connection = AnnouncementsRoutes.getAnnouncementsConnectionFromRoute(
GET_LATEST_ANNOUNCEMENT, CONSUMER, Locale.getDefault().toLanguageTag());
GET_LATEST_ANNOUNCEMENT, Locale.getDefault().toLanguageTag());
Logger.printDebug(() -> "Get latest announcement route connection url: " + connection.getURL());
@@ -139,15 +136,6 @@ public final class AnnouncementsPatch {
});
}
private static String getOrSetConsumer() {
final var consumer = Settings.ANNOUNCEMENT_CONSUMER.get();
if (!consumer.isEmpty()) return consumer;
final var uuid = UUID.randomUUID().toString();
Settings.ANNOUNCEMENT_CONSUMER.save(uuid);
return uuid;
}
// TODO: Use better icons.
private enum Level {
INFO(android.R.drawable.ic_dialog_info),

View File

@@ -14,7 +14,7 @@ public class AnnouncementsRoutes {
/**
* 'language' parameter is IETF format (for USA it would be 'en-us').
*/
public static final Route GET_LATEST_ANNOUNCEMENT = new Route(GET, "/announcements/youtube/latest?consumer={consumer}&language={language}");
public static final Route GET_LATEST_ANNOUNCEMENT = new Route(GET, "/announcements/youtube/latest?language={language}");
private AnnouncementsRoutes() {
}

View File

@@ -1,5 +1,7 @@
package app.revanced.integrations.youtube.patches.components;
import static app.revanced.integrations.shared.StringRef.str;
import android.app.Instrumentation;
import android.view.KeyEvent;
import android.view.View;
@@ -170,7 +172,24 @@ public final class AdsFilter extends Filter {
Utils.runOnMainThreadDelayed(() -> {
// Must run off main thread (Odd, but whatever).
Utils.runOnBackgroundThread(() -> instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK));
Utils.runOnBackgroundThread(() -> {
try {
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
} catch (Exception ex) {
// Injecting user events on Android 10+ requires the manifest to include
// INJECT_EVENTS, and it's usage is heavily restricted
// and requires the user to manually approve the permission in the device settings.
//
// And no matter what, permissions cannot be added for root installations
// as manifest changes are ignored for mount installations.
//
// Instead, catch the SecurityException and turn off hide full screen ads
// since this functionality does not work for these devices.
Logger.printInfo(() -> "Could not inject back button event", ex);
Settings.HIDE_FULLSCREEN_ADS.save(false);
Utils.showToastLong(str("revanced_hide_fullscreen_ads_feature_not_available_toast"));
}
});
}, 1000);
}
}

View File

@@ -17,7 +17,6 @@ import java.util.regex.Pattern;
import app.revanced.integrations.shared.Logger;
import app.revanced.integrations.shared.Utils;
import app.revanced.integrations.youtube.ByteTrieSearch;
import app.revanced.integrations.youtube.StringTrieSearch;
import app.revanced.integrations.youtube.settings.Settings;
/**
@@ -30,10 +29,6 @@ final class CustomFilter extends Filter {
Utils.showToastLong(str("revanced_custom_filter_toast_invalid_syntax", expression));
}
private static void showInvalidCharactersToast(@NonNull String expression) {
Utils.showToastLong(str("revanced_custom_filter_toast_invalid_characters", expression));
}
private static class CustomFilterGroup extends StringFilterGroup {
/**
* Optional character for the path that indicates the custom filter path must match the start.
@@ -73,7 +68,7 @@ final class CustomFilter extends Filter {
Matcher matcher = pattern.matcher(expression);
if (!matcher.find()) {
showInvalidSyntaxToast(expression);
return null;
continue;
}
final String mapKey = matcher.group(1);
@@ -84,13 +79,7 @@ final class CustomFilter extends Filter {
if (path.isBlank() || (hasBufferSymbol && bufferString.isBlank())) {
showInvalidSyntaxToast(expression);
return null;
}
if (!StringTrieSearch.isValidPattern(path)
|| (hasBufferSymbol && !StringTrieSearch.isValidPattern(bufferString))) {
// Currently only ASCII is allowed.
showInvalidCharactersToast(path);
return null;
continue;
}
// Use one group object for all expressions with the same path.
@@ -149,11 +138,6 @@ final class CustomFilter extends Filter {
public CustomFilter() {
Collection<CustomFilterGroup> groups = CustomFilterGroup.parseCustomFilterGroups();
if (groups == null) {
Settings.CUSTOM_FILTER_STRINGS.resetToDefault();
Utils.showToastLong(str("revanced_custom_filter_toast_reset"));
groups = Objects.requireNonNull(CustomFilterGroup.parseCustomFilterGroups());
}
if (!groups.isEmpty()) {
CustomFilterGroup[] groupsArray = groups.toArray(new CustomFilterGroup[0]);

Some files were not shown because too many files have changed in this diff Show More