diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/ByteTrieSearch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ByteTrieSearch.java similarity index 89% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/ByteTrieSearch.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/ByteTrieSearch.java index 162e0b040..c91de4a7a 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/ByteTrieSearch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ByteTrieSearch.java @@ -1,6 +1,4 @@ -package app.revanced.extension.youtube; - -import androidx.annotation.NonNull; +package app.revanced.extension.shared; import java.nio.charset.StandardCharsets; @@ -39,7 +37,7 @@ public final class ByteTrieSearch extends TrieSearch { return replacement; } - public ByteTrieSearch(@NonNull byte[]... patterns) { + public ByteTrieSearch(byte[]... patterns) { super(new ByteTrieNode(), patterns); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/StringTrieSearch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/StringTrieSearch.java similarity index 85% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/StringTrieSearch.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/StringTrieSearch.java index fbff9beba..9c7b88213 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/StringTrieSearch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/StringTrieSearch.java @@ -1,6 +1,4 @@ -package app.revanced.extension.youtube; - -import androidx.annotation.NonNull; +package app.revanced.extension.shared; /** * Text pattern searching using a prefix tree (trie). @@ -28,7 +26,7 @@ public final class StringTrieSearch extends TrieSearch { } } - public StringTrieSearch(@NonNull String... patterns) { + public StringTrieSearch(String... patterns) { super(new StringTrieNode(), patterns); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/TrieSearch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/TrieSearch.java similarity index 93% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/TrieSearch.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/TrieSearch.java index 74fb4685d..a871fc9b1 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/TrieSearch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/TrieSearch.java @@ -1,6 +1,5 @@ -package app.revanced.extension.youtube; +package app.revanced.extension.shared; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.ArrayList; @@ -8,8 +7,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -/** - * Searches for a group of different patterns using a trie (prefix tree). +/**Searches for a group of different patterns using a trie (prefix tree). * Can significantly speed up searching for multiple patterns. */ public abstract class TrieSearch { @@ -136,7 +134,7 @@ public abstract class TrieSearch { * @param patternLength Length of the pattern. * @param callback Callback, where a value of NULL indicates to always accept a pattern match. */ - private void addPattern(@NonNull T pattern, int patternIndex, int patternLength, + private void addPattern(T pattern, int patternIndex, int patternLength, @Nullable TriePatternMatchedCallback callback) { if (patternIndex == patternLength) { // Reached the end of the pattern. if (endOfPatternCallback == null) { @@ -308,13 +306,13 @@ public abstract class TrieSearch { private final List patterns = new ArrayList<>(); @SafeVarargs - TrieSearch(@NonNull TrieNode root, @NonNull T... patterns) { + TrieSearch(TrieNode root, T... patterns) { this.root = Objects.requireNonNull(root); addPatterns(patterns); } @SafeVarargs - public final void addPatterns(@NonNull T... patterns) { + public final void addPatterns(T... patterns) { for (T pattern : patterns) { addPattern(pattern); } @@ -325,7 +323,7 @@ public abstract class TrieSearch { * * @param pattern Pattern to add. Calling this with a zero length pattern does nothing. */ - public void addPattern(@NonNull T pattern) { + public void addPattern(T pattern) { addPattern(pattern, root.getTextLength(pattern), null); } @@ -333,31 +331,31 @@ public abstract class TrieSearch { * @param pattern Pattern to add. Calling this with a zero length pattern does nothing. * @param callback Callback to determine if searching should halt when a match is found. */ - public void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback callback) { + public void addPattern(T pattern, TriePatternMatchedCallback callback) { addPattern(pattern, root.getTextLength(pattern), Objects.requireNonNull(callback)); } - void addPattern(@NonNull T pattern, int patternLength, @Nullable TriePatternMatchedCallback callback) { + void addPattern(T pattern, int patternLength, @Nullable TriePatternMatchedCallback callback) { if (patternLength == 0) return; // Nothing to match patterns.add(pattern); root.addPattern(pattern, 0, patternLength, callback); } - public final boolean matches(@NonNull T textToSearch) { + public final boolean matches(T textToSearch) { return matches(textToSearch, 0); } - public boolean matches(@NonNull T textToSearch, @NonNull Object callbackParameter) { + public boolean matches(T textToSearch, Object callbackParameter) { return matches(textToSearch, 0, root.getTextLength(textToSearch), Objects.requireNonNull(callbackParameter)); } - public boolean matches(@NonNull T textToSearch, int startIndex) { + public boolean matches(T textToSearch, int startIndex) { return matches(textToSearch, startIndex, root.getTextLength(textToSearch)); } - public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) { + public final boolean matches(T textToSearch, int startIndex, int endIndex) { return matches(textToSearch, startIndex, endIndex, null); } @@ -370,11 +368,11 @@ public abstract class TrieSearch { * @param callbackParameter Optional parameter passed to the callbacks. * @return If any pattern matched, and it's callback halted searching. */ - public boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) { + public boolean matches(T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) { return matches(textToSearch, root.getTextLength(textToSearch), startIndex, endIndex, callbackParameter); } - private boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex, + private boolean matches(T textToSearch, int textToSearchLength, int startIndex, int endIndex, @Nullable Object callbackParameter) { if (endIndex > textToSearchLength) { throw new IllegalArgumentException("endIndex: " + endIndex diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java index 81e96b690..a9651e07a 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java @@ -1,5 +1,6 @@ package app.revanced.extension.shared.spoof.requests; +import static app.revanced.extension.shared.ByteTrieSearch.convertStringsToBytes; import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA; import androidx.annotation.NonNull; @@ -13,12 +14,18 @@ import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import app.revanced.extension.shared.ByteTrieSearch; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; @@ -93,6 +100,16 @@ public class StreamingDataRequest { } }); + /** + * Strings found in the response if the video is a livestream. + */ + private static final ByteTrieSearch liveStreamBufferSearch = new ByteTrieSearch( + convertStringsToBytes( + "yt_live_broadcast", + "yt_premiere_broadcast" + ) + ); + private static volatile ClientType lastSpoofedClientType; public static String getLastSpoofedClientName() { @@ -221,9 +238,13 @@ public class StreamingDataRequest { while ((bytesRead = inputStream.read(buffer)) >= 0) { baos.write(buffer, 0, bytesRead); } - lastSpoofedClientType = clientType; + if (clientType == ClientType.ANDROID_CREATOR && liveStreamBufferSearch.matches(buffer)) { + Logger.printDebug(() -> "Skipping Android Studio as video is a livestream: " + videoId); + } else { + lastSpoofedClientType = clientType; - return ByteBuffer.wrap(baos.toByteArray()); + return ByteBuffer.wrap(baos.toByteArray()); + } } } } catch (IOException ex) { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java index 027fdd84a..cb604c57b 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java @@ -10,7 +10,7 @@ import java.util.List; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; -import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.shared.StringTrieSearch; import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/CustomFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/CustomFilter.java index cd6950717..1fed2e967 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/CustomFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/CustomFilter.java @@ -14,7 +14,7 @@ import java.util.regex.Pattern; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; -import app.revanced.extension.youtube.ByteTrieSearch; +import app.revanced.extension.shared.ByteTrieSearch; import app.revanced.extension.youtube.settings.Settings; /** diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/DescriptionComponentsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/DescriptionComponentsFilter.java index c5f4ac33f..5c0870cde 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/DescriptionComponentsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/DescriptionComponentsFilter.java @@ -1,6 +1,6 @@ package app.revanced.extension.youtube.patches.components; -import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.shared.StringTrieSearch; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.PlayerType; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroup.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroup.java index 4e20bc82a..cf880b468 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroup.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroup.java @@ -4,7 +4,7 @@ import androidx.annotation.NonNull; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.settings.BooleanSetting; -import app.revanced.extension.youtube.ByteTrieSearch; +import app.revanced.extension.shared.ByteTrieSearch; abstract class FilterGroup { final static class FilterGroupResult { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroupList.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroupList.java index c10b563e9..f839436c0 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroupList.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/FilterGroupList.java @@ -5,9 +5,9 @@ import androidx.annotation.NonNull; import java.util.*; import java.util.function.Consumer; -import app.revanced.extension.youtube.ByteTrieSearch; -import app.revanced.extension.youtube.StringTrieSearch; -import app.revanced.extension.youtube.TrieSearch; +import app.revanced.extension.shared.ByteTrieSearch; +import app.revanced.extension.shared.StringTrieSearch; +import app.revanced.extension.shared.TrieSearch; abstract class FilterGroupList> implements Iterable { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/KeywordContentFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/KeywordContentFilter.java index 470b650bb..eecf17766 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/KeywordContentFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/KeywordContentFilter.java @@ -14,9 +14,9 @@ import java.util.concurrent.atomic.AtomicReference; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; -import app.revanced.extension.youtube.ByteTrieSearch; -import app.revanced.extension.youtube.StringTrieSearch; -import app.revanced.extension.youtube.TrieSearch; +import app.revanced.extension.shared.ByteTrieSearch; +import app.revanced.extension.shared.StringTrieSearch; +import app.revanced.extension.shared.TrieSearch; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.NavigationBar; import app.revanced.extension.youtube.shared.PlayerType; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java index 3635f25a8..7000b2a96 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java @@ -10,7 +10,7 @@ import androidx.annotation.Nullable; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; -import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.shared.StringTrieSearch; import app.revanced.extension.youtube.patches.ChangeHeaderPatch; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.NavigationBar; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java index e2ed04e63..2777dec11 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java @@ -8,7 +8,7 @@ import java.util.List; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.settings.BaseSettings; -import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.shared.StringTrieSearch; import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java index b82cb5f56..49a623b84 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java @@ -12,7 +12,7 @@ import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch; import app.revanced.extension.youtube.patches.VideoInformation; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.shared.Logger; -import app.revanced.extension.youtube.TrieSearch; +import app.revanced.extension.shared.TrieSearch; /** * Searches for video id's in the proto buffer of Shorts dislike. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java index 6cd8212fb..10562d489 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java @@ -22,11 +22,9 @@ public class SpoofVideoStreamsPatch { List availableClients = List.of( ANDROID_VR_1_61_48, VISIONOS, - IPADOS, - // Creator must be next to last, because livestreams fetch successfully but don't playback. ANDROID_CREATOR, - // VR 1.43 must be last as spoof streaming data handles it slightly differently. - ANDROID_VR_1_43_32 + ANDROID_VR_1_43_32, + IPADOS ); StreamingDataRequest.setClientOrderToUse(availableClients,