You've already forked revanced-integrations
mirror of
https://github.com/revanced/revanced-integrations
synced 2025-11-21 18:35:37 +01:00
Compare commits
34 Commits
v1.4.1-dev
...
v1.5.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
910b03e9a3 | ||
|
|
0cbad98205 | ||
|
|
6e947e24c2 | ||
|
|
96a1e4680d | ||
|
|
46d8ef6f88 | ||
|
|
b7a8995f79 | ||
|
|
59165de801 | ||
|
|
2a08e5a98e | ||
|
|
b945e2f44b | ||
|
|
bed8f9f640 | ||
|
|
32a14efe6f | ||
|
|
4ec955fd01 | ||
|
|
f47495ccd8 | ||
|
|
9ac2d63489 | ||
|
|
74b6ab8712 | ||
|
|
ad477e4859 | ||
|
|
6f1ac5d073 | ||
|
|
254da31d16 | ||
|
|
7c40c947ef | ||
|
|
4be65be414 | ||
|
|
b060732e86 | ||
|
|
da8ec49589 | ||
|
|
b9c1eec69f | ||
|
|
d6032216e4 | ||
|
|
468dfac054 | ||
|
|
75a494e09b | ||
|
|
771a0de3bc | ||
|
|
6aacd1a225 | ||
|
|
8d48a90a8b | ||
|
|
6188fa75c6 | ||
|
|
ab07a563b9 | ||
|
|
c7ae3355a1 | ||
|
|
eee3f352c5 | ||
|
|
36aa6c9aa8 |
3
.editorconfig
Normal file
3
.editorconfig
Normal file
@@ -0,0 +1,3 @@
|
||||
[*.{kt,kts}]
|
||||
ktlint_code_style = intellij_idea
|
||||
ktlint_standard_no-wildcard-imports = disabled
|
||||
95
CHANGELOG.md
95
CHANGELOG.md
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ abstract class BaseJsonHook : JsonHook {
|
||||
abstract fun apply(json: JSONObject)
|
||||
|
||||
override fun transform(json: JSONObject) = json.apply { apply(json) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ interface JsonHook : Hook<JSONObject> {
|
||||
fun transform(json: JSONObject): JSONObject
|
||||
|
||||
override fun hook(type: JSONObject) = transform(type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,4 @@ object JsonHookPatch {
|
||||
|
||||
return StreamUtils.fromString(jsonObject.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ interface Hook<T> {
|
||||
* @param type The type to hook
|
||||
*/
|
||||
fun hook(type: T): T
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ object DummyHook : BaseJsonHook() {
|
||||
override fun apply(json: JSONObject) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -10,4 +10,4 @@ object JsonUtils {
|
||||
@JvmStatic
|
||||
@Throws(IOException::class, JSONException::class)
|
||||
fun parseJson(jsonInputStream: InputStream) = JSONObject(StreamUtils.toString(jsonInputStream))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ object StreamUtils {
|
||||
fun fromString(string: String): InputStream {
|
||||
return ByteArrayInputStream(string.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,3 @@ class Event<T> {
|
||||
observer.invoke(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user