mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-25 18:34:07 +01:00
Compare commits
6 Commits
v5.41.0-de
...
v5.41.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b83d41ca88 | ||
|
|
bfbffbd1f5 | ||
|
|
ee4755646b | ||
|
|
d1a12930c3 | ||
|
|
dfac836a8c | ||
|
|
6fa404331b |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,3 +1,24 @@
|
||||
# [5.41.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.10...v5.41.0-dev.11) (2025-09-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Add `Disable video codecs` patch ([#5981](https://github.com/ReVanced/revanced-patches/issues/5981)) ([bfbffbd](https://github.com/ReVanced/revanced-patches/commit/bfbffbd1f5aa867027053e25b343a51a606216a3))
|
||||
|
||||
# [5.41.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.9...v5.41.0-dev.10) (2025-09-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **TikTok:** Show correct dialog restart text, use correct font color for non-dark mode ([d1a1293](https://github.com/ReVanced/revanced-patches/commit/d1a12930c35f630793a0f240d4203c2ff9060158))
|
||||
|
||||
# [5.41.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.8...v5.41.0-dev.9) (2025-09-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Instagram - Hide navigation buttons:** Remove button based on name ([#5971](https://github.com/ReVanced/revanced-patches/issues/5971)) ([6fa4043](https://github.com/ReVanced/revanced-patches/commit/6fa404331b5162682d83fba5f38ed570c31495fc))
|
||||
|
||||
# [5.41.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.7...v5.41.0-dev.8) (2025-09-23)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package app.revanced.extension.instagram.hide.navigation;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HideNavigationButtonsPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* @param navigationButtonsList the list of navigation buttons, as an (obfuscated) Enum type
|
||||
* @param buttonNameToRemove the name of the button we want to remove
|
||||
* @param enumNameField the field in the nav button enum class which contains the name of the button
|
||||
* @return the patched list of navigation buttons
|
||||
*/
|
||||
public static List<Object> removeNavigationButtonByName(
|
||||
List<Object> navigationButtonsList,
|
||||
String buttonNameToRemove,
|
||||
String enumNameField
|
||||
)
|
||||
throws IllegalAccessException, NoSuchFieldException {
|
||||
for (Object button : navigationButtonsList) {
|
||||
Field f = button.getClass().getDeclaredField(enumNameField);
|
||||
String currentButtonEnumName = (String) f.get(button);
|
||||
|
||||
if (buttonNameToRemove.equals(currentButtonEnumName)) {
|
||||
navigationButtonsList.remove(button);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return navigationButtonsList;
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,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 {
|
||||
@@ -125,10 +125,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.
|
||||
() -> {
|
||||
@@ -152,6 +155,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);
|
||||
|
||||
@@ -2,12 +2,15 @@ package app.revanced.extension.tiktok.settings.preference;
|
||||
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceScreen;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment;
|
||||
import app.revanced.extension.tiktok.settings.preference.categories.DownloadsPreferenceCategory;
|
||||
import app.revanced.extension.tiktok.settings.preference.categories.FeedFilterPreferenceCategory;
|
||||
import app.revanced.extension.tiktok.settings.preference.categories.ExtensionPreferenceCategory;
|
||||
import app.revanced.extension.tiktok.settings.preference.categories.FeedFilterPreferenceCategory;
|
||||
import app.revanced.extension.tiktok.settings.preference.categories.SimSpoofPreferenceCategory;
|
||||
|
||||
/**
|
||||
@@ -37,10 +40,14 @@ public class TikTokPreferenceFragment extends AbstractPreferenceFragment {
|
||||
|
||||
// Currently no resources can be compiled for TikTok (fails with aapt error).
|
||||
// So all TikTok Strings are hard coded in the extension.
|
||||
restartDialogTitle = "Refresh and restart";
|
||||
restartDialogTitle = "Restart required";
|
||||
restartDialogMessage = "Restart the app for this change to take effect.";
|
||||
restartDialogButtonText = "Restart";
|
||||
confirmDialogTitle = "Do you wish to proceed?";
|
||||
|
||||
// App does not use dark mode.
|
||||
Utils.setIsDarkModeEnabled(false);
|
||||
|
||||
PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(context);
|
||||
setPreferenceScreen(preferenceScreen);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.view.Display;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class DisableHdrPatch {
|
||||
public class DisableVideoCodecsPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
@@ -15,5 +15,12 @@ public class DisableHdrPatch {
|
||||
? new int[0]
|
||||
: capabilities.getSupportedHdrTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static boolean allowVP9() {
|
||||
return !Settings.FORCE_AVC_CODEC.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ public class ForceOriginalAudioPatch {
|
||||
*/
|
||||
public static void setPreferredLanguage() {
|
||||
if (Settings.FORCE_ORIGINAL_AUDIO.get()
|
||||
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
|
||||
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()
|
||||
&& !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) {
|
||||
// If client spoofing does not use authentication and lacks multi-audio streams,
|
||||
// then can use any language code for the request and if that requested language is
|
||||
// not available YT uses the original audio language. Authenticated requests ignore
|
||||
|
||||
@@ -18,7 +18,22 @@ public class SpoofVideoStreamsPatch {
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setClientOrderToUse() {
|
||||
List<ClientType> availableClients = List.of(
|
||||
final boolean forceAVC = Settings.FORCE_AVC_CODEC.get();
|
||||
|
||||
// VR 1.61 uses VP9/AV1, and cannot force AVC.
|
||||
ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
if (forceAVC && client == ANDROID_VR_1_61_48) {
|
||||
client = ANDROID_VR_1_43_32; // Use VR 1.43 instead.
|
||||
}
|
||||
|
||||
List<ClientType> availableClients = forceAVC
|
||||
? List.of(
|
||||
ANDROID_VR_1_43_32,
|
||||
VISIONOS,
|
||||
ANDROID_CREATOR,
|
||||
ANDROID_VR_1_61_48,
|
||||
IPADOS)
|
||||
: List.of(
|
||||
ANDROID_VR_1_61_48,
|
||||
VISIONOS,
|
||||
ANDROID_CREATOR,
|
||||
@@ -27,6 +42,6 @@ public class SpoofVideoStreamsPatch {
|
||||
);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
availableClients, Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
|
||||
availableClients, client);
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,9 @@ import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationPr
|
||||
|
||||
public class Settings extends BaseSettings {
|
||||
// Video
|
||||
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
|
||||
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
|
||||
public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message");
|
||||
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
|
||||
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
|
||||
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
|
||||
@@ -56,8 +59,6 @@ public class Settings extends BaseSettings {
|
||||
public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE);
|
||||
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_video_quality_last_selected_toast", TRUE, false,
|
||||
parentsAny(REMEMBER_VIDEO_QUALITY_LAST_SELECTED, REMEMBER_SHORTS_QUALITY_LAST_SELECTED));
|
||||
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
|
||||
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
|
||||
|
||||
// Speed
|
||||
public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true);
|
||||
|
||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
||||
org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
version = 5.41.0-dev.8
|
||||
version = 5.41.0-dev.11
|
||||
|
||||
@@ -1727,6 +1727,10 @@ public final class app/revanced/patches/youtube/video/audio/ForceOriginalAudioPa
|
||||
public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatchKt {
|
||||
public static final fun getDisableVideoCodecsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/video/hdr/DisableHdrPatchKt {
|
||||
public static final fun getDisableHdrPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
@@ -2,28 +2,22 @@
|
||||
package app.revanced.patches.instagram.hide.navigation
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
|
||||
internal val tabCreateButtonsLoopStartFingerprint = fingerprint {
|
||||
returns("V")
|
||||
strings("InstagramMainActivity.createTabButtons")
|
||||
opcodes(
|
||||
//Loop Start
|
||||
Opcode.IF_GE, // Check if index is finished (index, size)
|
||||
//Injection
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
)
|
||||
internal val initializeNavigationButtonsListFingerprint = fingerprint {
|
||||
strings("Nav3")
|
||||
parameters("Lcom/instagram/common/session/UserSession;", "Z")
|
||||
returns("Ljava/util/List;")
|
||||
}
|
||||
|
||||
internal val tabCreateButtonsLoopEndFingerprint = fingerprint {
|
||||
returns("V")
|
||||
strings("InstagramMainActivity.createTabButtons")
|
||||
opcodes(
|
||||
Opcode.IPUT_OBJECT,
|
||||
// Injection Jump
|
||||
Opcode.ADD_INT_LIT8, //Increase Index
|
||||
Opcode.GOTO // Jump to loopStart
|
||||
// LoopEnd
|
||||
)
|
||||
private val navigationButtonsEnumClassDef = fingerprint {
|
||||
strings("FEED", "fragment_feed", "SEARCH", "fragment_search")
|
||||
}
|
||||
|
||||
context(BytecodePatchContext)
|
||||
internal val navigationButtonsEnumInitFingerprint get() = fingerprint {
|
||||
custom { method, classDef ->
|
||||
method.name == "<init>"
|
||||
&& classDef == navigationButtonsEnumClassDef.classDef
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
package app.revanced.patches.instagram.hide.navigation
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.util.addInstructionsAtControlFlowLabel
|
||||
import app.revanced.util.findFreeRegister
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import java.util.logging.Logger
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/instagram/hide/navigation/HideNavigationButtonsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val hideNavigationButtonsPatch = bytecodePatch(
|
||||
name = "Hide navigation buttons",
|
||||
description = "Hides navigation bar buttons, such as the Reels and Create button.",
|
||||
use = false
|
||||
) {
|
||||
compatibleWith("com.instagram.android"("397.1.0.52.81"))
|
||||
compatibleWith("com.instagram.android")
|
||||
|
||||
val hideReels by booleanOption(
|
||||
key = "hideReels",
|
||||
@@ -38,43 +45,44 @@ val hideNavigationButtonsPatch = bytecodePatch(
|
||||
)
|
||||
}
|
||||
|
||||
tabCreateButtonsLoopStartFingerprint.method.apply {
|
||||
// Check the current loop index, and skip over adding the
|
||||
// navigation button view if the index matches a given button.
|
||||
val enumNameField: String
|
||||
|
||||
val startIndex = tabCreateButtonsLoopStartFingerprint.patternMatch!!.startIndex
|
||||
val endIndex = tabCreateButtonsLoopEndFingerprint.patternMatch!!.endIndex
|
||||
val insertIndex = startIndex + 1
|
||||
val loopIndexRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
|
||||
val freeRegister = findFreeRegister(insertIndex, loopIndexRegister)
|
||||
val instruction = getInstruction(endIndex - 1)
|
||||
|
||||
val instructions = buildString {
|
||||
if (hideCreate!!) {
|
||||
appendLine(
|
||||
"""
|
||||
const v$freeRegister, 0x2
|
||||
if-eq v$freeRegister, v$loopIndexRegister, :skipAddView
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
if (hideReels!!) {
|
||||
appendLine(
|
||||
"""
|
||||
const v$freeRegister, 0x3
|
||||
if-eq v$freeRegister, v$loopIndexRegister, :skipAddView
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex,
|
||||
instructions,
|
||||
ExternalLabel("skipAddView", instruction)
|
||||
)
|
||||
// Get the field name which contains the name of the enum for the navigation button ("fragment_clips", "fragment_share", ...)
|
||||
with(navigationButtonsEnumInitFingerprint.method) {
|
||||
enumNameField = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.IPUT_OBJECT &&
|
||||
(this as TwoRegisterInstruction).registerA == 2 // The p2 register
|
||||
}.let {
|
||||
getInstruction(it).getReference<FieldReference>()!!.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializeNavigationButtonsListFingerprint.method.apply {
|
||||
val returnIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_OBJECT)
|
||||
val buttonsListRegister = getInstruction<OneRegisterInstruction>(returnIndex).registerA
|
||||
val freeRegister = findFreeRegister(returnIndex)
|
||||
val freeRegister2 = findFreeRegister(returnIndex, freeRegister)
|
||||
|
||||
fun instructionsRemoveButtonByName(buttonEnumName: String): String {
|
||||
return """
|
||||
const-string v$freeRegister, "$buttonEnumName"
|
||||
const-string v$freeRegister2, "$enumNameField"
|
||||
invoke-static { v$buttonsListRegister, v$freeRegister, v$freeRegister2 }, $EXTENSION_CLASS_DESCRIPTOR->removeNavigationButtonByName(Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
|
||||
move-result-object v$buttonsListRegister
|
||||
"""
|
||||
}
|
||||
|
||||
if (hideReels!!)
|
||||
addInstructionsAtControlFlowLabel(
|
||||
returnIndex,
|
||||
instructionsRemoveButtonByName("fragment_clips")
|
||||
)
|
||||
|
||||
if (hideCreate!!)
|
||||
addInstructionsAtControlFlowLabel(
|
||||
returnIndex,
|
||||
instructionsRemoveButtonByName("fragment_share")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package app.revanced.patches.youtube.video.codecs
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/DisableVideoCodecsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val disableVideoCodecsPatch = bytecodePatch(
|
||||
name = "disable video codecs",
|
||||
description = "Adds options to disable HDR and VP9 codecs.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
/**
|
||||
* Override all calls of `getSupportedHdrTypes`.
|
||||
*/
|
||||
transformInstructionsPatch(
|
||||
filterMap = filterMap@{ classDef, _, instruction, instructionIndex ->
|
||||
if (classDef.type.startsWith("Lapp/revanced/")) {
|
||||
return@filterMap null
|
||||
}
|
||||
|
||||
val reference = instruction.getReference<MethodReference>()
|
||||
if (reference?.definingClass =="Landroid/view/Display\$HdrCapabilities;"
|
||||
&& reference.name == "getSupportedHdrTypes") {
|
||||
return@filterMap instruction to instructionIndex
|
||||
}
|
||||
return@filterMap null
|
||||
},
|
||||
transform = { method, entry ->
|
||||
val (instruction, index) = entry
|
||||
val register = (instruction as FiveRegisterInstruction).registerC
|
||||
|
||||
method.replaceInstruction(
|
||||
index,
|
||||
"invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I",
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
"20.07.39",
|
||||
"20.13.41",
|
||||
"20.14.43",
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("youtube", "video.codecs.disableVideoCodecsPatch")
|
||||
|
||||
PreferenceScreen.VIDEO.addPreferences(
|
||||
SwitchPreference("revanced_disable_hdr_video"),
|
||||
SwitchPreference("revanced_force_avc_codec")
|
||||
)
|
||||
|
||||
vp9CapabilityFingerprint.method.addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->allowVP9()Z
|
||||
move-result v0
|
||||
if-nez v0, :default
|
||||
return v0
|
||||
:default
|
||||
nop
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.video.codecs
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val vp9CapabilityFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("Z")
|
||||
strings(
|
||||
"vp9_supported",
|
||||
"video/x-vnd.on2.vp9"
|
||||
)
|
||||
}
|
||||
@@ -1,71 +1,10 @@
|
||||
package app.revanced.patches.youtube.video.hdr
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/DisableHdrPatch;"
|
||||
import app.revanced.patches.youtube.video.codecs.disableVideoCodecsPatch
|
||||
|
||||
@Deprecated("Patch was renamed", ReplaceWith("disableVideoCodecsPatch"))
|
||||
@Suppress("unused")
|
||||
val disableHdrPatch = bytecodePatch(
|
||||
name = "Disable HDR video",
|
||||
description = "Adds an option to disable video HDR.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
// Override all calls of `getSupportedHdrTypes`.
|
||||
transformInstructionsPatch(
|
||||
filterMap = filterMap@{ classDef, _, instruction, instructionIndex ->
|
||||
if (classDef.type.startsWith("Lapp/revanced/")) {
|
||||
return@filterMap null
|
||||
}
|
||||
|
||||
val reference = instruction.getReference<MethodReference>()
|
||||
if (reference?.definingClass =="Landroid/view/Display\$HdrCapabilities;"
|
||||
&& reference.name == "getSupportedHdrTypes") {
|
||||
return@filterMap instruction to instructionIndex
|
||||
}
|
||||
return@filterMap null
|
||||
},
|
||||
transform = { method, entry ->
|
||||
val (instruction, index) = entry
|
||||
val register = (instruction as FiveRegisterInstruction).registerC
|
||||
|
||||
method.replaceInstruction(
|
||||
index,
|
||||
"invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I",
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
"20.07.39",
|
||||
"20.13.41",
|
||||
"20.14.43",
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("youtube", "video.hdr.disableHdrPatch")
|
||||
|
||||
PreferenceScreen.VIDEO.addPreferences(
|
||||
SwitchPreference("revanced_disable_hdr_video")
|
||||
)
|
||||
}
|
||||
}
|
||||
val disableHdrPatch = bytecodePatch{
|
||||
dependsOn(disableVideoCodecsPatch)
|
||||
}
|
||||
@@ -26,7 +26,6 @@ internal val videoQualityItemOnClickFingerprint = fingerprint {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal val videoQualityMenuOptionsFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.STATIC)
|
||||
returns("[L")
|
||||
|
||||
@@ -14,12 +14,13 @@ internal val settingsMenuVideoQualityGroup = mutableSetOf<BasePreference>()
|
||||
@Suppress("unused")
|
||||
val videoQualityPatch = bytecodePatch(
|
||||
name = "Video quality",
|
||||
description = "Adds options to use the advanced video quality menu and set default video qualities."
|
||||
description = "Adds options to use the advanced video quality menu, set default video qualities, " +
|
||||
"and disable video codecs such as VP9/HDR."
|
||||
) {
|
||||
dependsOn(
|
||||
rememberVideoQualityPatch,
|
||||
advancedVideoQualityMenuPatch,
|
||||
videoQualityDialogButtonPatch,
|
||||
videoQualityDialogButtonPatch
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
|
||||
@@ -1641,10 +1641,22 @@ Enabling this can unlock higher video qualities"</string>
|
||||
<string name="revanced_playback_speed_default_title">Default playback speed</string>
|
||||
<string name="revanced_remember_playback_speed_toast">Changed default speed to: %s</string>
|
||||
</patch>
|
||||
<patch id="video.hdr.disableHdrPatch">
|
||||
<patch id="video.codecs.disableVideoCodecsPatch">
|
||||
<string name="revanced_disable_hdr_video_title">Disable HDR video</string>
|
||||
<string name="revanced_disable_hdr_video_summary_on">HDR video is disabled</string>
|
||||
<string name="revanced_disable_hdr_video_summary_off">HDR video is enabled</string>
|
||||
<string name="revanced_force_avc_codec_title">Force AVC (H.264)</string>
|
||||
<string name="revanced_force_avc_codec_summary_on">Video codec is forced to AVC (H.264)</string>
|
||||
<string name="revanced_force_avc_codec_summary_off">Video codec is determined automatically</string>
|
||||
<string name="revanced_force_avc_codec_user_dialog_message">"Benefits:
|
||||
• Can improve battery life.
|
||||
• Can restore missing video resolutions on older device.
|
||||
|
||||
Limitations:
|
||||
• Maximum resolution is 1080p.
|
||||
• Video playback will use more internet data than VP9 or AV1.
|
||||
• HDR videos may not use AVC.
|
||||
• Some devices cannot force AVC."</string>
|
||||
</patch>
|
||||
<patch id="video.quality.advancedVideoQualityMenuPatch">
|
||||
<string name="revanced_advanced_video_quality_menu_title">Show advanced video quality menu</string>
|
||||
|
||||
Reference in New Issue
Block a user