mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-31 14:41:03 +00:00
Merge remote-tracking branch 'upstream/dev' into feat/patcher_instruction_filters
# Conflicts: # patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt # patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt # patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package app.revanced.extension.shared.patches;
|
||||
|
||||
import static app.revanced.extension.shared.StringRef.str;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.text.Html;
|
||||
import android.util.Pair;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.ui.CustomDialog;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class CheckWatchHistoryDomainNameResolutionPatch {
|
||||
|
||||
private static final String HISTORY_TRACKING_ENDPOINT = "s.youtube.com";
|
||||
|
||||
private static final String SINKHOLE_IPV4 = "0.0.0.0";
|
||||
private static final String SINKHOLE_IPV6 = "::";
|
||||
|
||||
private static boolean domainResolvesToValidIP(String host) {
|
||||
try {
|
||||
InetAddress address = InetAddress.getByName(host);
|
||||
String hostAddress = address.getHostAddress();
|
||||
|
||||
if (address.isLoopbackAddress()) {
|
||||
Logger.printDebug(() -> host + " resolves to localhost");
|
||||
} else if (SINKHOLE_IPV4.equals(hostAddress) || SINKHOLE_IPV6.equals(hostAddress)) {
|
||||
Logger.printDebug(() -> host + " resolves to sinkhole ip");
|
||||
} else {
|
||||
return true; // Domain is not blocked.
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
Logger.printDebug(() -> host + " failed to resolve");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* Checks if s.youtube.com is blacklisted and playback history will fail to work.
|
||||
*/
|
||||
public static void checkDnsResolver(Activity context) {
|
||||
if (!Utils.isNetworkConnected() || !BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return;
|
||||
|
||||
Utils.runOnBackgroundThread(() -> {
|
||||
try {
|
||||
// If the user has a flaky DNS server, or they just lost internet connectivity
|
||||
// and the isNetworkConnected() check has not detected it yet (it can take a few
|
||||
// seconds after losing connection), then the history tracking endpoint will
|
||||
// show a resolving error but it's actually an internet connection problem.
|
||||
//
|
||||
// Prevent this false positive by verify youtube.com resolves.
|
||||
// If youtube.com does not resolve, then it's not a watch history domain resolving error
|
||||
// because the entire app will not work since no domains are resolving.
|
||||
if (!domainResolvesToValidIP("youtube.com")
|
||||
|| domainResolvesToValidIP(HISTORY_TRACKING_ENDPOINT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.runOnMainThread(() -> {
|
||||
try {
|
||||
// Create the custom dialog.
|
||||
Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create(
|
||||
context,
|
||||
str("revanced_check_watch_history_domain_name_dialog_title"), // Title.
|
||||
Html.fromHtml(str("revanced_check_watch_history_domain_name_dialog_message")), // Message (HTML).
|
||||
null, // No EditText.
|
||||
null, // OK button text.
|
||||
() -> {}, // OK button action (just dismiss).
|
||||
() -> {}, // Cancel button action (just dismiss).
|
||||
str("revanced_check_watch_history_domain_name_dialog_ignore"), // Neutral button text.
|
||||
() -> BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore).
|
||||
true // Dismiss dialog on Neutral button click.
|
||||
);
|
||||
|
||||
// Show the dialog.
|
||||
Dialog dialog = dialogPair.first;
|
||||
|
||||
Utils.showDialog(context, dialog, false, null);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "checkDnsResolver dialog creation failure", ex);
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "checkDnsResolver failure", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,16 @@ public class BaseSettings {
|
||||
public static final BooleanSetting SETTINGS_SEARCH_HISTORY = new BooleanSetting("revanced_settings_search_history", TRUE, true);
|
||||
public static final StringSetting SETTINGS_SEARCH_ENTRIES = new StringSetting("revanced_settings_search_entries", "");
|
||||
|
||||
//
|
||||
// Settings shared by YouTube and YouTube Music.
|
||||
//
|
||||
|
||||
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
|
||||
public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
|
||||
|
||||
public static final BooleanSetting SANITIZE_SHARED_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE);
|
||||
public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE);
|
||||
|
||||
public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
* Set by subclasses if Strings cannot be added as a resource.
|
||||
*/
|
||||
@Nullable
|
||||
protected static String restartDialogButtonText, restartDialogTitle, confirmDialogTitle, restartDialogMessage;
|
||||
protected static CharSequence restartDialogTitle, restartDialogMessage, restartDialogButtonText, confirmDialogTitle;
|
||||
|
||||
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
|
||||
try {
|
||||
@@ -126,10 +126,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
|
||||
showingUserDialogMessage = true;
|
||||
|
||||
CharSequence message = BulletPointPreference.formatIntoBulletPoints(
|
||||
Objects.requireNonNull(setting.userDialogMessage).toString());
|
||||
|
||||
Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create(
|
||||
context,
|
||||
confirmDialogTitle, // Title.
|
||||
Objects.requireNonNull(setting.userDialogMessage).toString(), // No message.
|
||||
message,
|
||||
null, // No EditText.
|
||||
null, // OK button text.
|
||||
() -> {
|
||||
@@ -153,6 +156,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
);
|
||||
|
||||
dialogPair.first.setOnDismissListener(d -> showingUserDialogMessage = false);
|
||||
dialogPair.first.setCancelable(false);
|
||||
|
||||
// Show the dialog.
|
||||
dialogPair.first.show();
|
||||
|
||||
@@ -15,7 +15,15 @@ import android.util.AttributeSet;
|
||||
@SuppressWarnings({"unused", "deprecation"})
|
||||
public class BulletPointPreference extends Preference {
|
||||
|
||||
public static SpannedString formatIntoBulletPoints(CharSequence source) {
|
||||
/**
|
||||
* Replaces bullet points with styled spans.
|
||||
*/
|
||||
public static CharSequence formatIntoBulletPoints(CharSequence source) {
|
||||
final char bulletPoint = '•';
|
||||
if (TextUtils.indexOf(source, bulletPoint) < 0) {
|
||||
return source; // Nothing to do.
|
||||
}
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(source);
|
||||
|
||||
int lineStart = 0;
|
||||
@@ -26,7 +34,7 @@ public class BulletPointPreference extends Preference {
|
||||
if (lineEnd < 0) lineEnd = length;
|
||||
|
||||
// Apply BulletSpan only if the line starts with the '•' character.
|
||||
if (lineEnd > lineStart && builder.charAt(lineStart) == '•') {
|
||||
if (lineEnd > lineStart && builder.charAt(lineStart) == bulletPoint) {
|
||||
int deleteEnd = lineStart + 1; // remove the bullet itself
|
||||
|
||||
// If there's a single space right after the bullet, remove that too.
|
||||
|
||||
@@ -42,11 +42,8 @@ final class PlayerRoutes {
|
||||
JSONObject context = new JSONObject();
|
||||
|
||||
AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride();
|
||||
if (language == null || clientType == ANDROID_VR_1_43_32) {
|
||||
if (language == null) {
|
||||
// Force original audio has not overrode the language.
|
||||
// Or if YT has fallen over to the last unauthenticated client (VR 1.43), then
|
||||
// always use the app language because forcing an audio stream of specific languages
|
||||
// can sometimes fail so it's better to try and load something rather than nothing.
|
||||
language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get();
|
||||
}
|
||||
//noinspection ExtractMethodRecommender
|
||||
|
||||
@@ -58,10 +58,10 @@ public class CustomDialog {
|
||||
* @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked.
|
||||
* @return The Dialog and its main LinearLayout container.
|
||||
*/
|
||||
public static Pair<Dialog, LinearLayout> create(Context context, String title, CharSequence message,
|
||||
@Nullable EditText editText, String okButtonText,
|
||||
public static Pair<Dialog, LinearLayout> create(Context context, CharSequence title, CharSequence message,
|
||||
@Nullable EditText editText, CharSequence okButtonText,
|
||||
Runnable onOkClick, Runnable onCancelClick,
|
||||
@Nullable String neutralButtonText,
|
||||
@Nullable CharSequence neutralButtonText,
|
||||
@Nullable Runnable onNeutralClick,
|
||||
boolean dismissDialogOnNeutralClick) {
|
||||
Logger.printDebug(() -> "Creating custom dialog with title: " + title);
|
||||
@@ -85,9 +85,9 @@ public class CustomDialog {
|
||||
* @param onNeutralClick Action to perform when the Neutral button is clicked, or null if no Neutral button is needed.
|
||||
* @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked.
|
||||
*/
|
||||
private CustomDialog(Context context, String title, CharSequence message, @Nullable EditText editText,
|
||||
String okButtonText, Runnable onOkClick, Runnable onCancelClick,
|
||||
@Nullable String neutralButtonText, @Nullable Runnable onNeutralClick,
|
||||
private CustomDialog(Context context, CharSequence title, CharSequence message, @Nullable EditText editText,
|
||||
CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick,
|
||||
@Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick,
|
||||
boolean dismissDialogOnNeutralClick) {
|
||||
this.context = context;
|
||||
this.dialog = new Dialog(context);
|
||||
@@ -139,7 +139,7 @@ public class CustomDialog {
|
||||
*
|
||||
* @param title The title text to display.
|
||||
*/
|
||||
private void addTitle(String title) {
|
||||
private void addTitle(CharSequence title) {
|
||||
if (TextUtils.isEmpty(title)) return;
|
||||
|
||||
TextView titleView = new TextView(context);
|
||||
@@ -232,8 +232,8 @@ public class CustomDialog {
|
||||
* @param onNeutralClick Action for the Neutral button click, or null if no Neutral button.
|
||||
* @param dismissDialogOnNeutralClick If the dialog should dismiss on Neutral button click.
|
||||
*/
|
||||
private void addButtons(String okButtonText, Runnable onOkClick, Runnable onCancelClick,
|
||||
@Nullable String neutralButtonText, @Nullable Runnable onNeutralClick,
|
||||
private void addButtons(CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick,
|
||||
@Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick,
|
||||
boolean dismissDialogOnNeutralClick) {
|
||||
// Button container.
|
||||
LinearLayout buttonContainer = new LinearLayout(context);
|
||||
@@ -280,7 +280,7 @@ public class CustomDialog {
|
||||
* @param dismissDialog If the dialog should dismiss when the button is clicked.
|
||||
* @return The created Button.
|
||||
*/
|
||||
private Button createButton(String text, Runnable onClick, boolean isOkButton, boolean dismissDialog) {
|
||||
private Button createButton(CharSequence text, Runnable onClick, boolean isOkButton, boolean dismissDialog) {
|
||||
Button button = new Button(context, null, 0);
|
||||
button.setText(text);
|
||||
button.setTextSize(14);
|
||||
|
||||
Reference in New Issue
Block a user