From 1c789769009272fed9dcd33a122bca0ba59e6f62 Mon Sep 17 00:00:00 2001 From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com> Date: Thu, 29 Jul 2021 20:26:36 +0200 Subject: [PATCH 1/6] [YouTube] Expand regex to match n param decrypt function Temporary solution --- .../youtube/YoutubeThrottlingDecrypter.java | 2 +- .../YoutubeThrottlingDecrypterTest.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java index 4f10e8c5..1cf6cb49 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java @@ -70,7 +70,7 @@ public class YoutubeThrottlingDecrypter { @Nonnull private String parseDecodeFunction(final String playerJsCode, final String functionName) throws Parser.RegexException { - Pattern functionPattern = Pattern.compile(functionName + "=function(.*?;)\n", + Pattern functionPattern = Pattern.compile(functionName + "=function(.*?};)\n", Pattern.DOTALL); return "function " + functionName + Parser.matchGroup1(functionPattern, playerJsCode); } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java index f072615f..4a87245e 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java @@ -2,6 +2,7 @@ package org.schabi.newpipe.extractor.services.youtube; import org.junit.Before; import org.junit.Test; +import org.mozilla.javascript.EvaluatorException; import org.schabi.newpipe.downloader.DownloaderTestImpl; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.exceptions.ParsingException; @@ -11,6 +12,7 @@ import java.io.IOException; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; public class YoutubeThrottlingDecrypterTest { @@ -19,6 +21,22 @@ public class YoutubeThrottlingDecrypterTest { NewPipe.init(DownloaderTestImpl.getInstance()); } + @Test + public void testExtractFunction__success() throws ParsingException { + String[] videoIds = {"jE1USQrs1rw", "CqxjzfudGAc", "goH-9MfQI7w", "KYIdr_7H5Yw", "J1WeqmGbYeI"}; + + final String encryptedUrl = "https://r6---sn-4g5ednek.googlevideo.com/videoplayback?expire=1626562120&ei=6AnzYO_YBpql1gLGkb_IBQ&ip=127.0.0.1&id=o-ANhBEf36Z5h-8U9DDddtPDqtS0ZNwf0XJAAigudKI2uI&itag=278&aitags=133%2C134%2C135%2C136%2C137%2C160%2C242%2C243%2C244%2C247%2C248%2C278&source=youtube&requiressl=yes&vprv=1&mime=video%2Fwebm&ns=TvecOReN0vPuXb3j_zq157IG&gir=yes&clen=2915100&dur=270.203&lmt=1608157174907785&keepalive=yes&fexp=24001373,24007246&c=WEB&txp=5535432&n=N9BWSTFT7vvBJrvQ&sparams=expire%2Cei%2Cip%2Cid%2Caitags%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&alr=yes&sig=AOq0QJ8wRQIgW6XnUDKPDSxiT0_KE_tDDMpcaCJl2Un5p0Fu9qZNQGkCIQDWxsDHi_s2BEmRqIbd1C5g_gzfihB7RZLsScKWNMwzzA%3D%3D&cpn=9r2yt3BqcYmeb2Yu&cver=2.20210716.00.00&redirect_counter=1&cm2rm=sn-4g5ezy7s&cms_redirect=yes&mh=Y5&mm=34&mn=sn-4g5ednek&ms=ltu&mt=1626540524&mv=m&mvi=6&pl=43&lsparams=mh,mm,mn,ms,mv,mvi,pl&lsig=AG3C_xAwRQIhAIUzxTn9Vw1-vm-_7OQ5-0h1M6AZsY9Bx1FlCCTeMICzAiADtGggbn4Znsrh2EnvyOsGnYdRGcbxn4mW9JMOQiInDQ%3D%3D&range=259165-480735&rn=11&rbuf=20190"; + + for (String videoId : videoIds) { + try { + final String decryptedUrl = new YoutubeThrottlingDecrypter(videoId).apply(encryptedUrl); + assertNotEquals(encryptedUrl, decryptedUrl); + } catch (EvaluatorException e) { + fail("Failed to extract n param decrypt function for video " + videoId + "\n" + e); + } + } + } + @Test public void testDecode__success() throws ParsingException { // URL extracted from browser with the dev tools From 2967d1ae6afdbd0ff391e48ecb7528f300b76c7a Mon Sep 17 00:00:00 2001 From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com> Date: Thu, 29 Jul 2021 20:27:29 +0200 Subject: [PATCH 2/6] [YouTube] Compile YoutubeThrottlingDecrypter pattern statically --- .../youtube/YoutubeThrottlingDecrypter.java | 14 +++++++------- .../org/schabi/newpipe/extractor/utils/Parser.java | 5 +++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java index 1cf6cb49..678b7968 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java @@ -33,7 +33,10 @@ import java.util.regex.Pattern; */ public class YoutubeThrottlingDecrypter { - private static final String N_PARAM_REGEX = "[&?]n=([^&]+)"; + private static final Pattern N_PARAM_PATTERN = Pattern.compile("[&?]n=([^&]+)"); + private static final Pattern FUNCTION_NAME_PATTERN = Pattern.compile( + "b=a\\.get\\(\"n\"\\)\\)&&\\(b=(\\w+)\\(b\\),a\\.set\\(\"n\",b\\)"); + private static final Map nParams = new HashMap<>(); private final String functionName; @@ -62,9 +65,7 @@ public class YoutubeThrottlingDecrypter { private String parseDecodeFunctionName(final String playerJsCode) throws Parser.RegexException { - Pattern pattern = Pattern.compile( - "b=a\\.get\\(\"n\"\\)\\)&&\\(b=(\\w+)\\(b\\),a\\.set\\(\"n\",b\\)"); - return Parser.matchGroup1(pattern, playerJsCode); + return Parser.matchGroup1(FUNCTION_NAME_PATTERN, playerJsCode); } @Nonnull @@ -86,12 +87,11 @@ public class YoutubeThrottlingDecrypter { } private boolean containsNParam(final String url) { - return Parser.isMatch(N_PARAM_REGEX, url); + return Parser.isMatch(N_PARAM_PATTERN, url); } private String parseNParam(final String url) throws Parser.RegexException { - Pattern nValuePattern = Pattern.compile(N_PARAM_REGEX); - return Parser.matchGroup1(nValuePattern, url); + return Parser.matchGroup1(N_PARAM_PATTERN, url); } private String decryptNParam(final String nParam) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java index 44368de2..0a766fd1 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java @@ -84,6 +84,11 @@ public class Parser { return mat.find(); } + public static boolean isMatch(Pattern pattern, String input) { + Matcher mat = pattern.matcher(input); + return mat.find(); + } + public static Map compatParseMap(final String input) throws UnsupportedEncodingException { Map map = new HashMap<>(); for (String arg : input.split("&")) { From 60794aea314a4db3c5a89d2d77e1c276f944f794 Mon Sep 17 00:00:00 2001 From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com> Date: Thu, 29 Jul 2021 21:23:00 +0200 Subject: [PATCH 3/6] [YouTube] Add parenthesis matching as way to parse decrypt function From @Stypox --- .../youtube/YoutubeThrottlingDecrypter.java | 16 ++++++- .../newpipe/extractor/utils/StringUtil.java | 47 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java index 678b7968..8de3ac98 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java @@ -3,6 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.utils.JavaScript; import org.schabi.newpipe.extractor.utils.Parser; +import org.schabi.newpipe.extractor.utils.StringUtil; import javax.annotation.Nonnull; import java.util.HashMap; @@ -71,7 +72,20 @@ public class YoutubeThrottlingDecrypter { @Nonnull private String parseDecodeFunction(final String playerJsCode, final String functionName) throws Parser.RegexException { - Pattern functionPattern = Pattern.compile(functionName + "=function(.*?};)\n", + try { + return parseWithParenthesisMatching(playerJsCode, functionName); + } catch (Exception e) { + return parseWithRegex(playerJsCode, functionName); + } + } + + private String parseWithParenthesisMatching(final String playerJsCode, final String functionName) { + final String functionBase = functionName + "=function"; + return functionBase + StringUtil.matchToClosingParenthesis(playerJsCode, functionBase) + ";"; + } + + private String parseWithRegex(final String playerJsCode, final String functionName) throws Parser.RegexException { + Pattern functionPattern = Pattern.compile(functionName + "=function(.*?}};)\n", Pattern.DOTALL); return "function " + functionName + Parser.matchGroup1(functionPattern, playerJsCode); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java new file mode 100644 index 00000000..42f8d962 --- /dev/null +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java @@ -0,0 +1,47 @@ +package org.schabi.newpipe.extractor.utils; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class StringUtil { + + private StringUtil() { + } + + /** + * @param string The string to search in + * @param start A string from which to start searching. + * @return A substring where each '{' matches a '}' + * @throws IndexOutOfBoundsException If {@ string} does not contain {@code start} + */ + @NonNull + public static String matchToClosingParenthesis(@NonNull final String string, @NonNull final String start) { + int startIndex = string.indexOf(start); + if (startIndex < 0) { + throw new IndexOutOfBoundsException(); + } + + startIndex += start.length(); + int endIndex = startIndex; + while (string.charAt(endIndex) != '{') { + ++endIndex; + } + ++endIndex; + + int openParenthesis = 1; + while (openParenthesis > 0) { + switch (string.charAt(endIndex)) { + case '{': + ++openParenthesis; + break; + case '}': + --openParenthesis; + break; + default: + break; + } + ++endIndex; + } + + return string.substring(startIndex, endIndex); + } +} From 48d897e6ad1643e24f0e1a943988d7b31abce30a Mon Sep 17 00:00:00 2001 From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com> Date: Thu, 29 Jul 2021 21:33:45 +0200 Subject: [PATCH 4/6] Add final and adjust utils class name --- .../youtube/YoutubeThrottlingDecrypter.java | 4 ++-- .../org/schabi/newpipe/extractor/utils/Parser.java | 6 +++--- .../utils/{StringUtil.java => StringUtils.java} | 13 +++++++------ .../youtube/YoutubeThrottlingDecrypterTest.java | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) rename extractor/src/main/java/org/schabi/newpipe/extractor/utils/{StringUtil.java => StringUtils.java} (76%) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java index 8de3ac98..fb56e2c7 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypter.java @@ -3,7 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.utils.JavaScript; import org.schabi.newpipe.extractor.utils.Parser; -import org.schabi.newpipe.extractor.utils.StringUtil; +import org.schabi.newpipe.extractor.utils.StringUtils; import javax.annotation.Nonnull; import java.util.HashMap; @@ -81,7 +81,7 @@ public class YoutubeThrottlingDecrypter { private String parseWithParenthesisMatching(final String playerJsCode, final String functionName) { final String functionBase = functionName + "=function"; - return functionBase + StringUtil.matchToClosingParenthesis(playerJsCode, functionBase) + ";"; + return functionBase + StringUtils.matchToClosingParenthesis(playerJsCode, functionBase) + ";"; } private String parseWithRegex(final String playerJsCode, final String functionName) throws Parser.RegexException { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java index 0a766fd1..5b25ed76 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java @@ -79,13 +79,13 @@ public class Parser { } public static boolean isMatch(String pattern, String input) { - Pattern pat = Pattern.compile(pattern); - Matcher mat = pat.matcher(input); + final Pattern pat = Pattern.compile(pattern); + final Matcher mat = pat.matcher(input); return mat.find(); } public static boolean isMatch(Pattern pattern, String input) { - Matcher mat = pattern.matcher(input); + final Matcher mat = pattern.matcher(input); return mat.find(); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java similarity index 76% rename from extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java rename to extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java index 42f8d962..3f0af27c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtil.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java @@ -1,20 +1,21 @@ package org.schabi.newpipe.extractor.utils; -import edu.umd.cs.findbugs.annotations.NonNull; -public class StringUtil { +import javax.annotation.Nonnull; - private StringUtil() { +public class StringUtils { + + private StringUtils() { } /** * @param string The string to search in * @param start A string from which to start searching. * @return A substring where each '{' matches a '}' - * @throws IndexOutOfBoundsException If {@ string} does not contain {@code start} + * @throws IndexOutOfBoundsException If {@code string} does not contain {@code start} */ - @NonNull - public static String matchToClosingParenthesis(@NonNull final String string, @NonNull final String start) { + @Nonnull + public static String matchToClosingParenthesis(@Nonnull final String string, @Nonnull final String start) { int startIndex = string.indexOf(start); if (startIndex < 0) { throw new IndexOutOfBoundsException(); diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java index 4a87245e..5d107594 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingDecrypterTest.java @@ -23,11 +23,11 @@ public class YoutubeThrottlingDecrypterTest { @Test public void testExtractFunction__success() throws ParsingException { - String[] videoIds = {"jE1USQrs1rw", "CqxjzfudGAc", "goH-9MfQI7w", "KYIdr_7H5Yw", "J1WeqmGbYeI"}; + final String[] videoIds = {"jE1USQrs1rw", "CqxjzfudGAc", "goH-9MfQI7w", "KYIdr_7H5Yw", "J1WeqmGbYeI"}; final String encryptedUrl = "https://r6---sn-4g5ednek.googlevideo.com/videoplayback?expire=1626562120&ei=6AnzYO_YBpql1gLGkb_IBQ&ip=127.0.0.1&id=o-ANhBEf36Z5h-8U9DDddtPDqtS0ZNwf0XJAAigudKI2uI&itag=278&aitags=133%2C134%2C135%2C136%2C137%2C160%2C242%2C243%2C244%2C247%2C248%2C278&source=youtube&requiressl=yes&vprv=1&mime=video%2Fwebm&ns=TvecOReN0vPuXb3j_zq157IG&gir=yes&clen=2915100&dur=270.203&lmt=1608157174907785&keepalive=yes&fexp=24001373,24007246&c=WEB&txp=5535432&n=N9BWSTFT7vvBJrvQ&sparams=expire%2Cei%2Cip%2Cid%2Caitags%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&alr=yes&sig=AOq0QJ8wRQIgW6XnUDKPDSxiT0_KE_tDDMpcaCJl2Un5p0Fu9qZNQGkCIQDWxsDHi_s2BEmRqIbd1C5g_gzfihB7RZLsScKWNMwzzA%3D%3D&cpn=9r2yt3BqcYmeb2Yu&cver=2.20210716.00.00&redirect_counter=1&cm2rm=sn-4g5ezy7s&cms_redirect=yes&mh=Y5&mm=34&mn=sn-4g5ednek&ms=ltu&mt=1626540524&mv=m&mvi=6&pl=43&lsparams=mh,mm,mn,ms,mv,mvi,pl&lsig=AG3C_xAwRQIhAIUzxTn9Vw1-vm-_7OQ5-0h1M6AZsY9Bx1FlCCTeMICzAiADtGggbn4Znsrh2EnvyOsGnYdRGcbxn4mW9JMOQiInDQ%3D%3D&range=259165-480735&rn=11&rbuf=20190"; - for (String videoId : videoIds) { + for (final String videoId : videoIds) { try { final String decryptedUrl = new YoutubeThrottlingDecrypter(videoId).apply(encryptedUrl); assertNotEquals(encryptedUrl, decryptedUrl); From 852a65ff18411454f67adaeb3dbcb0d7c47270e0 Mon Sep 17 00:00:00 2001 From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com> Date: Fri, 30 Jul 2021 19:56:29 +0200 Subject: [PATCH 5/6] Add tests for StringUtils --- .../newpipe/extractor/utils/StringUtils.java | 3 +- .../extractor/utils/StringUtilsTest.java | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/utils/StringUtilsTest.java diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java index 3f0af27c..66f79360 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java @@ -29,7 +29,8 @@ public class StringUtils { ++endIndex; int openParenthesis = 1; - while (openParenthesis > 0) { + int length = string.length(); + while (openParenthesis > 0 && endIndex < length) { switch (string.charAt(endIndex)) { case '{': ++openParenthesis; diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/utils/StringUtilsTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/utils/StringUtilsTest.java new file mode 100644 index 00000000..17eb9f9a --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/utils/StringUtilsTest.java @@ -0,0 +1,61 @@ +package org.schabi.newpipe.extractor.utils; + +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.schabi.newpipe.extractor.utils.StringUtils.matchToClosingParenthesis; + +public class StringUtilsTest { + + @Test + public void actualDecodeFunction__success() { + String preNoise = "if(\"function\"===typeof b&&\"function\"===typeof c||\"function\"===typeof c&&\"function\"===typeof d)throw Error(\"It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function.\");\"function\"===typeof b&&\"undefined\"===typeof c&&(c=b,b=void 0);if(\"undefined\"!==typeof c){if(\"function\"!==typeof c)throw Error(\"Expected the enhancer to be a function.\");return c(Dr)(a,b)}if(\"function\"!==typeof a)throw Error(\"Expected the reducer to be a function.\");\n" + + "var l=a,m=b,n=[],p=n,q=!1;h({type:Cr});a={};var t=(a.dispatch=h,a.subscribe=f,a.getState=e,a.replaceReducer=function(u){if(\"function\"!==typeof u)throw Error(\"Expected the nextReducer to be a function.\");l=u;h({type:hha});return t},a[Er]=function(){var u={};\n" + + "return u.subscribe=function(x){function y(){x.next&&x.next(e())}\n" + + "if(\"object\"!==typeof x||null===x)throw new TypeError(\"Expected the observer to be an object.\");y();return{unsubscribe:f(y)}},u[Er]=function(){return this},u},a);\n" + + "return t};\n" + + "Fr=function(a){De.call(this,a,-1,iha)};\n" + + "Gr=function(a){De.call(this,a)};\n" + + "jha=function(a,b){for(;Jd(b);)switch(b.C){case 10:var c=Od(b);Ge(a,1,c);break;case 18:c=Od(b);Ge(a,2,c);break;case 26:c=Od(b);Ge(a,3,c);break;case 34:c=Od(b);Ge(a,4,c);break;case 40:c=Hd(b.i);Ge(a,5,c);break;default:if(!we(b))return a}return a};"; + String signature = "kha=function(a)"; + String body = "{var b=a.split(\"\"),c=[-1186681497,-1653318181,372630254,function(d,e){for(var f=64,h=[];++f-h.length-32;){switch(f){case 58:f-=14;case 91:case 92:case 93:continue;case 123:f=47;case 94:case 95:case 96:continue;case 46:f=95}h.push(String.fromCharCode(f))}d.forEach(function(l,m,n){this.push(n[m]=h[(h.indexOf(l)-h.indexOf(this[m])+m-32+f--)%h.length])},e.split(\"\"))},\n" + + "-467738125,1158037010,function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f},\n" + + "\"continue\",158531598,-172776392,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},\n" + + "-1753359936,function(d){for(var e=d.length;e;)d.push(d.splice(--e,1)[0])},\n" + + "1533713399,-1736576025,-1274201783,function(d){d.reverse()},\n" + + "169126570,1077517431,function(d,e){d.push(e)},\n" + + "-1807932259,-150219E3,480561184,-3495188,-1856307605,1416497372,b,-1034568435,-501230371,1979778585,null,b,-1049521459,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},\n" + + "1119056651,function(d,e){for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())},\n" + + "b,1460920438,135616752,-1807932259,-815823682,-387465417,1979778585,113585E4,function(d,e){d.push(e)},\n" + + "-1753359936,-241651400,-386043301,-144139513,null,null,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(e,1)}];\n" + + "c[30]=c;c[49]=c;c[50]=c;try{c[51](c[26],c[25]),c[10](c[30],c[17]),c[5](c[28],c[9]),c[18](c[51]),c[14](c[19],c[21]),c[8](c[40],c[22]),c[50](c[35],c[28]),c[24](c[29],c[3]),c[0](c[31],c[19]),c[27](c[26],c[33]),c[29](c[36],c[40]),c[50](c[26]),c[27](c[32],c[9]),c[8](c[10],c[14]),c[35](c[44],c[28]),c[22](c[44],c[1]),c[8](c[11],c[3]),c[29](c[44]),c[21](c[41],c[45]),c[16](c[32],c[4]),c[17](c[14],c[26]),c[36](c[20],c[45]),c[43](c[35],c[39]),c[43](c[20],c[23]),c[43](c[10],c[51]),c[43](c[34],c[32]),c[29](c[34],\n" + + "c[49]),c[43](c[20],c[44]),c[49](c[20]),c[19](c[15],c[8]),c[36](c[15],c[46]),c[17](c[20],c[37]),c[18](c[10]),c[17](c[34],c[31]),c[19](c[10],c[30]),c[19](c[20],c[2]),c[36](c[20],c[21]),c[43](c[35],c[16]),c[19](c[35],c[5]),c[18](c[46],c[34])}catch(d){return\"enhanced_except_lJMB6-z-_w8_\"+a}return b.join(\"\")}"; + String postNoise = "Hr=function(a){this.i=a}"; + + String substring = matchToClosingParenthesis(preNoise + '\n' + signature + body + ";" + postNoise, signature); + + assertEquals(body, substring); + } + + @Test + public void moreClosing__success() { + String expected = "{{{}}}"; + String string = "a" + expected + "}}"; + + String substring = matchToClosingParenthesis(string, "a"); + + assertEquals(expected, substring); + } + + @Ignore("Functionality currently not needed") + @Test + public void lessClosing__success() { + String expected = "{{{}}}"; + String string = "a{{" + expected; + + String substring = matchToClosingParenthesis(string, "a"); + + assertEquals(expected, substring); + } +} \ No newline at end of file From 37df22555638c457aaac855e8a5ef087ee3fd044 Mon Sep 17 00:00:00 2001 From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com> Date: Sat, 31 Jul 2021 16:05:24 +0200 Subject: [PATCH 6/6] Remove length check from StringUtils.matchToClosingParenthesis --- .../org/schabi/newpipe/extractor/utils/StringUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java index 66f79360..a0429156 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/StringUtils.java @@ -9,10 +9,11 @@ public class StringUtils { } /** - * @param string The string to search in + * @param string The string to search in. * @param start A string from which to start searching. - * @return A substring where each '{' matches a '}' + * @return A substring where each '{' matches a '}'. * @throws IndexOutOfBoundsException If {@code string} does not contain {@code start} + * or parenthesis could not be matched . */ @Nonnull public static String matchToClosingParenthesis(@Nonnull final String string, @Nonnull final String start) { @@ -29,8 +30,7 @@ public class StringUtils { ++endIndex; int openParenthesis = 1; - int length = string.length(); - while (openParenthesis > 0 && endIndex < length) { + while (openParenthesis > 0) { switch (string.charAt(endIndex)) { case '{': ++openParenthesis;