revanced-patches-template icon indicating copy to clipboard operation
revanced-patches-template copied to clipboard

feat: `disable-auto-captions` patch

Open OxrxL opened this issue 3 years ago • 30 comments

🐞 Issue

YouTube turn on captions (chosen based on the current region) automatically at the beginning of some videos.

❗ Solution

Adapt the following POC to ReVanced patches:

        public static void ForcedInitCaption()
        {
            ConsoleLog.Divider();

            ConsoleLog.StartPatch("Patching Forced Init Captions in progress...");

            string[] allFiles = Directory.GetFiles(Main.apkDecompiledPath, "*.smali*", SearchOption.AllDirectories);

            string firstReference = "\"pc\"";
            string secondReference = APKOps.GetResourceID("drawable", "quantum_ic_closed_caption_white_24");
            string thirdReference = "\"DISABLE_CAPTIONS_OPTION\"";
            string firstSubReference = ".method";
            string secondSubReference = "(Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;";
            string thirdSubReference = ".locals";
            string fourthSubReference = "# static fields";
            string fifthSubReference = "()Z";
            bool firstReferencePatched = false;
            bool secondReferencePatched = false;
            bool thirdReferencePatched = false;
            foreach (string file in allFiles)
            {
                string fullContent = File.ReadAllText(file);
                List<string> lines = new List<string>();

                if (!firstReferencePatched)
                {
                    if (fullContent.Contains(firstReference))
                    {
                        lines = File.ReadAllLines(file).ToList();

                        for (int i = 0; i < lines.Count; i++)
                        {
                            if (lines[i].Contains(firstReference))
                            {
                                for (int j = i; j >= 0; j--)
                                {
                                    if (lines[j].Contains(firstSubReference) &&
                                        lines[j].Contains(secondSubReference))
                                    {
                                        ConsoleLog.Found($"Found file: {Path.GetFileNameWithoutExtension(file)}", true);

                                        string[] firstPatch = {
                                            "const/4 v0, 0x0",
                                            "sput-boolean v0, Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;->disablecaption:Z"
                                        };

                                        lines.InsertRange(j + 2, firstPatch);

                                        File.WriteAllLines(file, lines);

                                        firstReferencePatched = true;

                                        break;
                                    }
                                }

                                if (firstReferencePatched)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                if (!secondReferencePatched)
                {
                    if (file.Contains("SubtitleButtonController.smali"))
                    {
                        lines = File.ReadAllLines(file).ToList();

                        for (int i = 0; i < lines.Count; i++)
                        {
                            if (lines[i].Contains(secondReference))
                            {
                                for (int j = i; j >= 0; j--)
                                {
                                    if (lines[j].Contains(thirdSubReference))
                                    {
                                        ConsoleLog.Found($"Found file: {Path.GetFileNameWithoutExtension(file)}", true);

                                        string[] secondPatch = {
                                            "const/4 v0, 0x1",
                                            "sput-boolean v0, Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;->disablecaption:Z"
                                        };

                                        lines.InsertRange(j + 1, secondPatch);

                                        File.WriteAllLines(file, lines);

                                        secondReferencePatched = true;

                                        break;
                                    }
                                }

                                if (secondReferencePatched)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                if (!thirdReferencePatched)
                {
                    if (file.Contains("SubtitleTrack.smali"))
                    {
                        lines = File.ReadAllLines(file).ToList();

                        for (int i = 0; i < lines.Count; i++)
                        {
                            if (lines[i].Contains(fourthSubReference))
                            {
                                string[] thirdSubPatch = {
                                    ".field public static disablecaption:Z"
                                };

                                lines.InsertRange(i + 1, thirdSubPatch);
                            }

                            if (lines[i].Contains(thirdReference))
                            {
                                for (int j = i; j >= 0; j--)
                                {
                                    if (lines[j].Contains(firstSubReference) &&
                                        lines[j].Contains(fifthSubReference))
                                    {
                                        ConsoleLog.Found($"Found file: {Path.GetFileNameWithoutExtension(file)}", true);

                                        string[] thirdPatch = {
                                            "sget-boolean v0, Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;->disablecaption:Z",
                                            "if-nez v0, :cond_disableinitcaption",
                                            "const/4 v0, 0x1",
                                            "return v0",
                                            ":cond_disableinitcaption"
                                        };

                                        lines.InsertRange(j + 2, thirdPatch);

                                        File.WriteAllLines(file, lines);

                                        thirdReferencePatched = true;

                                        break;
                                    }
                                }

                                if (thirdReferencePatched)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                if (firstReferencePatched &&
                    secondReferencePatched &&
                    thirdReferencePatched)
                {
                    break;
                }
            }
            if (!firstReferencePatched)
			{
                ConsoleLog.EndPatch("Error during searching and patching the first reference", false);
            }
            if (!secondReferencePatched)
            {
                ConsoleLog.EndPatch("Error during searching and patching the second reference", false);
            }
            if (!thirdReferencePatched)
            {
                ConsoleLog.EndPatch("Error during searching and patching the third reference", false);
            }

            if (firstReferencePatched &&
                secondReferencePatched &&
                thirdReferencePatched)
            {
                ConsoleLog.EndPatch("Forced Init Captions succesfully patched", true);
            }
            else
            {
                Main.buildingFailed = true;
            }
        }

❓ Motivation

This mod may be useful for those who intend to have as few interactions as possible with their device.

OxrxL avatar Jul 12 '22 11:07 OxrxL

I have tried it but this did not work for me.

oSumAtrIX avatar Jul 12 '22 12:07 oSumAtrIX

I have tried it but this did not work for me.

It working flawlessly for me.

Are you sure you have tested it on a video that automatically activates the captions? Otherwise nothing changes.

OxrxL avatar Jul 12 '22 12:07 OxrxL

Can you send one?

oSumAtrIX avatar Jul 12 '22 12:07 oSumAtrIX

Can you send one?

Already done in private, but it doesn't seem to work for everyone.

In any case, I'll try again:

The videos of this channel contains auto-captions:

https://youtu.be/NkHH4LX_kRg

OxrxL avatar Jul 12 '22 12:07 OxrxL

And this channel too:

https://youtu.be/3F5cV98isaY

OxrxL avatar Jul 12 '22 12:07 OxrxL

Works.

oSumAtrIX avatar Jul 12 '22 12:07 oSumAtrIX

Works.

Would have been very weird if it only worked on my device xD

OxrxL avatar Jul 12 '22 12:07 OxrxL

What is that code? Thats not referring to our Patcher?

TheJeterLP avatar Jul 12 '22 14:07 TheJeterLP

What is that code? Thats not referring to our Patcher?

This is code from my C# patcher.

I hate kotlin for various reason, first of all my inability to write a patch.

You can adapt the code if you want.

Just add a toggle to disable patch, at this point:

sget-boolean v0, Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;->disablecaption:Z
if-nez v0, :cond_disableinitcaption
const/4 v0, 0x1
return v0
:cond_disableinitcaption

OxrxL avatar Jul 12 '22 14:07 OxrxL

What is that code? Thats not referring to our Patcher?

This is code from my C# patcher.

I hate kotlin for various reason, first of all my inability to write a patch.

You can adapt the code if you want.

Just add a toggle to disable patch, at this point:

sget-boolean v0, Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;->disablecaption:Z
if-nez v0, :cond_disableinitcaption
const/4 v0, 0x1
return v0
:cond_disableinitcaption

So thats the same which vanced did, so we would have done this anyway, but thanks for helping us out :)

TheJeterLP avatar Jul 12 '22 14:07 TheJeterLP

What is that code? Thats not referring to our Patcher?

This is code from my C# patcher. I hate kotlin for various reason, first of all my inability to write a patch. You can adapt the code if you want. Just add a toggle to disable patch, at this point:

sget-boolean v0, Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;->disablecaption:Z
if-nez v0, :cond_disableinitcaption
const/4 v0, 0x1
return v0
:cond_disableinitcaption

So thats the same which vanced did, so we would have done this anyway, but thanks for helping us out :)

Nope... This was deprecated starting from vanced 15.xx, despite Vanced Team keep the reference inside settings.

The proof is there's no patch like that on Vanced 17.03.38.

OxrxL avatar Jul 12 '22 14:07 OxrxL

This would be way easier if you would actually provide class and method names :)

TheJeterLP avatar Jul 19 '22 14:07 TheJeterLP

This would be way easier if you would actually provide class and method names :)

Based on which version?

OxrxL avatar Jul 19 '22 15:07 OxrxL

The one from the docs

oSumAtrIX avatar Jul 19 '22 15:07 oSumAtrIX

This would be way easier if you would actually provide class and method names :)

17.27.39 --->

First reference: {method: public final void d, class: aamt.smali} Second reference: {method: public final void D, class: SubtitleButtonController.smali} Third reference: {method: public final boolean t, class: SubtitleTrack.smali}

OxrxL avatar Jul 19 '22 15:07 OxrxL

Thanks, I can work with that now :)

TheJeterLP avatar Jul 19 '22 15:07 TheJeterLP

Patch is not possible to create. Theres no way to generate a safe fingerprint for class aamt.

TheJeterLP avatar Jul 21 '22 15:07 TheJeterLP

Not required, you can create a parent fingerprint for a different method which references this one and use the method walker.

oSumAtrIX avatar Jul 21 '22 16:07 oSumAtrIX

Not required, you can create a parent fingerprint for a different method which references this one and use the method walker.

not possible. Those methods have no usages. Thats at least what jadx says.

TheJeterLP avatar Jul 21 '22 16:07 TheJeterLP

Not required, you can create a parent fingerprint for a different method which references this one and use the method walker.

not possible. Those methods have no usages. Thats at least what jadx says.

Searching for string:

"pc"

OxrxL avatar Jul 21 '22 16:07 OxrxL

And after searching for method

"(Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"

OxrxL avatar Jul 21 '22 16:07 OxrxL

Anyway...I posted the PoC for a reason.

All these infos was already listed there.

OxrxL avatar Jul 21 '22 16:07 OxrxL

And after searching for method

"(Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"

Returns 0 results.

TheJeterLP avatar Jul 21 '22 16:07 TheJeterLP

Not required, you can create a parent fingerprint for a different method which references this one and use the method walker.

not possible. Those methods have no usages. Thats at least what jadx says.

The class has, and since the class has you can get it from a parent method.

oSumAtrIX avatar Jul 21 '22 16:07 oSumAtrIX

And after searching for method "(Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"

Returns 0 results.

Instead this returns me, on my patcher at least, a method with the aformentioned variables. 🤷‍♂️

OxrxL avatar Jul 21 '22 16:07 OxrxL

Not required, you can create a parent fingerprint for a different method which references this one and use the method walker.

not possible. Those methods have no usages. Thats at least what jadx says.

Searching for string:

"pc"

"pc" is not contained in the class

TheJeterLP avatar Jul 21 '22 16:07 TheJeterLP

The class has, and since the class has you can get it from a parent method.

I'll check again tomorrow then

TheJeterLP avatar Jul 21 '22 16:07 TheJeterLP

Not required, you can create a parent fingerprint for a different method which references this one and use the method walker.

not possible. Those methods have no usages. Thats at least what jadx says.

Searching for string: "pc"

"pc" is not contained in the class

LOL Immagine 2022-07-21 190032

OxrxL avatar Jul 21 '22 17:07 OxrxL

And after searching for method "(Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"

Returns 0 results.

Instead this returns me, on my patcher at least, a method with the aformentioned variables. 🤷‍♂️

Open jadx, go to mentioned class, open smali view, Ctrl+f, search, and find nothing. Your patcher is not revanced. So We have to find a working way.

TheJeterLP avatar Jul 21 '22 17:07 TheJeterLP

And after searching for method "(Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"

Returns 0 results.

Instead this returns me, on my patcher at least, a method with the aformentioned variables. 🤷‍♂️

Open jadx, go to mentioned class, open smali view, Ctrl+f, search, and find nothing. Your patcher is not revanced. So We have to find a working way.

Already done.

You can see the screenshot in the answer preceding yours.

OxrxL avatar Jul 21 '22 17:07 OxrxL