generated from ReVanced/revanced-patches-template
-
-
Notifications
You must be signed in to change notification settings - Fork 316
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- v5.8.2-dev.1
- v5.8.1
- v5.8.1-dev.1
- v5.8.0
- v5.8.0-dev.8
- v5.8.0-dev.7
- v5.8.0-dev.6
- v5.8.0-dev.5
- v5.8.0-dev.4
- v5.8.0-dev.3
- v5.8.0-dev.2
- v5.8.0-dev.1
- v5.7.2
- v5.7.2-dev.2
- v5.7.2-dev.1
- v5.7.1
- v5.7.1-dev.5
- v5.7.1-dev.4
- v5.7.1-dev.3
- v5.7.1-dev.2
- v5.7.1-dev.1
- v5.7.0
- v5.7.0-dev.1
- v5.6.1-dev.4
- v5.6.1-dev.3
- v5.6.1-dev.2
- v5.6.1-dev.1
- v5.6.0
- v5.6.0-dev.6
- v5.6.0-dev.5
- v5.6.0-dev.4
- v5.6.0-dev.3
- v5.6.0-dev.2
- v5.6.0-dev.1
- v5.5.2-dev.2
- v5.5.2-dev.1
- v5.5.1
- v5.5.1-dev.1
- v5.5.0
Showing
111 changed files
with
3,016 additions
and
787 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
// Do not remove. Necessary for the extension plugin to be applied to the project. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<manifest/> |
27 changes: 27 additions & 0 deletions
27
extensions/music/src/main/java/app/revanced/extension/music/spoof/SpoofClientPatch.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package app.revanced.extension.music.spoof; | ||
|
||
/** | ||
* @noinspection unused | ||
*/ | ||
public class SpoofClientPatch { | ||
private static final int CLIENT_TYPE_ID = 26; | ||
private static final String CLIENT_VERSION = "6.21"; | ||
private static final String DEVICE_MODEL = "iPhone16,2"; | ||
private static final String OS_VERSION = "17.7.2.21H221"; | ||
|
||
public static int getClientId() { | ||
return CLIENT_TYPE_ID; | ||
} | ||
|
||
public static String getClientVersion() { | ||
return CLIENT_VERSION; | ||
} | ||
|
||
public static String getClientModel() { | ||
return DEVICE_MODEL; | ||
} | ||
|
||
public static String getOsVersion() { | ||
return OS_VERSION; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
...youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package app.revanced.extension.youtube.patches; | ||
|
||
import app.revanced.extension.shared.Logger; | ||
import app.revanced.extension.youtube.settings.Settings; | ||
|
||
@SuppressWarnings("unused") | ||
public class ForceOriginalAudioPatch { | ||
|
||
private static final String DEFAULT_AUDIO_TRACKS_IDENTIFIER = "original"; | ||
|
||
/** | ||
* Injection point. | ||
*/ | ||
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) { | ||
try { | ||
if (!Settings.FORCE_ORIGINAL_AUDIO.get()) { | ||
return isDefault; | ||
} | ||
|
||
if (audioTrackDisplayName.isEmpty()) { | ||
// Older app targets can have empty audio tracks and these might be placeholders. | ||
// The real audio tracks are called after these. | ||
return isDefault; | ||
} | ||
|
||
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: " | ||
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName); | ||
|
||
final boolean isOriginal = audioTrackDisplayName.contains(DEFAULT_AUDIO_TRACKS_IDENTIFIER); | ||
if (isOriginal) { | ||
Logger.printDebug(() -> "Using audio: " + audioTrackId); | ||
} | ||
|
||
return isOriginal; | ||
} catch (Exception ex) { | ||
Logger.printException(() -> "isDefaultAudioStream failure", ex); | ||
} | ||
|
||
return isDefault; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/Fingerprints.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package app.revanced.patches.music.misc.spoof | ||
|
||
import app.revanced.patcher.fingerprint | ||
import com.android.tools.smali.dexlib2.AccessFlags | ||
import com.android.tools.smali.dexlib2.Opcode | ||
|
||
internal val playerRequestConstructorFingerprint = fingerprint { | ||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) | ||
strings("player") | ||
} | ||
|
||
/** | ||
* Matches using the class found in [playerRequestConstructorFingerprint]. | ||
*/ | ||
internal val createPlayerRequestBodyFingerprint = fingerprint { | ||
parameters("L") | ||
returns("V") | ||
opcodes( | ||
Opcode.CHECK_CAST, | ||
Opcode.IGET, | ||
Opcode.AND_INT_LIT16, | ||
) | ||
strings("ms") | ||
} | ||
|
||
/** | ||
* Used to get a reference to other clientInfo fields. | ||
*/ | ||
internal val setClientInfoFieldsFingerprint = fingerprint { | ||
returns("L") | ||
strings("Google Inc.") | ||
} | ||
|
||
/** | ||
* Used to get a reference to the clientInfo and clientInfo.clientVersion field. | ||
*/ | ||
internal val setClientInfoClientVersionFingerprint = fingerprint { | ||
strings("10.29") | ||
} |
105 changes: 105 additions & 0 deletions
105
patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofClientPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package app.revanced.patches.music.misc.spoof | ||
|
||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction | ||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions | ||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction | ||
import app.revanced.patcher.extensions.InstructionExtensions.instructions | ||
import app.revanced.patcher.patch.bytecodePatch | ||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable | ||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch | ||
import app.revanced.util.getReference | ||
import com.android.tools.smali.dexlib2.AccessFlags | ||
import com.android.tools.smali.dexlib2.Opcode | ||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation | ||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction | ||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference | ||
import com.android.tools.smali.dexlib2.iface.reference.TypeReference | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter | ||
|
||
internal const val EXTENSION_CLASS_DESCRIPTOR = | ||
"Lapp/revanced/extension/music/spoof/SpoofClientPatch;" | ||
|
||
// TODO: Replace this patch with spoofVideoStreamsPatch once possible. | ||
val spoofClientPatch = bytecodePatch( | ||
name = "Spoof client", | ||
description = "Spoofs the client to fix playback.", | ||
) { | ||
compatibleWith("com.google.android.apps.youtube.music") | ||
|
||
dependsOn( | ||
sharedExtensionPatch, | ||
// TODO: Add settingsPatch | ||
userAgentClientSpoofPatch, | ||
) | ||
|
||
execute { | ||
val playerRequestClass = playerRequestConstructorFingerprint.classDef | ||
|
||
val createPlayerRequestBodyMatch = createPlayerRequestBodyFingerprint.match(playerRequestClass) | ||
|
||
val clientInfoContainerClass = createPlayerRequestBodyMatch.method | ||
.getInstruction(createPlayerRequestBodyMatch.patternMatch!!.startIndex) | ||
.getReference<TypeReference>()!!.type | ||
|
||
val clientInfoField = setClientInfoClientVersionFingerprint.method.instructions.first { | ||
it.opcode == Opcode.IPUT_OBJECT && it.getReference<FieldReference>()!!.definingClass == clientInfoContainerClass | ||
}.getReference<FieldReference>()!! | ||
|
||
val setClientInfoFieldInstructions = setClientInfoFieldsFingerprint.method.instructions.filter { | ||
(it.opcode == Opcode.IPUT_OBJECT || it.opcode == Opcode.IPUT) && | ||
it.getReference<FieldReference>()!!.definingClass == clientInfoField.type | ||
}.map { it.getReference<FieldReference>()!! } | ||
|
||
// Offsets are known for the fields in the clientInfo object. | ||
val clientIdField = setClientInfoFieldInstructions[0] | ||
val clientModelField = setClientInfoFieldInstructions[5] | ||
val osVersionField = setClientInfoFieldInstructions[7] | ||
val clientVersionField = setClientInfoClientVersionFingerprint.method | ||
.getInstruction(setClientInfoClientVersionFingerprint.stringMatches!!.first().index + 1) | ||
.getReference<FieldReference>() | ||
|
||
// Helper method to spoof the client info. | ||
val spoofClientInfoMethod = ImmutableMethod( | ||
playerRequestClass.type, | ||
"spoofClientInfo", | ||
listOf(ImmutableMethodParameter(clientInfoContainerClass, null, null)), | ||
"V", | ||
AccessFlags.PRIVATE.value or AccessFlags.STATIC.value, | ||
null, | ||
null, | ||
MutableMethodImplementation(3), | ||
).toMutable().also(playerRequestClass.methods::add).apply { | ||
addInstructions( | ||
""" | ||
iget-object v0, p0, $clientInfoField | ||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->getClientId()I | ||
move-result v1 | ||
iput v1, v0, $clientIdField | ||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->getClientModel()Ljava/lang/String; | ||
move-result-object v1 | ||
iput-object v1, v0, $clientModelField | ||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->getClientVersion()Ljava/lang/String; | ||
move-result-object v1 | ||
iput-object v1, v0, $clientVersionField | ||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->getOsVersion()Ljava/lang/String; | ||
move-result-object v1 | ||
iput-object v1, v0, $osVersionField | ||
return-void | ||
""", | ||
) | ||
} | ||
|
||
createPlayerRequestBodyMatch.method.apply { | ||
val checkCastIndex = createPlayerRequestBodyMatch.patternMatch!!.startIndex | ||
val clientInfoContainerRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA | ||
|
||
addInstruction(checkCastIndex + 1, "invoke-static {v$clientInfoContainerRegister}, $spoofClientInfoMethod") | ||
} | ||
} | ||
} |
15 changes: 0 additions & 15 deletions
15
patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatch.kt
This file was deleted.
Oops, something went wrong.
5 changes: 5 additions & 0 deletions
5
patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/UserAgentClientSpoofPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package app.revanced.patches.music.misc.spoof | ||
|
||
import app.revanced.patches.shared.misc.spoof.userAgentClientSpoofPatch | ||
|
||
val userAgentClientSpoofPatch = userAgentClientSpoofPatch("com.google.android.apps.youtube.music") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package app.revanced.patches.shared.misc.spoof | ||
|
||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction | ||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction | ||
import app.revanced.patches.all.misc.transformation.IMethodCall | ||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c | ||
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch | ||
import app.revanced.util.getReference | ||
import app.revanced.util.indexOfFirstInstruction | ||
import com.android.tools.smali.dexlib2.Opcode | ||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction | ||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference | ||
import com.android.tools.smali.dexlib2.iface.reference.StringReference | ||
|
||
private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE = | ||
"Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;" | ||
|
||
fun userAgentClientSpoofPatch(originalPackageName: String) = transformInstructionsPatch( | ||
filterMap = { classDef, _, instruction, instructionIndex -> | ||
filterMapInstruction35c<MethodCall>( | ||
"Lapp/revanced/extension", | ||
classDef, | ||
instruction, | ||
instructionIndex, | ||
) | ||
}, | ||
transform = transform@{ mutableMethod, entry -> | ||
val (_, _, instructionIndex) = entry | ||
|
||
// Replace the result of context.getPackageName(), if it is used in a user agent string. | ||
mutableMethod.apply { | ||
// After context.getPackageName() the result is moved to a register. | ||
val targetRegister = ( | ||
getInstruction(instructionIndex + 1) | ||
as? OneRegisterInstruction ?: return@transform | ||
).registerA | ||
|
||
// IndexOutOfBoundsException is technically possible here, | ||
// but no such occurrences are present in the app. | ||
val referee = getInstruction(instructionIndex + 2).getReference<MethodReference>()?.toString() | ||
|
||
// Only replace string builder usage. | ||
if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) { | ||
return@transform | ||
} | ||
|
||
// Do not change the package name in methods that use resources, or for methods that use GmsCore. | ||
// Changing these package names will result in playback limitations, | ||
// particularly Android VR background audio only playback. | ||
val resourceOrGmsStringInstructionIndex = indexOfFirstInstruction { | ||
val reference = getReference<StringReference>() | ||
opcode == Opcode.CONST_STRING && | ||
(reference?.string == "android.resource://" || reference?.string == "gcore_") | ||
} | ||
if (resourceOrGmsStringInstructionIndex >= 0) { | ||
return@transform | ||
} | ||
|
||
// Overwrite the result of context.getPackageName() with the original package name. | ||
replaceInstruction( | ||
instructionIndex + 1, | ||
"const-string v$targetRegister, \"$originalPackageName\"", | ||
) | ||
} | ||
}, | ||
) | ||
|
||
@Suppress("unused") | ||
private enum class MethodCall( | ||
override val definedClassName: String, | ||
override val methodName: String, | ||
override val methodParams: Array<String>, | ||
override val returnType: String, | ||
) : IMethodCall { | ||
GetPackageName( | ||
"Landroid/content/Context;", | ||
"getPackageName", | ||
emptyArray(), | ||
"Ljava/lang/String;", | ||
), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 2 additions & 79 deletions
81
patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,5 @@ | ||
package app.revanced.patches.youtube.misc.spoof | ||
|
||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction | ||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction | ||
import app.revanced.patches.all.misc.transformation.IMethodCall | ||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c | ||
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch | ||
import app.revanced.util.getReference | ||
import app.revanced.util.indexOfFirstInstruction | ||
import com.android.tools.smali.dexlib2.Opcode | ||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction | ||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference | ||
import com.android.tools.smali.dexlib2.iface.reference.StringReference | ||
import app.revanced.patches.shared.misc.spoof.userAgentClientSpoofPatch | ||
|
||
private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube" | ||
private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE = | ||
"Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;" | ||
|
||
val userAgentClientSpoofPatch = transformInstructionsPatch( | ||
filterMap = { classDef, _, instruction, instructionIndex -> | ||
filterMapInstruction35c<MethodCall>( | ||
"Lapp/revanced/extension", | ||
classDef, | ||
instruction, | ||
instructionIndex, | ||
) | ||
}, | ||
transform = transform@{ mutableMethod, entry -> | ||
val (_, _, instructionIndex) = entry | ||
|
||
// Replace the result of context.getPackageName(), if it is used in a user agent string. | ||
mutableMethod.apply { | ||
// After context.getPackageName() the result is moved to a register. | ||
val targetRegister = ( | ||
getInstruction(instructionIndex + 1) | ||
as? OneRegisterInstruction ?: return@transform | ||
).registerA | ||
|
||
// IndexOutOfBoundsException is technically possible here, | ||
// but no such occurrences are present in the app. | ||
val referee = getInstruction(instructionIndex + 2).getReference<MethodReference>()?.toString() | ||
|
||
// Only replace string builder usage. | ||
if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) { | ||
return@transform | ||
} | ||
|
||
// Do not change the package name in methods that use resources, or for methods that use GmsCore. | ||
// Changing these package names will result in playback limitations, | ||
// particularly Android VR background audio only playback. | ||
val resourceOrGmsStringInstructionIndex = indexOfFirstInstruction { | ||
val reference = getReference<StringReference>() | ||
opcode == Opcode.CONST_STRING && | ||
(reference?.string == "android.resource://" || reference?.string == "gcore_") | ||
} | ||
if (resourceOrGmsStringInstructionIndex >= 0) { | ||
return@transform | ||
} | ||
|
||
// Overwrite the result of context.getPackageName() with the original package name. | ||
replaceInstruction( | ||
instructionIndex + 1, | ||
"const-string v$targetRegister, \"$ORIGINAL_PACKAGE_NAME\"", | ||
) | ||
} | ||
}, | ||
) | ||
|
||
@Suppress("unused") | ||
private enum class MethodCall( | ||
override val definedClassName: String, | ||
override val methodName: String, | ||
override val methodParams: Array<String>, | ||
override val returnType: String, | ||
) : IMethodCall { | ||
GetPackageName( | ||
"Landroid/content/Context;", | ||
"getPackageName", | ||
emptyArray(), | ||
"Ljava/lang/String;", | ||
), | ||
} | ||
val userAgentClientSpoofPatch = userAgentClientSpoofPatch("com.google.android.youtube") |
23 changes: 23 additions & 0 deletions
23
patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/Fingerprints.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package app.revanced.patches.youtube.video.audio | ||
|
||
import app.revanced.patcher.fingerprint | ||
import com.android.tools.smali.dexlib2.AccessFlags | ||
|
||
internal val streamingModelBuilderFingerprint = fingerprint { | ||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) | ||
returns("L") | ||
strings("vprng") | ||
} | ||
|
||
internal val menuItemAudioTrackFingerprint = fingerprint { | ||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) | ||
parameters("L") | ||
returns("V") | ||
strings("menu_item_audio_track") | ||
} | ||
|
||
internal val audioStreamingTypeSelector = fingerprint { | ||
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) | ||
returns("L") | ||
strings("raw") // String is not unique | ||
} |
159 changes: 159 additions & 0 deletions
159
patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package app.revanced.patches.youtube.video.audio | ||
|
||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions | ||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels | ||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction | ||
import app.revanced.patcher.patch.bytecodePatch | ||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable | ||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod | ||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable | ||
import app.revanced.patches.all.misc.resources.addResources | ||
import app.revanced.patches.all.misc.resources.addResourcesPatch | ||
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 app.revanced.util.indexOfFirstInstructionOrThrow | ||
import com.android.tools.smali.dexlib2.AccessFlags | ||
import com.android.tools.smali.dexlib2.Opcode | ||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation | ||
import com.android.tools.smali.dexlib2.iface.Method | ||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction | ||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableField | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod | ||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter | ||
|
||
private const val EXTENSION_CLASS_DESCRIPTOR = | ||
"Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;" | ||
|
||
@Suppress("unused") | ||
val forceOriginalAudioPatch = bytecodePatch( | ||
name = "Force original audio", | ||
description = "Adds an option to always use the original audio track.", | ||
) { | ||
dependsOn( | ||
sharedExtensionPatch, | ||
settingsPatch, | ||
addResourcesPatch, | ||
) | ||
|
||
compatibleWith( | ||
"com.google.android.youtube"( | ||
"18.38.44", | ||
"18.49.37", | ||
"19.16.39", | ||
"19.25.37", | ||
"19.34.42", | ||
"19.43.41", | ||
"19.45.38", | ||
"19.46.42", | ||
), | ||
) | ||
|
||
execute { | ||
addResources("youtube", "video.audio.forceOriginalAudioPatch") | ||
|
||
PreferenceScreen.VIDEO.addPreferences( | ||
SwitchPreference("revanced_force_original_audio") | ||
) | ||
|
||
fun Method.firstFormatStreamingModelCall( | ||
returnType: String = "Ljava/lang/String;" | ||
): MutableMethod { | ||
val audioTrackIdIndex = indexOfFirstInstructionOrThrow { | ||
val reference = getReference<MethodReference>() | ||
reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;" | ||
&& reference.returnType == returnType | ||
} | ||
|
||
return navigate(this).to(audioTrackIdIndex).stop() | ||
} | ||
|
||
// Accessor methods of FormatStreamModel have no string constants and | ||
// opcodes are identical to other methods in the same class, | ||
// so must walk from another class that use the methods. | ||
val isDefaultMethod = streamingModelBuilderFingerprint.originalMethod.firstFormatStreamingModelCall("Z") | ||
val audioTrackIdMethod = menuItemAudioTrackFingerprint.originalMethod.firstFormatStreamingModelCall() | ||
val audioTrackDisplayNameMethod = audioStreamingTypeSelector.originalMethod.firstFormatStreamingModelCall() | ||
val formatStreamModelClass = proxy(classes.first { | ||
it.type == audioTrackIdMethod.definingClass | ||
}).mutableClass | ||
|
||
formatStreamModelClass.apply { | ||
// Add a new field to store the override. | ||
val helperFieldName = "isDefaultAudioTrackOverride" | ||
fields.add( | ||
ImmutableField( | ||
type, | ||
helperFieldName, | ||
"Ljava/lang/Boolean;", | ||
// Boolean is a 100% immutable class (all fields are final) | ||
// and safe to write to a shared field without volatile/synchronization, | ||
// but without volatile the field can show stale data | ||
// and the same field is calculated more than once by different threads. | ||
AccessFlags.PRIVATE.value or AccessFlags.VOLATILE.value, | ||
null, | ||
null, | ||
null | ||
).toMutable() | ||
) | ||
|
||
// Add a helper method because the isDefaultAudioTrack() has only 2 registers and 3 are needed. | ||
val helperMethodClass = type | ||
val helperMethodName = "extension_isDefaultAudioTrack" | ||
val helperMethod = ImmutableMethod( | ||
helperMethodClass, | ||
helperMethodName, | ||
listOf(ImmutableMethodParameter("Z", null, null)), | ||
"Z", | ||
AccessFlags.PRIVATE.value, | ||
null, | ||
null, | ||
MutableMethodImplementation(6), | ||
).toMutable().apply { | ||
addInstructionsWithLabels( | ||
0, | ||
""" | ||
iget-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean; | ||
if-eqz v0, :call_extension | ||
invoke-virtual { v0 }, Ljava/lang/Boolean;->booleanValue()Z | ||
move-result v3 | ||
return v3 | ||
:call_extension | ||
invoke-virtual { p0 }, $audioTrackIdMethod | ||
move-result-object v1 | ||
invoke-virtual { p0 }, $audioTrackDisplayNameMethod | ||
move-result-object v2 | ||
invoke-static { p1, v1, v2 }, $EXTENSION_CLASS_DESCRIPTOR->isDefaultAudioStream(ZLjava/lang/String;Ljava/lang/String;)Z | ||
move-result v3 | ||
invoke-static { v3 }, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean; | ||
move-result-object v0 | ||
iput-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean; | ||
return v3 | ||
""" | ||
) | ||
} | ||
methods.add(helperMethod) | ||
|
||
// Modify isDefaultAudioTrack() to call extension helper method. | ||
isDefaultMethod.apply { | ||
val index = indexOfFirstInstructionOrThrow(Opcode.RETURN) | ||
val register = getInstruction<OneRegisterInstruction>(index).registerA | ||
|
||
addInstructions( | ||
index, | ||
""" | ||
invoke-direct { p0, v$register }, $helperMethodClass->$helperMethodName(Z)Z | ||
move-result v$register | ||
""" | ||
) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.