diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaylistPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaylistPatch.java index 0e157be43..98ebe9f3c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaylistPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaylistPatch.java @@ -1,6 +1,10 @@ package app.revanced.extension.youtube.patches.utils; import static app.revanced.extension.shared.utils.StringRef.str; +import static app.revanced.extension.shared.utils.Utils.runOnMainThreadDelayed; +import static app.revanced.extension.youtube.utils.VideoUtils.dismissPlayer; +import static app.revanced.extension.youtube.utils.VideoUtils.launchVideoExternalDownloader; +import static app.revanced.extension.youtube.utils.VideoUtils.openPlaylist; import android.content.Context; import android.view.KeyEvent; @@ -32,30 +36,18 @@ import app.revanced.extension.youtube.patches.utils.requests.SavePlaylistRequest import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.PlayerType; import app.revanced.extension.youtube.shared.VideoInformation; +import app.revanced.extension.youtube.utils.AuthUtils; import app.revanced.extension.youtube.utils.ExtendedUtils; -import app.revanced.extension.youtube.utils.VideoUtils; import kotlin.Pair; // TODO: Implement sync queue and clean up code. @SuppressWarnings({"unused", "StaticFieldLeak"}) -public class PlaylistPatch extends VideoUtils { - private static final String AUTHORIZATION_HEADER = "Authorization"; - private static final String[] REQUEST_HEADER_KEYS = { - AUTHORIZATION_HEADER, - "X-GOOG-API-FORMAT-VERSION", - "X-Goog-Visitor-Id" - }; +public class PlaylistPatch extends AuthUtils { private static final boolean QUEUE_MANAGER = Settings.OVERLAY_BUTTON_EXTERNAL_DOWNLOADER_QUEUE_MANAGER.get() || Settings.OVERRIDE_VIDEO_DOWNLOAD_BUTTON_QUEUE_MANAGER.get(); private static Context mContext; - private static volatile String authorization = ""; - public static volatile String dataSyncId = ""; - public static volatile boolean isIncognito = false; - private static volatile Map requestHeader; - private static volatile String playlistId = ""; - private static volatile String videoId = ""; private static String checkFailedAuth; private static String checkFailedPlaylistId; @@ -141,30 +133,6 @@ public class PlaylistPatch extends VideoUtils { } } - /** - * Injection point. - */ - public static void setRequestHeaders(String url, Map requestHeaders) { - if (QUEUE_MANAGER) { - try { - // Save requestHeaders whenever an account is switched. - String auth = requestHeaders.get(AUTHORIZATION_HEADER); - if (auth == null || authorization.equals(auth)) { - return; - } - for (String key : REQUEST_HEADER_KEYS) { - if (requestHeaders.get(key) == null) { - return; - } - } - authorization = auth; - requestHeader = requestHeaders; - } catch (Exception ex) { - Logger.printException(() -> "setRequestHeaders failure", ex); - } - } - } - /** * Invoked by extension. */ diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/AuthUtils.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/AuthUtils.java new file mode 100644 index 000000000..8e015700e --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/AuthUtils.java @@ -0,0 +1,40 @@ +package app.revanced.extension.youtube.utils; + +import java.util.Map; + +import app.revanced.extension.shared.utils.Logger; + +@SuppressWarnings("unused") +public class AuthUtils { + public static final String AUTHORIZATION_HEADER = "Authorization"; + public static final String[] REQUEST_HEADER_KEYS = { + AUTHORIZATION_HEADER, + "X-GOOG-API-FORMAT-VERSION", + "X-Goog-Visitor-Id" + }; + public static volatile String authorization = ""; + public static volatile String dataSyncId = ""; + public static volatile boolean isIncognito = false; + public static volatile Map requestHeader; + public static volatile String playlistId = ""; + public static volatile String videoId = ""; + + public static void setRequestHeaders(String url, Map requestHeaders) { + try { + // Save requestHeaders whenever an account is switched. + String auth = requestHeaders.get(AUTHORIZATION_HEADER); + if (auth == null || authorization.equals(auth)) { + return; + } + for (String key : REQUEST_HEADER_KEYS) { + if (requestHeaders.get(key) == null) { + return; + } + } + authorization = auth; + requestHeader = requestHeaders; + } catch (Exception ex) { + Logger.initializationException(AuthUtils.class, "setRequestHeaders failure", ex); + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/auth/AuthHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/auth/AuthHookPatch.kt new file mode 100644 index 000000000..fe3e89272 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/auth/AuthHookPatch.kt @@ -0,0 +1,34 @@ +package app.revanced.patches.youtube.utils.auth + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.youtube.utils.extension.Constants.EXTENSION_PATH +import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch +import app.revanced.patches.youtube.utils.request.buildRequestPatch +import app.revanced.patches.youtube.utils.request.hookBuildRequest +import app.revanced.util.fingerprint.methodOrThrow + +private const val EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR = + "$EXTENSION_PATH/utils/AuthUtils;" + +val authHookPatch = bytecodePatch( + description = "authHookPatch" +) { + dependsOn( + sharedExtensionPatch, + buildRequestPatch, + ) + + execute { + // Get incognito status and data sync id. + accountIdentityFingerprint.methodOrThrow().addInstructions( + 1, """ + sput-object p3, $EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR->dataSyncId:Ljava/lang/String; + sput-boolean p4, $EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR->isIncognito:Z + """ + ) + + // Get the header to use the auth token. + hookBuildRequest("$EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR->setRequestHeaders(Ljava/lang/String;Ljava/util/Map;)V") + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/auth/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/auth/Fingerprints.kt new file mode 100644 index 000000000..85678373a --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/auth/Fingerprints.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.utils.auth + +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags + +internal val accountIdentityFingerprint = legacyFingerprint( + name = "accountIdentityFingerprint", + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + customFingerprint = { method, _ -> + method.definingClass.endsWith("${'$'}AutoValue_AccountIdentity;") + } +) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/Fingerprints.kt index 10c9e073d..9a55e8ecf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/Fingerprints.kt @@ -9,15 +9,6 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.reference.FieldReference -internal val accountIdentityFingerprint = legacyFingerprint( - name = "accountIdentityFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - customFingerprint = { method, _ -> - method.definingClass.endsWith("${'$'}AutoValue_AccountIdentity;") - } -) - internal val editPlaylistConstructorFingerprint = legacyFingerprint( name = "editPlaylistConstructorFingerprint", returnType = "V", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/PlaylistPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/PlaylistPatch.kt index 9f23ad2db..8d9fa6fb8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/PlaylistPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playlist/PlaylistPatch.kt @@ -7,13 +7,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.shared.mainactivity.getMainActivityMethod +import app.revanced.patches.youtube.utils.auth.authHookPatch import app.revanced.patches.youtube.utils.dismiss.dismissPlayerHookPatch import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch -import app.revanced.patches.youtube.utils.request.buildRequestPatch -import app.revanced.patches.youtube.utils.request.hookBuildRequest import app.revanced.patches.youtube.video.information.videoInformationPatch import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.methodOrThrow @@ -34,21 +33,10 @@ val playlistPatch = bytecodePatch( dismissPlayerHookPatch, playerTypeHookPatch, videoInformationPatch, - buildRequestPatch, + authHookPatch, ) execute { - // In Incognito mode, sending a request always seems to fail. - accountIdentityFingerprint.methodOrThrow().addInstructions( - 1, """ - sput-object p3, $EXTENSION_CLASS_DESCRIPTOR->dataSyncId:Ljava/lang/String; - sput-boolean p4, $EXTENSION_CLASS_DESCRIPTOR->isIncognito:Z - """ - ) - - // Get the header to use the auth token. - hookBuildRequest("$EXTENSION_CLASS_DESCRIPTOR->setRequestHeaders(Ljava/lang/String;Ljava/util/Map;)V") - // Open the queue manager by pressing and holding the back button. getMainActivityMethod("onKeyLongPress") .addInstructionsWithLabels(