diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 69489b44..48d82ec2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -49,6 +49,7 @@ dependencies { compileOnly(libs.annotation) compileOnly(libs.okhttp) compileOnly(libs.retrofit) + implementation("com.github.TeamNewPipe:NewPipeExtractor:0.24.0") compileOnly(project(":stub")) } diff --git a/app/src/main/java/app/revanced/Test.java b/app/src/main/java/app/revanced/Test.java index c7097e7d..cc92178f 100644 --- a/app/src/main/java/app/revanced/Test.java +++ b/app/src/main/java/app/revanced/Test.java @@ -1,47 +1,139 @@ package app.revanced; import android.net.Uri; +import androidx.annotation.Nullable; import app.revanced.integrations.shared.Logger; -import app.revanced.integrations.youtube.patches.spoof.requests.StoryboardRendererRequester; +import app.revanced.integrations.shared.Utils; +import app.revanced.integrations.youtube.requests.Requester; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.downloader.Downloader; +import org.schabi.newpipe.extractor.downloader.Request; +import org.schabi.newpipe.extractor.downloader.Response; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.services.youtube.YoutubeService; +import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; +import org.schabi.newpipe.extractor.stream.AudioStream; +import org.schabi.newpipe.extractor.stream.VideoStream; -import java.util.Map; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.*; public class Test { - private static Map formats; + private static Map formats = new HashMap<>(); - public static String hook(String s) { - if (!s.contains("googlevideo")) return s; - if (true) { - var c2 = new Throwable().getStackTrace()[2].toString(); - var c = new Throwable().getStackTrace()[1].toString(); - var itag = Uri.parse(s).getQueryParameter("itag"); - Logger.printInfo(() -> "Hooked " + c2 + ": itag: " + itag); - Logger.printInfo(() -> "Hooked " + c + ": itag: " + itag); + @Nullable + public static HttpURLConnection makeRequest(final Request request) { + try { + Utils.verifyOffMainThread(); + //Objects.requireNonNull(request.dataToSend()); - return s; + + HttpURLConnection connection = (HttpURLConnection) new URL(request.url()).openConnection(); + connection.setRequestMethod(request.httpMethod()); + + + String agentString = "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"; + connection.setRequestProperty("User-Agent", agentString); + + for (final Map.Entry> pair : request.headers().entrySet()) { + final String headerName = pair.getKey(); + final List headerValueList = pair.getValue(); + + if (headerValueList.size() > 1) { + for (final String headerValue : headerValueList) { + connection.addRequestProperty(headerName, headerValue); + } + } else if (headerValueList.size() == 1) { + connection.addRequestProperty(headerName, headerValueList.get(0)); + } + } + + final byte[] innerTubeBody = request.dataToSend(); + if (innerTubeBody != null) { + connection.getOutputStream().write(innerTubeBody, 0, innerTubeBody.length); + } + + final int responseCode = connection.getResponseCode(); + if (responseCode == 200) return connection; + else if (responseCode == 429) { + throw new Exception("reCaptcha Challenge requested"); + } else { + throw new Exception("Error making request: " + responseCode); + } + + } catch (Exception ignored) { + Logger.printInfo(() -> "Hooked Error making request: " + ignored.getMessage(), ignored); } - if (formats == null) - formats = StoryboardRendererRequester.getFormats("piKJAUwCYTo"); + return null; + } + public static String hook(String s) { + + if (!s.contains("googlevideo")) return s; + if (formats.isEmpty()) { + try { + NewPipe.init(new Downloader() { + @Override + public Response execute(Request request) throws IOException { + var c = makeRequest(request); + var r = new Response( + c.getResponseCode(), + c.getResponseMessage(), + c.getHeaderFields(), + Requester.parseString(c), + c.getURL().toString() + ); + c.disconnect();; + return r; + } + }); + var extractor = new YoutubeService(1).getStreamExtractor(YoutubeStreamLinkHandlerFactory.getInstance().fromId("piKJAUwCYTo")); + extractor.fetchPage(); + + for (AudioStream audioStream : extractor.getAudioStreams()) { + formats.put(audioStream.getItag(), audioStream.getContent()); + } + + for (VideoStream videoOnlyStream : extractor.getVideoOnlyStreams()) { + formats.put(videoOnlyStream.getItag(), videoOnlyStream.getContent()); + } + + for (VideoStream videoStream : extractor.getVideoStreams()) { + formats.put(videoStream.getItag(), videoStream.getContent()); + } + } catch (ExtractionException | IOException ignored) { + Logger.printInfo(() -> "Hooked Error making request: " + ignored.getMessage(), ignored); + } + + //formats = StoryboardRendererRequester.getFormats("piKJAUwCYTo"); + } var itag = Uri.parse(s).getQueryParameter("itag"); Logger.printInfo(() -> "Hooked itag: " + itag); if (itag == null) return s; - String m; + // find nearest key to itag + var availableTags = formats.keySet(); + Integer nearest; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { - m = formats.values().stream().findFirst().get(); + nearest = availableTags.stream().min(Comparator.comparingInt(a -> Math.abs(Integer.parseInt(itag) - a))).orElse(null); } else { - m = null; + nearest = null; } - Logger.printInfo(() -> "Hooked format: " + m); - if (m == null) return s; - - var c = new Throwable().getStackTrace()[1].toString(); - Logger.printInfo(() -> "Hooked " + c + ": From " + s + " to " + m); + Logger.printInfo(() -> "Hooked count: " + formats.size()); + Logger.printInfo(() -> "Hooked nearest " + nearest); + String m = formats.get(nearest); + Logger.printInfo(() -> String.valueOf(("Hooked format " + m == null))); + if (m == null) { + Logger.printInfo(() -> "Hooked format null"); + return s; + } + Logger.printInfo(() -> "Hooked"); return m; } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/PlayerRoutes.java b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/PlayerRoutes.java index 8d709abe..8fff9338 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/PlayerRoutes.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/PlayerRoutes.java @@ -10,7 +10,7 @@ import java.io.IOException; import java.net.HttpURLConnection; @Deprecated -final class PlayerRoutes { +public final class PlayerRoutes { private static final String YT_API_URL = "https://www.youtube.com/youtubei/v1/"; static final Route.CompiledRoute GET_STORYBOARD_SPEC_RENDERER = new Route( Route.Method.POST, @@ -84,10 +84,11 @@ final class PlayerRoutes { } /** @noinspection SameParameterValue*/ - static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route) throws IOException { + public static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route) throws IOException { var connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route); connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"); connection.setUseCaches(false); connection.setDoOutput(true); diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/StoryboardRendererRequester.java b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/StoryboardRendererRequester.java index eaa76763..17dc0138 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/StoryboardRendererRequester.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/requests/StoryboardRendererRequester.java @@ -49,6 +49,7 @@ public class StoryboardRendererRequester { Logger.printInfo(() -> toastMessage, ex); } + @Nullable private static JSONObject fetchPlayerResponse(@NonNull String requestBody, boolean showToastOnIOException) { final long startTime = System.currentTimeMillis(); diff --git a/settings.gradle.kts b/settings.gradle.kts index 61d1baa7..8c77d1f4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,6 +13,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url = uri("https://jitpack.io") } } }