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] [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); + } +}