From cda1f3160c12d239df1183799ead39526cbac20f Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:22:42 +0400 Subject: [PATCH 01/32] fix(YouTube - Hide keyword content): Do not hide flyout menu --- .../components/KeywordContentFilter.java | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java index c3813178d9..19dc25c0bf 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java @@ -18,6 +18,7 @@ import app.revanced.integrations.shared.Logger; import app.revanced.integrations.shared.Utils; import app.revanced.integrations.youtube.ByteTrieSearch; +import app.revanced.integrations.youtube.StringTrieSearch; import app.revanced.integrations.youtube.TrieSearch; import app.revanced.integrations.youtube.settings.Settings; import app.revanced.integrations.youtube.shared.NavigationBar; @@ -59,11 +60,15 @@ final class KeywordContentFilter extends Filter { */ private static final String[] STRINGS_IN_EVERY_BUFFER = { // Video playback data. - "https://i.ytimg.com/vi/", // Thumbnail url. - "sddefault.jpg", // More video sizes exist, but for most devices only these 2 are used. - "hqdefault.webp", "googlevideo.com/initplayback?source=youtube", // Video url. "ANDROID", // Video url parameter. + "https://i.ytimg.com/vi/", // Thumbnail url. + "mqdefault.jpg", + "hqdefault.jpg", + "sddefault.jpg", + "hq720.jpg", + "webp", + "_custom_", // Custom thumbnail set by video creator. // Video decoders. "OMX.ffmpeg.vp9.decoder", "OMX.Intel.sw_vd.vp9", @@ -75,15 +80,21 @@ final class KeywordContentFilter extends Filter { "c2.android.av1-dav1d.decoder", "c2.android.vp9.decoder", "c2.mtk.sw.vp9.decoder", - // User analytics. - "https://ad.doubleclick.net/ddm/activity/", - "DEVICE_ADVERTISER_ID_FOR_CONVERSION_TRACKING", - "tag_for_child_directed_treatment", // Found in overflow menu such as 'Watch later'. - // Litho components frequently found in the buffer that belong to the path filter items. - "metadata.eml", + // Analytics. + "searchR", + "browse-feed", + "FEwhat_to_watch", + "FEsubscriptions", + "search_vwc_description_transition_key", + "g-high-recZ", + // Text and litho components found in the buffer that belong to path filters. "thumbnail.eml", "avatar.eml", "overflow_button.eml", + "shorts-lockup-image", + "eml.shorts-lockup.overlay-metadata.secondary-text", + "YouTubeSans-SemiBold", + "sans-serif" }; /** @@ -112,6 +123,20 @@ final class KeywordContentFilter extends Filter { "video_card.eml" // Shorts that appear in a horizontal shelf. ); + /** + * Path components to not filter. Cannot filter the buffer when these are present, + * otherwise text in UI controls can be filtered as a keyword (such as using "Playlist" as a keyword). + * + * This is also a small performance improvement since + * the buffer of the parent component was already searched and passed. + */ + private final StringTrieSearch exceptions = new StringTrieSearch( + "metadata.eml", + "thumbnail.eml", + "avatar.eml", + "overflow_button.eml" + ); + /** * Threshold for {@link #filteredVideosPercentage} * that indicates all or nearly all videos have been filtered. @@ -361,6 +386,10 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff if (!hideKeywordSettingIsActive()) return false; + if (exceptions.matches(path)) { + return false; // Do not update statistics. + } + MutableReference matchRef = new MutableReference<>(); if (bufferSearch.matches(protobufBufferArray, matchRef)) { updateStats(true, matchRef.value); From 946923926496f60546503d41b68b1cfded3a0d27 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:45:44 +0400 Subject: [PATCH 02/32] refactor --- .../youtube/patches/components/KeywordContentFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java index 19dc25c0bf..d4de78702c 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java @@ -146,7 +146,7 @@ final class KeywordContentFilter extends Filter { private static final float ALL_VIDEOS_FILTERED_SAMPLE_SIZE = 50; - private static final long ALL_VIDEOS_FILTERED_TIMEOUT_MILLISECONDS = 60 * 1000; // 60 seconds + private static final long ALL_VIDEOS_FILTERED_BACKOFF_MILLISECONDS = 60 * 1000; // 60 seconds /** * Rolling average of how many videos were filtered by a keyword. @@ -364,7 +364,7 @@ private void updateStats(boolean videoWasHidden, @Nullable String keyword) { // A keyword is hiding everything. // Inform the user, and temporarily turn off filtering. - timeToResumeFiltering = System.currentTimeMillis() + ALL_VIDEOS_FILTERED_TIMEOUT_MILLISECONDS; + timeToResumeFiltering = System.currentTimeMillis() + ALL_VIDEOS_FILTERED_BACKOFF_MILLISECONDS; Logger.printDebug(() -> "Temporarily turning off filtering due to excessively broad filter: " + keyword); Utils.showToastLong(str("revanced_hide_keyword_toast_invalid_broad", keyword)); From d8d2a852d3879060bd95cc43d66c7cf195e82b43 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:48:36 +0400 Subject: [PATCH 03/32] fix: adjust blacklist --- .../youtube/patches/components/KeywordContentFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java index d4de78702c..56f044c40a 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java @@ -88,11 +88,12 @@ final class KeywordContentFilter extends Filter { "search_vwc_description_transition_key", "g-high-recZ", // Text and litho components found in the buffer that belong to path filters. + "metadata.eml", "thumbnail.eml", "avatar.eml", "overflow_button.eml", "shorts-lockup-image", - "eml.shorts-lockup.overlay-metadata.secondary-text", + "shorts-lockup.overlay-metadata.secondary-text", "YouTubeSans-SemiBold", "sans-serif" }; From 6fe85a21e9f8577f359ef74ec9ff25b5dc83d252 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 12 Jul 2024 17:52:23 +0000 Subject: [PATCH 04/32] chore(release): 1.11.2-dev.1 [skip ci] ## [1.11.2-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.1...v1.11.2-dev.1) (2024-07-12) ### Bug Fixes * adjust blacklist ([d8d2a85](https://github.com/ReVanced/revanced-integrations/commit/d8d2a852d3879060bd95cc43d66c7cf195e82b43)) * **YouTube - Hide keyword content:** Do not hide flyout menu ([cda1f31](https://github.com/ReVanced/revanced-integrations/commit/cda1f3160c12d239df1183799ead39526cbac20f)) * **YouTube - Hide keyword content:** Do not hide flyout menu ([#664](https://github.com/ReVanced/revanced-integrations/issues/664)) ([120188d](https://github.com/ReVanced/revanced-integrations/commit/120188d6431b5500d6fde9cec136c752f8ee0ea4)) --- CHANGELOG.md | 9 +++++++++ gradle.properties | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 179672a0fb..07f772f8cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [1.11.2-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.1...v1.11.2-dev.1) (2024-07-12) + + +### Bug Fixes + +* adjust blacklist ([d8d2a85](https://github.com/ReVanced/revanced-integrations/commit/d8d2a852d3879060bd95cc43d66c7cf195e82b43)) +* **YouTube - Hide keyword content:** Do not hide flyout menu ([cda1f31](https://github.com/ReVanced/revanced-integrations/commit/cda1f3160c12d239df1183799ead39526cbac20f)) +* **YouTube - Hide keyword content:** Do not hide flyout menu ([#664](https://github.com/ReVanced/revanced-integrations/issues/664)) ([120188d](https://github.com/ReVanced/revanced-integrations/commit/120188d6431b5500d6fde9cec136c752f8ee0ea4)) + ## [1.11.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.0...v1.11.1) (2024-07-11) diff --git a/gradle.properties b/gradle.properties index f06d6a4b21..93401cba23 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.11.1 +version = 1.11.2-dev.1 From 34ef27de798bd5c894985b429defa820de066e36 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 13 Jul 2024 00:44:39 +0200 Subject: [PATCH 05/32] ci: Correct usage of repository variable --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index edb9d1b8af..b06d6b240f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,7 +45,7 @@ jobs: with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PASSPHRASE }} - fingerprint: ${{ env.GPG_FINGERPRINT }} + fingerprint: ${{ vars.GPG_FINGERPRINT }} - name: Release env: From 7cdaf8df146fdc0da8254a27d9c125f1e3d34765 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 13 Jul 2024 19:32:40 +0400 Subject: [PATCH 06/32] fix(YouTube - Alternative thumbnails): Always use primary thumbnail domain for still captures (#666) --- .../patches/AlternativeThumbnailsPatch.java | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch.java index df7aab9fcd..c34841da5c 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch.java @@ -190,16 +190,17 @@ private static ThumbnailOption optionSettingForCurrentNavigation() { * Build the alternative thumbnail url using YouTube provided still video captures. * * @param decodedUrl Decoded original thumbnail request url. - * @return The alternative thumbnail url, or the original url. Both without tracking parameters. + * @return The alternative thumbnail url, or if not available NULL. */ - @NonNull - private static String buildYoutubeVideoStillURL(@NonNull DecodedThumbnailUrl decodedUrl, + @Nullable + private static String buildYouTubeVideoStillURL(@NonNull DecodedThumbnailUrl decodedUrl, @NonNull ThumbnailQuality qualityToUse) { String sanitizedReplacement = decodedUrl.createStillsUrl(qualityToUse, false); if (VerifiedQualities.verifyAltThumbnailExist(decodedUrl.videoId, qualityToUse, sanitizedReplacement)) { return sanitizedReplacement; } - return decodedUrl.sanitizedUrl; + + return null; } /** @@ -284,14 +285,21 @@ public static String overrideImageURL(String originalUrl) { final boolean includeTracking; if (option.useDeArrow && canUseDeArrowAPI()) { includeTracking = false; // Do not include view tracking parameters with API call. - final String fallbackUrl = option.useStillImages - ? buildYoutubeVideoStillURL(decodedUrl, qualityToUse) - : decodedUrl.sanitizedUrl; + String fallbackUrl = null; + if (option.useStillImages) { + fallbackUrl = buildYouTubeVideoStillURL(decodedUrl, qualityToUse); + } + if (fallbackUrl == null) { + fallbackUrl = decodedUrl.sanitizedUrl; + } sanitizedReplacementUrl = buildDeArrowThumbnailURL(decodedUrl.videoId, fallbackUrl); } else if (option.useStillImages) { includeTracking = true; // Include view tracking parameters if present. - sanitizedReplacementUrl = buildYoutubeVideoStillURL(decodedUrl, qualityToUse); + sanitizedReplacementUrl = buildYouTubeVideoStillURL(decodedUrl, qualityToUse); + if (sanitizedReplacementUrl == null) { + return originalUrl; // Still capture is not available. Return the untouched original url. + } } else { return originalUrl; // Recently experienced DeArrow failure and video stills are not enabled. } @@ -345,7 +353,7 @@ public static void handleCronetSuccess(UrlRequest request, @NonNull UrlResponseI return; // Not a thumbnail. } - Logger.printDebug(() -> "handleCronetSuccess, image not available: " + url); + Logger.printDebug(() -> "handleCronetSuccess, image not available: " + decodedUrl.sanitizedUrl); ThumbnailQuality quality = ThumbnailQuality.altImageNameToQuality(decodedUrl.imageQuality); if (quality == null) { @@ -627,14 +635,17 @@ synchronized boolean verifyYouTubeThumbnailExists(@NonNull String videoId, @NonN * YouTube video thumbnail url, decoded into it's relevant parts. */ private static class DecodedThumbnailUrl { - /** - * YouTube thumbnail URL prefix. Can be '/vi/' or '/vi_webp/' - */ - private static final String YOUTUBE_THUMBNAIL_PREFIX = "https://i.ytimg.com/vi"; + private static final String YOUTUBE_THUMBNAIL_DOMAIN = "https://i.ytimg.com/"; @Nullable static DecodedThumbnailUrl decodeImageUrl(String url) { - final int videoIdStartIndex = url.indexOf('/', YOUTUBE_THUMBNAIL_PREFIX.length()) + 1; + final int urlPathStartIndex = url.indexOf('/', "https://".length()) + 1; + if (urlPathStartIndex <= 0) return null; + + final int urlPathEndIndex = url.indexOf('/', urlPathStartIndex); + if (urlPathEndIndex < 0) return null; + + final int videoIdStartIndex = url.indexOf('/', urlPathEndIndex) + 1; if (videoIdStartIndex <= 0) return null; final int videoIdEndIndex = url.indexOf('/', videoIdStartIndex); @@ -647,15 +658,15 @@ static DecodedThumbnailUrl decodeImageUrl(String url) { int imageExtensionEndIndex = url.indexOf('?', imageSizeEndIndex); if (imageExtensionEndIndex < 0) imageExtensionEndIndex = url.length(); - return new DecodedThumbnailUrl(url, videoIdStartIndex, videoIdEndIndex, + return new DecodedThumbnailUrl(url, urlPathStartIndex, urlPathEndIndex, videoIdStartIndex, videoIdEndIndex, imageSizeStartIndex, imageSizeEndIndex, imageExtensionEndIndex); } final String originalFullUrl; /** Full usable url, but stripped of any tracking information. */ final String sanitizedUrl; - /** Url up to the video ID. */ - final String urlPrefix; + /** Url path, such as 'vi' or 'vi_webp' */ + final String urlPath; final String videoId; /** Quality, such as hq720 or sddefault. */ final String imageQuality; @@ -664,11 +675,11 @@ static DecodedThumbnailUrl decodeImageUrl(String url) { /** User view tracking parameters, only present on some images. */ final String viewTrackingParameters; - DecodedThumbnailUrl(String fullUrl, int videoIdStartIndex, int videoIdEndIndex, + DecodedThumbnailUrl(String fullUrl, int urlPathStartIndex, int urlPathEndIndex, int videoIdStartIndex, int videoIdEndIndex, int imageSizeStartIndex, int imageSizeEndIndex, int imageExtensionEndIndex) { originalFullUrl = fullUrl; sanitizedUrl = fullUrl.substring(0, imageExtensionEndIndex); - urlPrefix = fullUrl.substring(0, videoIdStartIndex); + urlPath = fullUrl.substring(urlPathStartIndex, urlPathEndIndex); videoId = fullUrl.substring(videoIdStartIndex, videoIdEndIndex); imageQuality = fullUrl.substring(imageSizeStartIndex, imageSizeEndIndex); imageExtension = fullUrl.substring(imageSizeEndIndex + 1, imageExtensionEndIndex); @@ -681,9 +692,12 @@ String createStillsUrl(@NonNull ThumbnailQuality qualityToUse, boolean includeVi // Images could be upgraded to webp if they are not already, but this fails quite often, // especially for new videos uploaded in the last hour. // And even if alt webp images do exist, sometimes they can load much slower than the original jpg alt images. - // (as much as 4x slower has been observed, despite the alt webp image being a smaller file). + // (as much as 4x slower network response has been observed, despite the alt webp image being a smaller file). StringBuilder builder = new StringBuilder(originalFullUrl.length() + 2); - builder.append(urlPrefix); + // Many different "i.ytimage.com" domains exist such as "i9.ytimg.com", + // but still captures are frequently not available on the other domains (especially newly uploaded videos). + // So always use the primary domain for a higher success rate. + builder.append(YOUTUBE_THUMBNAIL_DOMAIN).append(urlPath).append('/'); builder.append(videoId).append('/'); builder.append(qualityToUse.getAltImageNameToUse()); builder.append('.').append(imageExtension); From 66cf6c4263596d33453e7183b667e60f0a72b2c9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 13 Jul 2024 15:55:01 +0000 Subject: [PATCH 07/32] chore(release): 1.11.2-dev.2 [skip ci] ## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-13) ### Bug Fixes * **YouTube - Alternative thumbnails:** Always use primary thumbnail domain for still captures ([#666](https://github.com/ReVanced/revanced-integrations/issues/666)) ([7cdaf8d](https://github.com/ReVanced/revanced-integrations/commit/7cdaf8df146fdc0da8254a27d9c125f1e3d34765)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07f772f8cb..05c8fa49e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-13) + + +### Bug Fixes + +* **YouTube - Alternative thumbnails:** Always use primary thumbnail domain for still captures ([#666](https://github.com/ReVanced/revanced-integrations/issues/666)) ([7cdaf8d](https://github.com/ReVanced/revanced-integrations/commit/7cdaf8df146fdc0da8254a27d9c125f1e3d34765)) + ## [1.11.2-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.1...v1.11.2-dev.1) (2024-07-12) diff --git a/gradle.properties b/gradle.properties index 93401cba23..8005358f8b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.11.2-dev.1 +version = 1.11.2-dev.2 From 1fa59a62a17c63916808647331fa682d3de6aafb Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 14 Jul 2024 18:11:55 +0400 Subject: [PATCH 08/32] fix(YouTube - Hide layout components): Hide new type of horizontal shelf --- .../youtube/patches/components/LayoutComponentsFilter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/LayoutComponentsFilter.java index b9d581a945..4d7358d467 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/LayoutComponentsFilter.java @@ -250,6 +250,7 @@ public LayoutComponentsFilter() { Settings.HIDE_HORIZONTAL_SHELVES, "horizontal_video_shelf.eml", "horizontal_shelf.eml", + "horizontal_shelf_inline.eml", "horizontal_tile_shelf.eml" ); From 3368023ff9435e74ec9482e51063fae1758de71e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 14 Jul 2024 14:15:08 +0000 Subject: [PATCH 09/32] chore(release): 1.11.2-dev.2 [skip ci] ## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-14) ### Bug Fixes * **YouTube - Alternative thumbnails:** Always use primary thumbnail domain for still captures ([#666](https://github.com/ReVanced/revanced-integrations/issues/666)) ([7cdaf8d](https://github.com/ReVanced/revanced-integrations/commit/7cdaf8df146fdc0da8254a27d9c125f1e3d34765)) * **YouTube - Hide layout components:** Hide new type of horizontal shelf ([1fa59a6](https://github.com/ReVanced/revanced-integrations/commit/1fa59a62a17c63916808647331fa682d3de6aafb)) --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05c8fa49e4..75dd896f99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-14) + + +### Bug Fixes + +* **YouTube - Alternative thumbnails:** Always use primary thumbnail domain for still captures ([#666](https://github.com/ReVanced/revanced-integrations/issues/666)) ([7cdaf8d](https://github.com/ReVanced/revanced-integrations/commit/7cdaf8df146fdc0da8254a27d9c125f1e3d34765)) +* **YouTube - Hide layout components:** Hide new type of horizontal shelf ([1fa59a6](https://github.com/ReVanced/revanced-integrations/commit/1fa59a62a17c63916808647331fa682d3de6aafb)) + ## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-13) From 2fabdb245f2ff15bd0b654521a0c877154ba867b Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 15 Jul 2024 00:39:54 +0200 Subject: [PATCH 10/32] ci: Add custom release rule to create a build release --- .releaserc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.releaserc b/.releaserc index ceee0e49d5..dfa9b4470f 100644 --- a/.releaserc +++ b/.releaserc @@ -7,7 +7,13 @@ } ], "plugins": [ - "@semantic-release/commit-analyzer", + [ + "@semantic-release/commit-analyzer", { + "releaseRules": [ + { "type": "build", "scope": "Needs bump", "release": "patch" } + ] + } + ], "@semantic-release/release-notes-generator", "@semantic-release/changelog", "gradle-semantic-release-plugin", From 7af763f4b137abffc868bdf6b285e60a9b4d84b8 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 15 Jul 2024 00:37:37 +0200 Subject: [PATCH 11/32] build(Needs bump): Sign APK properly without relying on internal Gradle classes --- app/build.gradle.kts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 69489b444e..42f157ea41 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin) publishing + signing } android { @@ -53,28 +54,27 @@ dependencies { compileOnly(project(":stub")) } + tasks { - // Because the signing plugin doesn't support signing APKs, do it manually. - register("sign") { - group = "signing" + val assembleReleaseSignApk by registering { + dependsOn("assembleRelease") - dependsOn(build) + val apk = layout.buildDirectory.file("outputs/apk/release/${rootProject.name}-$version.apk") - doLast { - val outputDirectory = layout.buildDirectory.dir("outputs/apk/release").get().asFile - val integrationsApk = outputDirectory.resolve("${rootProject.name}-$version.apk") + inputs.file(apk).withPropertyName("input") + outputs.file(apk.map { it.asFile.resolveSibling("${it.asFile.name}.asc") }) - org.gradle.security.internal.gnupg.GnupgSignatoryFactory().createSignatory(project).sign( - integrationsApk.inputStream(), - outputDirectory.resolve("${integrationsApk.name}.asc").outputStream(), - ) + doLast { + signing { + useGpgCmd() + sign(*inputs.files.files.toTypedArray()) + } } } // Needed by gradle-semantic-release-plugin. - // Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435 + // Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435. publish { - dependsOn(build) - dependsOn("sign") + dependsOn(assembleReleaseSignApk) } } From 67ff3172bb6a921d9d04c27af30f3020af5c93b2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 14 Jul 2024 22:43:08 +0000 Subject: [PATCH 12/32] chore(release): 1.11.2-dev.3 [skip ci] ## [1.11.2-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.2...v1.11.2-dev.3) (2024-07-14) --- CHANGELOG.md | 2 ++ gradle.properties | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75dd896f99..8839056490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [1.11.2-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.2...v1.11.2-dev.3) (2024-07-14) + ## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-14) diff --git a/gradle.properties b/gradle.properties index 8005358f8b..b6abb8ca73 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.11.2-dev.2 +version = 1.11.2-dev.3 From 396ba77c207b438651ba6b83fb4b31e623544c00 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 15 Jul 2024 02:55:42 +0400 Subject: [PATCH 13/32] feat(YouTube): Add `Bypass image region restrictions` patch (#667) --- .../BypassImageRegionRestrictionsPatch.java | 46 +++++++++++++++++++ .../youtube/settings/Settings.java | 1 + 2 files changed, 47 insertions(+) create mode 100644 app/src/main/java/app/revanced/integrations/youtube/patches/BypassImageRegionRestrictionsPatch.java diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/BypassImageRegionRestrictionsPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/BypassImageRegionRestrictionsPatch.java new file mode 100644 index 0000000000..2fac8e39c2 --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/BypassImageRegionRestrictionsPatch.java @@ -0,0 +1,46 @@ +package app.revanced.integrations.youtube.patches; + +import static app.revanced.integrations.youtube.settings.Settings.BYPASS_IMAGE_REGION_RESTRICTIONS; + +import java.util.regex.Pattern; + +import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.youtube.settings.Settings; + +@SuppressWarnings("unused") +public final class BypassImageRegionRestrictionsPatch { + + private static final boolean BYPASS_IMAGE_REGION_RESTRICTIONS_ENABLED = BYPASS_IMAGE_REGION_RESTRICTIONS.get(); + + private static final String REPLACEMENT_IMAGE_DOMAIN = "https://yt4.ggpht.com"; + + /** + * YouTube static images domain. Includes user and channel avatar images and community post images. + */ + private static final Pattern YOUTUBE_STATIC_IMAGE_DOMAIN_PATTERN + = Pattern.compile("^https://(yt3|lh[3-6]|play-lh)\\.(ggpht|googleusercontent)\\.com"); + + /** + * Injection point. Called off the main thread and by multiple threads at the same time. + * + * @param originalUrl Image url for all image urls loaded. + */ + public static String overrideImageURL(String originalUrl) { + try { + if (BYPASS_IMAGE_REGION_RESTRICTIONS_ENABLED) { + String replacement = YOUTUBE_STATIC_IMAGE_DOMAIN_PATTERN + .matcher(originalUrl).replaceFirst(REPLACEMENT_IMAGE_DOMAIN); + + if (Settings.DEBUG.get() && !replacement.equals(originalUrl)) { + Logger.printDebug(() -> "Replaced: '" + originalUrl + "' with: '" + replacement + "'"); + } + + return replacement; + } + } catch (Exception ex) { + Logger.printException(() -> "overrideImageURL failure", ex); + } + + return originalUrl; + } +} diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java index ddf5532897..470cf7873b 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java @@ -189,6 +189,7 @@ public class Settings extends BaseSettings { public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "17.33.42", true, parent(SPOOF_APP_VERSION)); public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message"); public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true); + public static final BooleanSetting BYPASS_IMAGE_REGION_RESTRICTIONS = new BooleanSetting("revanced_bypass_image_region_restrictions", FALSE, true); public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG = new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE, "revanced_remove_viewer_discretion_dialog_user_dialog_message"); From d996d3832a74fd03e27a6a41ba338a67d62d8d98 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 14 Jul 2024 22:58:56 +0000 Subject: [PATCH 14/32] chore(release): 1.12.0-dev.1 [skip ci] # [1.12.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.3...v1.12.0-dev.1) (2024-07-14) ### Features * **YouTube:** Add `Bypass image region restrictions` patch ([#667](https://github.com/ReVanced/revanced-integrations/issues/667)) ([396ba77](https://github.com/ReVanced/revanced-integrations/commit/396ba77c207b438651ba6b83fb4b31e623544c00)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8839056490..9708f9e83c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.3...v1.12.0-dev.1) (2024-07-14) + + +### Features + +* **YouTube:** Add `Bypass image region restrictions` patch ([#667](https://github.com/ReVanced/revanced-integrations/issues/667)) ([396ba77](https://github.com/ReVanced/revanced-integrations/commit/396ba77c207b438651ba6b83fb4b31e623544c00)) + ## [1.11.2-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.2...v1.11.2-dev.3) (2024-07-14) ## [1.11.2-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.1...v1.11.2-dev.2) (2024-07-14) diff --git a/gradle.properties b/gradle.properties index b6abb8ca73..d480c03977 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.11.2-dev.3 +version = 1.12.0-dev.1 From 0345a00d6095797e275bb31f92ccda2e861f44c4 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:16:39 +0400 Subject: [PATCH 15/32] fix(YouTube - Disable auto captions): Do not break Shorts captions menu --- .../youtube/patches/DisableAutoCaptionsPatch.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch.java index e35ac70b06..2d20e6adcc 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch.java @@ -1,6 +1,7 @@ package app.revanced.integrations.youtube.patches; import app.revanced.integrations.youtube.settings.Settings; +import app.revanced.integrations.youtube.shared.PlayerType; @SuppressWarnings("unused") public class DisableAutoCaptionsPatch { @@ -11,7 +12,9 @@ public class DisableAutoCaptionsPatch { public static boolean captionsButtonDisabled; public static boolean autoCaptionsEnabled() { - return Settings.AUTO_CAPTIONS.get(); + return Settings.AUTO_CAPTIONS.get() + // Do not use auto captions for Shorts. + && !PlayerType.getCurrent().isNoneHiddenOrSlidingMinimized(); } } From 7bf43c68965821ca8860a28aa130b99aabfb5d3c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 15 Jul 2024 19:02:18 +0000 Subject: [PATCH 16/32] chore(release): 1.12.0-dev.2 [skip ci] # [1.12.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.1...v1.12.0-dev.2) (2024-07-15) ### Bug Fixes * **YouTube - Disable auto captions:** Do not break Shorts captions menu ([0345a00](https://github.com/ReVanced/revanced-integrations/commit/0345a00d6095797e275bb31f92ccda2e861f44c4)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9708f9e83c..f053093939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.1...v1.12.0-dev.2) (2024-07-15) + + +### Bug Fixes + +* **YouTube - Disable auto captions:** Do not break Shorts captions menu ([0345a00](https://github.com/ReVanced/revanced-integrations/commit/0345a00d6095797e275bb31f92ccda2e861f44c4)) + # [1.12.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v1.11.2-dev.3...v1.12.0-dev.1) (2024-07-14) diff --git a/gradle.properties b/gradle.properties index d480c03977..c3656d55de 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.1 +version = 1.12.0-dev.2 From e71955d5bbe58c1c634e82262d0e67dc65eca078 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:36:27 -0400 Subject: [PATCH 17/32] fix(YouTube - SponsorBlock): Correctly show minute timestamp when creating a new segment --- .../youtube/sponsorblock/SponsorBlockUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SponsorBlockUtils.java b/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SponsorBlockUtils.java index 9c36d25e32..63569c374e 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SponsorBlockUtils.java +++ b/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SponsorBlockUtils.java @@ -234,9 +234,7 @@ public static void onMarkLocationClicked() { new AlertDialog.Builder(SponsorBlockViewController.getOverLaysViewGroupContext()) .setTitle(str("revanced_sb_new_segment_title")) .setMessage(str("revanced_sb_new_segment_mark_time_as_question", - newSponsorSegmentDialogShownMillis / 3600000, - newSponsorSegmentDialogShownMillis / 1000 % 60, - newSponsorSegmentDialogShownMillis % 1000)) + formatSegmentTime(newSponsorSegmentDialogShownMillis))) .setNeutralButton(android.R.string.cancel, null) .setNegativeButton(str("revanced_sb_new_segment_mark_start"), newSponsorSegmentDialogListener) .setPositiveButton(str("revanced_sb_new_segment_mark_end"), newSponsorSegmentDialogListener) @@ -448,17 +446,20 @@ public static String getTimeSavedString(long totalSecondsSaved) { Duration duration = Duration.ofSeconds(totalSecondsSaved); final long hours = duration.toHours(); final long minutes = duration.toMinutes() % 60; + // Format all numbers so non-western numbers use a consistent appearance. String minutesFormatted = statsNumberFormatter.format(minutes); if (hours > 0) { String hoursFormatted = statsNumberFormatter.format(hours); return str("revanced_sb_stats_saved_hour_format", hoursFormatted, minutesFormatted); } + final long seconds = duration.getSeconds() % 60; String secondsFormatted = statsNumberFormatter.format(seconds); if (minutes > 0) { return str("revanced_sb_stats_saved_minute_format", minutesFormatted, secondsFormatted); } + return str("revanced_sb_stats_saved_second_format", secondsFormatted); } return "error"; // will never be reached. YouTube requires Android O or greater From 848ed6e878edbd8a7dbcc937a0b2621c7265a14e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 26 Jul 2024 14:39:42 +0000 Subject: [PATCH 18/32] chore(release): 1.12.0-dev.3 [skip ci] # [1.12.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.2...v1.12.0-dev.3) (2024-07-26) ### Bug Fixes * **YouTube - SponsorBlock:** Correctly show minute timestamp when creating a new segment ([e71955d](https://github.com/ReVanced/revanced-integrations/commit/e71955d5bbe58c1c634e82262d0e67dc65eca078)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f053093939..1893bf89b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.2...v1.12.0-dev.3) (2024-07-26) + + +### Bug Fixes + +* **YouTube - SponsorBlock:** Correctly show minute timestamp when creating a new segment ([e71955d](https://github.com/ReVanced/revanced-integrations/commit/e71955d5bbe58c1c634e82262d0e67dc65eca078)) + # [1.12.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.1...v1.12.0-dev.2) (2024-07-15) diff --git a/gradle.properties b/gradle.properties index c3656d55de..b8f974c2fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.2 +version = 1.12.0-dev.3 From 4ac698fd4bd493d3830009853454a8f6566362b5 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 28 Jul 2024 15:53:55 +0200 Subject: [PATCH 19/32] fix(YouTube - Spoof client): Fix tracking history on brand accounts (#669) --- .../patches/spoof/SpoofClientPatch.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java index e6c1c1f8e6..001b413745 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java @@ -18,6 +18,13 @@ public class SpoofClientPatch { private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0"; private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING); + /** + * Tracking URL authority to use when spoofing the client to iOS, + * because watch history is not working on brand accounts. + * See LuanRT/YouTube.js. + */ + private static final String WWW_TRACKING_URL_AUTHORITY = "www.youtube.com"; + /** * Injection point. * Blocks /get_watch requests by returning an unreachable URI. @@ -127,6 +134,19 @@ public static boolean forceCreatePlaybackSpeedMenu(boolean original) { return original; } + /** + * Injection point. + * When spoofing the client to iOS, history is not working on brand accounts. + * Replace the tracking URL authority to {@link SpoofClientPatch#WWW_TRACKING_URL_AUTHORITY} to fix this. + */ + public static Uri overrideTrackingUrl(Uri trackingUrl) { + if (SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS) { + return trackingUrl.buildUpon().authority(WWW_TRACKING_URL_AUTHORITY).build(); + } + + return trackingUrl; + } + private enum ClientType { // https://dumps.tadiphone.dev/dumps/oculus/eureka ANDROID_VR(28, "Quest 3", "1.56.21"), From ab0093ff8311824e4a6c316e4d0164b32f95d64c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 28 Jul 2024 13:56:49 +0000 Subject: [PATCH 20/32] chore(release): 1.12.0-dev.4 [skip ci] # [1.12.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.3...v1.12.0-dev.4) (2024-07-28) ### Bug Fixes * **YouTube - Spoof client:** Fix tracking history on brand accounts ([#669](https://github.com/ReVanced/revanced-integrations/issues/669)) ([4ac698f](https://github.com/ReVanced/revanced-integrations/commit/4ac698fd4bd493d3830009853454a8f6566362b5)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1893bf89b4..c78f9a378f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.3...v1.12.0-dev.4) (2024-07-28) + + +### Bug Fixes + +* **YouTube - Spoof client:** Fix tracking history on brand accounts ([#669](https://github.com/ReVanced/revanced-integrations/issues/669)) ([4ac698f](https://github.com/ReVanced/revanced-integrations/commit/4ac698fd4bd493d3830009853454a8f6566362b5)) + # [1.12.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.2...v1.12.0-dev.3) (2024-07-26) diff --git a/gradle.properties b/gradle.properties index b8f974c2fe..f2819e7864 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.3 +version = 1.12.0-dev.4 From fbf629fd6278440e70b0f1fb07e4cb7c412f0949 Mon Sep 17 00:00:00 2001 From: Zain Arbani Date: Sun, 28 Jul 2024 21:51:17 +0700 Subject: [PATCH 21/32] fix(YouTube - Client Spoof): Restore missing high qualities by spoofing the iOS client user agent (#668) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Co-authored-by: oSumAtrIX --- .../patches/spoof/SpoofClientPatch.java | 74 +++++++++++++------ .../chromium/net/ExperimentalUrlRequest.java | 8 ++ 2 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java index 001b413745..a83bf2a6ab 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java @@ -6,11 +6,13 @@ import android.os.Build; import app.revanced.integrations.shared.Logger; import app.revanced.integrations.youtube.settings.Settings; +import org.chromium.net.ExperimentalUrlRequest; @SuppressWarnings("unused") public class SpoofClientPatch { private static final boolean SPOOF_CLIENT_ENABLED = Settings.SPOOF_CLIENT.get(); private static final ClientType SPOOF_CLIENT_TYPE = Settings.SPOOF_CLIENT_USE_IOS.get() ? ClientType.IOS : ClientType.ANDROID_VR; + private static final boolean SPOOFING_TO_IOS = SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS; /** * Any unreachable ip address. Used to intentionally fail requests. @@ -52,7 +54,7 @@ public static Uri blockGetWatchRequest(Uri playerRequestUri) { /** * Injection point. - * + *

* Blocks /initplayback requests. */ public static String blockInitPlaybackRequest(String originalUrlString) { @@ -78,33 +80,29 @@ public static String blockInitPlaybackRequest(String originalUrlString) { * Injection point. */ public static int getClientTypeId(int originalClientTypeId) { - if (SPOOF_CLIENT_ENABLED) { - return SPOOF_CLIENT_TYPE.id; - } - - return originalClientTypeId; + return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.id : originalClientTypeId; } /** * Injection point. */ public static String getClientVersion(String originalClientVersion) { - if (SPOOF_CLIENT_ENABLED) { - return SPOOF_CLIENT_TYPE.version; - } - - return originalClientVersion; + return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.version : originalClientVersion; } /** * Injection point. */ public static String getClientModel(String originalClientModel) { - if (SPOOF_CLIENT_ENABLED) { - return SPOOF_CLIENT_TYPE.model; - } + return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.model : originalClientModel; + } - return originalClientModel; + /** + * Injection point. + * Fix video qualities missing, if spoofing to iOS by using the correct client OS version. + */ + public static String getOsVersion(String originalOsVersion) { + return SPOOFING_TO_IOS ? ClientType.IOS.osVersion : originalOsVersion; } /** @@ -127,11 +125,23 @@ public static boolean isClientSpoofingEnabled() { * Return true to force create the playback speed menu. */ public static boolean forceCreatePlaybackSpeedMenu(boolean original) { - if (SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS) { - return true; + return SPOOFING_TO_IOS || original; + } + + + /** + * Injection point. + * Fix video qualities missing, if spoofing to iOS by using the correct iOS user-agent. + */ + public static ExperimentalUrlRequest overrideUserAgent(ExperimentalUrlRequest.Builder builder, String url) { + if (SPOOFING_TO_IOS) { + String path = Uri.parse(url).getPath(); + if (path != null && path.contains("player")) { + return builder.addHeader("User-Agent", ClientType.IOS.userAgent).build(); + } } - return original; + return builder.build(); } /** @@ -149,7 +159,12 @@ public static Uri overrideTrackingUrl(Uri trackingUrl) { private enum ClientType { // https://dumps.tadiphone.dev/dumps/oculus/eureka - ANDROID_VR(28, "Quest 3", "1.56.21"), + ANDROID_VR(28, + "Quest 3", + "1.56.21", + "12", + "com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip" + ), // 11,4 = iPhone XS Max. // 16,2 = iPhone 15 Pro Max. // Since the 15 supports AV1 hardware decoding, only spoof that device if this @@ -157,7 +172,12 @@ private enum ClientType { // // Version number should be a valid iOS release. // https://www.ipa4fun.com/history/185230 - IOS(5, deviceHasAV1HardwareDecoding() ? "iPhone16,2" : "iPhone11,4", "19.10.7"); + IOS(5, + deviceHasAV1HardwareDecoding() ? "iPhone16,2" : "iPhone11,4", + "19.10.7", + "17.5.1.21F90", + "com.google.ios.youtube/19.10.7 (iPhone; U; CPU iOS 17_5_1 like Mac OS X)" + ); /** * YouTube @@ -175,10 +195,22 @@ private enum ClientType { */ final String version; - ClientType(int id, String model, String version) { + /** + * Device OS version. + */ + final String osVersion; + + /** + * Player user-agent. + */ + final String userAgent; + + ClientType(int id, String model, String version, String osVersion, String userAgent) { this.id = id; this.model = model; this.version = version; + this.osVersion = osVersion; + this.userAgent = userAgent; } } diff --git a/stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java b/stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java new file mode 100644 index 0000000000..cdf2593e79 --- /dev/null +++ b/stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java @@ -0,0 +1,8 @@ +package org.chromium.net; + +public abstract class ExperimentalUrlRequest { + public abstract class Builder { + public abstract ExperimentalUrlRequest.Builder addHeader(String name, String value); + public abstract ExperimentalUrlRequest build(); + } +} From 3945a379445a4e12dd9e080a5d75e53e2af10fd7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 28 Jul 2024 14:54:07 +0000 Subject: [PATCH 22/32] chore(release): 1.12.0-dev.5 [skip ci] # [1.12.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.4...v1.12.0-dev.5) (2024-07-28) ### Bug Fixes * **YouTube - Client Spoof:** Restore missing high qualities by spoofing the iOS client user agent ([#668](https://github.com/ReVanced/revanced-integrations/issues/668)) ([fbf629f](https://github.com/ReVanced/revanced-integrations/commit/fbf629fd6278440e70b0f1fb07e4cb7c412f0949)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c78f9a378f..7d625a6c1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.4...v1.12.0-dev.5) (2024-07-28) + + +### Bug Fixes + +* **YouTube - Client Spoof:** Restore missing high qualities by spoofing the iOS client user agent ([#668](https://github.com/ReVanced/revanced-integrations/issues/668)) ([fbf629f](https://github.com/ReVanced/revanced-integrations/commit/fbf629fd6278440e70b0f1fb07e4cb7c412f0949)) + # [1.12.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.3...v1.12.0-dev.4) (2024-07-28) diff --git a/gradle.properties b/gradle.properties index f2819e7864..dbfa49e343 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.4 +version = 1.12.0-dev.5 From 2f2eeea5a722b6b7053eb2825d16fa37938b4e9e Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 28 Jul 2024 13:19:40 -0400 Subject: [PATCH 23/32] fix(YouTube - Keyword filter): Filter videos from new subscription layout --- .../youtube/patches/components/KeywordContentFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java index 56f044c40a..4e0e6f58b9 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/KeywordContentFilter.java @@ -107,6 +107,7 @@ final class KeywordContentFilter extends Filter { "search_video_with_context.eml", "video_with_context.eml", // Subscription tab videos. "related_video_with_context.eml", + "video_lockup_with_attachment.eml", // A/B test for subscribed video. "compact_video.eml", "inline_shorts", "shorts_video_cell", @@ -120,7 +121,7 @@ final class KeywordContentFilter extends Filter { private final StringFilterGroup containsFilter = new StringFilterGroup( null, "modern_type_shelf_header_content.eml", - "shorts_lockup_cell.eml", // Part of 'shorts_shelf_carousel.eml' + "shorts_lockup_cell.eml", // Part of 'shorts_shelf_carousel.eml' "video_card.eml" // Shorts that appear in a horizontal shelf. ); @@ -166,7 +167,7 @@ final class KeywordContentFilter extends Filter { /** * If filtering is temporarily turned off, the time to resume filtering. - * Field is zero if no timeout is in effect. + * Field is zero if no backoff is in effect. */ private volatile long timeToResumeFiltering; From e879e40e56fbd8288fae7bdddbb1de904446027a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 28 Jul 2024 17:22:53 +0000 Subject: [PATCH 24/32] chore(release): 1.12.0-dev.6 [skip ci] # [1.12.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.5...v1.12.0-dev.6) (2024-07-28) ### Bug Fixes * **YouTube - Keyword filter:** Filter videos from new subscription layout ([2f2eeea](https://github.com/ReVanced/revanced-integrations/commit/2f2eeea5a722b6b7053eb2825d16fa37938b4e9e)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d625a6c1b..264a727535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.5...v1.12.0-dev.6) (2024-07-28) + + +### Bug Fixes + +* **YouTube - Keyword filter:** Filter videos from new subscription layout ([2f2eeea](https://github.com/ReVanced/revanced-integrations/commit/2f2eeea5a722b6b7053eb2825d16fa37938b4e9e)) + # [1.12.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.4...v1.12.0-dev.5) (2024-07-28) diff --git a/gradle.properties b/gradle.properties index dbfa49e343..1e53a1f081 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.5 +version = 1.12.0-dev.6 From 86b25ea468a132bd01e3fb1e2972cc903dd46d0c Mon Sep 17 00:00:00 2001 From: ILoveOpenSourceApplications <117499019+ILoveOpenSourceApplications@users.noreply.github.com> Date: Thu, 1 Aug 2024 16:57:19 +0530 Subject: [PATCH 25/32] feat(YouTube - Description components): Add `Hide 'Key concepts' section` option (#670) Co-authored-by: oSumAtrIX Co-authored-by: ILoveOpenSourceApplications Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> --- .../DescriptionComponentsFilter.java | 43 ++++++++++++++----- .../youtube/settings/Settings.java | 1 + 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter.java b/app/src/main/java/app/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter.java index 7b1ab3e8e5..474f6aa738 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter.java @@ -1,14 +1,19 @@ package app.revanced.integrations.youtube.patches.components; import androidx.annotation.Nullable; -import app.revanced.integrations.youtube.settings.Settings; + import app.revanced.integrations.youtube.StringTrieSearch; +import app.revanced.integrations.youtube.settings.Settings; @SuppressWarnings("unused") final class DescriptionComponentsFilter extends Filter { private final StringTrieSearch exceptions = new StringTrieSearch(); + private final ByteArrayFilterGroupList macroMarkersCarouselGroupList = new ByteArrayFilterGroupList(); + + private final StringFilterGroup macroMarkersCarousel; + public DescriptionComponentsFilter() { exceptions.addPatterns( "compact_channel", @@ -25,11 +30,6 @@ public DescriptionComponentsFilter() { "video_attributes_section" ); - final StringFilterGroup chaptersSection = new StringFilterGroup( - Settings.HIDE_CHAPTERS_SECTION, - "macro_markers_carousel" - ); - final StringFilterGroup infoCardsSection = new StringFilterGroup( Settings.HIDE_INFO_CARDS_SECTION, "infocards_section" @@ -45,21 +45,44 @@ public DescriptionComponentsFilter() { "transcript_section" ); + macroMarkersCarousel = new StringFilterGroup( + null, + "macro_markers_carousel.eml" + ); + + macroMarkersCarouselGroupList.addAll( + new ByteArrayFilterGroup( + Settings.HIDE_CHAPTERS_SECTION, + "chapters_horizontal_shelf" + ), + new ByteArrayFilterGroup( + Settings.HIDE_KEY_CONCEPTS_SECTION, + "learning_concept_macro_markers_carousel_shelf" + ) + ); + addPathCallbacks( attributesSection, - chaptersSection, infoCardsSection, podcastSection, - transcriptSection + transcriptSection, + macroMarkersCarousel ); } - @Override boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { if (exceptions.matches(path)) return false; + if (matchedGroup == macroMarkersCarousel) { + if (contentIndex == 0 && macroMarkersCarouselGroupList.check(protobufBufferArray).isFiltered()) { + return super.isFiltered(path, identifier, protobufBufferArray, matchedGroup, contentType, contentIndex); + } + + return false; + } + return super.isFiltered(path, identifier, protobufBufferArray, matchedGroup, contentType, contentIndex); } -} \ No newline at end of file +} diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java index 470cf7873b..9c18932ffd 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java @@ -157,6 +157,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE); public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE); public static final BooleanSetting HIDE_INFO_CARDS_SECTION = new BooleanSetting("revanced_hide_info_cards_section", TRUE); + public static final BooleanSetting HIDE_KEY_CONCEPTS_SECTION = new BooleanSetting("revanced_hide_key_concepts_section", FALSE); public static final BooleanSetting HIDE_PODCAST_SECTION = new BooleanSetting("revanced_hide_podcast_section", TRUE); public static final BooleanSetting HIDE_TRANSCRIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE); From d57a64b65906402d844c50096143058f4e81b305 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 1 Aug 2024 11:30:52 +0000 Subject: [PATCH 26/32] chore(release): 1.12.0-dev.7 [skip ci] # [1.12.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.6...v1.12.0-dev.7) (2024-08-01) ### Features * **YouTube - Description components:** Add `Hide 'Key concepts' section` option ([#670](https://github.com/ReVanced/revanced-integrations/issues/670)) ([86b25ea](https://github.com/ReVanced/revanced-integrations/commit/86b25ea468a132bd01e3fb1e2972cc903dd46d0c)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 264a727535..3814fa9429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.6...v1.12.0-dev.7) (2024-08-01) + + +### Features + +* **YouTube - Description components:** Add `Hide 'Key concepts' section` option ([#670](https://github.com/ReVanced/revanced-integrations/issues/670)) ([86b25ea](https://github.com/ReVanced/revanced-integrations/commit/86b25ea468a132bd01e3fb1e2972cc903dd46d0c)) + # [1.12.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.5...v1.12.0-dev.6) (2024-07-28) diff --git a/gradle.properties b/gradle.properties index 1e53a1f081..22d381d04b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.6 +version = 1.12.0-dev.7 From 34c02aeb2a75bd95492e55958a446c9f99efdbb3 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:39:33 -0400 Subject: [PATCH 27/32] fix(YouTube - SponsorBlock): Improve create segment manual seek accuracy (#671) --- .../youtube/patches/VideoInformation.java | 101 ++++++++++++------ .../quality/RememberVideoQualityPatch.java | 17 +-- .../speed/RememberPlaybackSpeedPatch.java | 2 +- .../SegmentPlaybackController.java | 16 +-- 4 files changed, 86 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/VideoInformation.java b/app/src/main/java/app/revanced/integrations/youtube/patches/VideoInformation.java index 21aafa6672..0d7a29aa66 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/VideoInformation.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/VideoInformation.java @@ -7,7 +7,6 @@ import app.revanced.integrations.shared.Utils; import java.lang.ref.WeakReference; -import java.lang.reflect.Method; import java.util.Objects; /** @@ -15,17 +14,21 @@ * @noinspection unused */ public final class VideoInformation { + + public interface PlaybackController { + // Methods are added to YT classes during patching. + boolean seekTo(long videoTime); + boolean seekToRelative(long videoTimeOffset); + } + private static final float DEFAULT_YOUTUBE_PLAYBACK_SPEED = 1.0f; - private static final String SEEK_METHOD_NAME = "seekTo"; /** * Prefix present in all Short player parameters signature. */ private static final String SHORTS_PLAYER_PARAMETERS = "8AEB"; - private static WeakReference playerControllerRef; - private static WeakReference mdxPlayerDirectorRef; - private static Method seekMethod; - private static Method mdxSeekMethod; + private static WeakReference playerControllerRef = new WeakReference<>(null); + private static WeakReference mdxPlayerDirectorRef = new WeakReference<>(null); @NonNull private static String videoId = ""; @@ -47,15 +50,12 @@ public final class VideoInformation { * * @param playerController player controller object. */ - public static void initialize(@NonNull Object playerController) { + public static void initialize(@NonNull PlaybackController playerController) { try { playerControllerRef = new WeakReference<>(Objects.requireNonNull(playerController)); videoTime = -1; videoLength = 0; playbackSpeed = DEFAULT_YOUTUBE_PLAYBACK_SPEED; - - seekMethod = playerController.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE); - seekMethod.setAccessible(true); } catch (Exception ex) { Logger.printException(() -> "Failed to initialize", ex); } @@ -66,12 +66,9 @@ public static void initialize(@NonNull Object playerController) { * * @param mdxPlayerDirector MDX player director object (casting mode). */ - public static void initializeMdx(@NonNull Object mdxPlayerDirector) { + public static void initializeMdx(@NonNull PlaybackController mdxPlayerDirector) { try { mdxPlayerDirectorRef = new WeakReference<>(Objects.requireNonNull(mdxPlayerDirector)); - - mdxSeekMethod = mdxPlayerDirector.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE); - mdxSeekMethod.setAccessible(true); } catch (Exception ex) { Logger.printException(() -> "Failed to initialize MDX", ex); } @@ -195,42 +192,80 @@ public static boolean seekTo(final long seekTime) { return false; } - Logger.printDebug(() -> "Seeking to " + adjustedSeekTime); + Logger.printDebug(() -> "Seeking to: " + adjustedSeekTime); - try { - //noinspection DataFlowIssue - if ((Boolean) seekMethod.invoke(playerControllerRef.get(), adjustedSeekTime)) { - return true; - } // Else the video is loading or changing videos, or video is casting to a different device. - } catch (Exception ex) { - Logger.printInfo(() -> "seekTo method call failed", ex); + // Try regular playback controller first, and it will not succeed if casting. + PlaybackController controller = playerControllerRef.get(); + if (controller == null) { + Logger.printDebug(() -> "Cannot seekTo because player controller is null"); + } else { + if (controller.seekTo(adjustedSeekTime)) return true; + Logger.printDebug(() -> "seekTo did not succeeded. Trying MXD."); + // Else the video is loading or changing videos, or video is casting to a different device. } // Try calling the seekTo method of the MDX player director (called when casting). // The difference has to be a different second mark in order to avoid infinite skip loops // as the Lounge API only supports seconds. - if ((adjustedSeekTime / 1000) == (videoTime / 1000)) { - Logger.printDebug(() -> "Skipping seekTo for MDX because seek time is too small (" - + (adjustedSeekTime - videoTime) + "ms)"); + if (adjustedSeekTime / 1000 == videoTime / 1000) { + Logger.printDebug(() -> "Skipping seekTo for MDX because seek time is too small " + + "(" + (adjustedSeekTime - videoTime) + "ms)"); return false; } - try { - //noinspection DataFlowIssue - return (Boolean) mdxSeekMethod.invoke(mdxPlayerDirectorRef.get(), adjustedSeekTime); - } catch (Exception ex) { - Logger.printInfo(() -> "seekTo (MDX) method call failed", ex); + + controller = mdxPlayerDirectorRef.get(); + if (controller == null) { + Logger.printDebug(() -> "Cannot seekTo MXD because player controller is null"); return false; } + return controller.seekTo(adjustedSeekTime); } catch (Exception ex) { Logger.printException(() -> "Failed to seek", ex); return false; } } - /** @noinspection UnusedReturnValue*/ - public static boolean seekToRelative(long millisecondsRelative) { - return seekTo(videoTime + millisecondsRelative); + /** + * Seeks a relative amount. Should always be used over {@link #seekTo(long)} + * when the desired seek time is an offset of the current time. + * + * @noinspection UnusedReturnValue + */ + public static boolean seekToRelative(long seekTime) { + Utils.verifyOnMainThread(); + try { + Logger.printDebug(() -> "Seeking relative to: " + seekTime); + + // Try regular playback controller first, and it will not succeed if casting. + PlaybackController controller = playerControllerRef.get(); + if (controller == null) { + Logger.printDebug(() -> "Cannot seek relative as player controller is null"); + } else { + if (controller.seekToRelative(seekTime)) return true; + Logger.printDebug(() -> "seekToRelative did not succeeded. Trying MXD."); + } + + // Adjust the fine adjustment function so it's at least 1 second before/after. + // Otherwise the fine adjustment will do nothing when casting. + final long adjustedSeekTime; + if (seekTime < 0) { + adjustedSeekTime = Math.min(seekTime, -1000); + } else { + adjustedSeekTime = Math.max(seekTime, 1000); + } + + controller = mdxPlayerDirectorRef.get(); + if (controller == null) { + Logger.printDebug(() -> "Cannot seek relative as MXD player controller is null"); + return false; + } + + return controller.seekToRelative(adjustedSeekTime); + } catch (Exception ex) { + Logger.printException(() -> "Failed to seek relative", ex); + return false; + } } /** diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/playback/quality/RememberVideoQualityPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/playback/quality/RememberVideoQualityPatch.java index 566792857f..56013f4d36 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/playback/quality/RememberVideoQualityPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/playback/quality/RememberVideoQualityPatch.java @@ -1,19 +1,20 @@ package app.revanced.integrations.youtube.patches.playback.quality; -import androidx.annotation.Nullable; +import static app.revanced.integrations.shared.StringRef.str; +import static app.revanced.integrations.shared.Utils.NetworkType; -import app.revanced.integrations.shared.settings.IntegerSetting; -import app.revanced.integrations.youtube.settings.Settings; -import app.revanced.integrations.shared.Logger; -import app.revanced.integrations.shared.Utils; +import androidx.annotation.Nullable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import static app.revanced.integrations.shared.StringRef.str; -import static app.revanced.integrations.shared.Utils.NetworkType; +import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.shared.Utils; +import app.revanced.integrations.shared.settings.IntegerSetting; +import app.revanced.integrations.youtube.patches.VideoInformation; +import app.revanced.integrations.youtube.settings.Settings; @SuppressWarnings("unused") public class RememberVideoQualityPatch { @@ -158,7 +159,7 @@ public static void userChangedQualityInNewFlyout(int selectedQuality) { /** * Injection point. */ - public static void newVideoStarted(Object ignoredPlayerController) { + public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) { Logger.printDebug(() -> "newVideoStarted"); qualityNeedsUpdating = true; videoQualities = null; diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/playback/speed/RememberPlaybackSpeedPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/playback/speed/RememberPlaybackSpeedPatch.java index 1782ade6b3..2bb3f9cb11 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/playback/speed/RememberPlaybackSpeedPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/playback/speed/RememberPlaybackSpeedPatch.java @@ -13,7 +13,7 @@ public final class RememberPlaybackSpeedPatch { /** * Injection point. */ - public static void newVideoStarted(Object ignoredPlayerController) { + public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) { Logger.printDebug(() -> "newVideoStarted"); VideoInformation.overridePlaybackSpeed(Settings.PLAYBACK_SPEED_DEFAULT.get()); } diff --git a/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java b/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java index 9a35adceda..ad02eec8b8 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java +++ b/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java @@ -11,11 +11,7 @@ import androidx.annotation.Nullable; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; +import java.util.*; import app.revanced.integrations.shared.Logger; import app.revanced.integrations.shared.Utils; @@ -182,7 +178,7 @@ private static void clearData() { * Injection point. * Initializes SponsorBlock when the video player starts playing a new video. */ - public static void initialize(Object ignoredPlayerController) { + public static void initialize(VideoInformation.PlaybackController ignoredPlayerController) { try { Utils.verifyOnMainThread(); SponsorBlockSettings.initialize(); @@ -632,6 +628,7 @@ public static void onSkipSegmentClicked(@NonNull SponsorSegment segment) { /** * Injection point */ + @SuppressWarnings("unused") public static void setSponsorBarRect(final Object self) { try { Field field = self.getClass().getDeclaredField("replaceMeWithsetSponsorBarRect"); @@ -663,6 +660,7 @@ private static void setSponsorBarAbsoluteRight(Rect rect) { /** * Injection point */ + @SuppressWarnings("unused") public static void setSponsorBarThickness(int thickness) { if (sponsorBarThickness != thickness) { Logger.printDebug(() -> "setSponsorBarThickness: " + thickness); @@ -673,6 +671,7 @@ public static void setSponsorBarThickness(int thickness) { /** * Injection point. */ + @SuppressWarnings("unused") public static String appendTimeWithoutSegments(String totalTime) { try { if (Settings.SB_ENABLED.get() && Settings.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.get() @@ -725,9 +724,9 @@ private static void calculateTimeWithoutSegments() { final long minutes = (timeWithoutSegmentsValue / 60000) % 60; final long seconds = (timeWithoutSegmentsValue / 1000) % 60; if (hours > 0) { - timeWithoutSegments = String.format("\u2009(%d:%02d:%02d)", hours, minutes, seconds); + timeWithoutSegments = String.format(Locale.ENGLISH, "\u2009(%d:%02d:%02d)", hours, minutes, seconds); } else { - timeWithoutSegments = String.format("\u2009(%d:%02d)", minutes, seconds); + timeWithoutSegments = String.format(Locale.ENGLISH, "\u2009(%d:%02d)", minutes, seconds); } } @@ -744,6 +743,7 @@ private static int getHighlightSegmentTimeBarScreenWidth() { /** * Injection point. */ + @SuppressWarnings("unused") public static void drawSponsorTimeBars(final Canvas canvas, final float posY) { try { if (segments == null) return; From a0f3d7a0f770330e178260feadcf9963e9822680 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 2 Aug 2024 13:43:19 +0000 Subject: [PATCH 28/32] chore(release): 1.12.0-dev.8 [skip ci] # [1.12.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.7...v1.12.0-dev.8) (2024-08-02) ### Bug Fixes * **YouTube - SponsorBlock:** Improve create segment manual seek accuracy ([#671](https://github.com/ReVanced/revanced-integrations/issues/671)) ([34c02ae](https://github.com/ReVanced/revanced-integrations/commit/34c02aeb2a75bd95492e55958a446c9f99efdbb3)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3814fa9429..091fba2e7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.7...v1.12.0-dev.8) (2024-08-02) + + +### Bug Fixes + +* **YouTube - SponsorBlock:** Improve create segment manual seek accuracy ([#671](https://github.com/ReVanced/revanced-integrations/issues/671)) ([34c02ae](https://github.com/ReVanced/revanced-integrations/commit/34c02aeb2a75bd95492e55958a446c9f99efdbb3)) + # [1.12.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.6...v1.12.0-dev.7) (2024-08-01) diff --git a/gradle.properties b/gradle.properties index 22d381d04b..db224d9c5c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.7 +version = 1.12.0-dev.8 From 5bf5fbd1a79389895991f6b672d87373e96b698c Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:38:07 -0400 Subject: [PATCH 29/32] fix(YouTube - Spoof client): Restore livestream audio only playback with iOS spoofing (#673) --- .../revanced/integrations/shared/Utils.java | 2 +- .../patches/spoof/SpoofClientPatch.java | 29 ++++++------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/shared/Utils.java b/app/src/main/java/app/revanced/integrations/shared/Utils.java index f0c17e8c26..4b13a7876d 100644 --- a/app/src/main/java/app/revanced/integrations/shared/Utils.java +++ b/app/src/main/java/app/revanced/integrations/shared/Utils.java @@ -273,7 +273,6 @@ public static T getChildView(@NonNull ViewGroup viewGroup, bool @NonNull MatchFilter filter) { for (int i = 0, childCount = viewGroup.getChildCount(); i < childCount; i++) { View childAt = viewGroup.getChildAt(i); - Logger.printDebug(() -> "View id: " + childAt.getId() + " tag: " + childAt.getTag()); if (filter.matches(childAt)) { //noinspection unchecked @@ -285,6 +284,7 @@ public static T getChildView(@NonNull ViewGroup viewGroup, bool if (match != null) return match; } } + return null; } diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java index a83bf2a6ab..2b29dd97ce 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java @@ -5,6 +5,7 @@ import android.net.Uri; import android.os.Build; import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.youtube.patches.BackgroundPlaybackPatch; import app.revanced.integrations.youtube.settings.Settings; import org.chromium.net.ExperimentalUrlRequest; @@ -20,13 +21,6 @@ public class SpoofClientPatch { private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0"; private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING); - /** - * Tracking URL authority to use when spoofing the client to iOS, - * because watch history is not working on brand accounts. - * See LuanRT/YouTube.js. - */ - private static final String WWW_TRACKING_URL_AUTHORITY = "www.youtube.com"; - /** * Injection point. * Blocks /get_watch requests by returning an unreachable URI. @@ -128,6 +122,14 @@ public static boolean forceCreatePlaybackSpeedMenu(boolean original) { return SPOOFING_TO_IOS || original; } + /** + * Injection point. + * When spoofing the client to iOS, background audio only playback of livestreams fails. + * Return true to force enable audio background play. + */ + public static boolean overrideBackgroundAudioPlayback() { + return SPOOFING_TO_IOS && BackgroundPlaybackPatch.playbackIsNotShort(); + } /** * Injection point. @@ -144,19 +146,6 @@ public static ExperimentalUrlRequest overrideUserAgent(ExperimentalUrlRequest.Bu return builder.build(); } - /** - * Injection point. - * When spoofing the client to iOS, history is not working on brand accounts. - * Replace the tracking URL authority to {@link SpoofClientPatch#WWW_TRACKING_URL_AUTHORITY} to fix this. - */ - public static Uri overrideTrackingUrl(Uri trackingUrl) { - if (SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS) { - return trackingUrl.buildUpon().authority(WWW_TRACKING_URL_AUTHORITY).build(); - } - - return trackingUrl; - } - private enum ClientType { // https://dumps.tadiphone.dev/dumps/oculus/eureka ANDROID_VR(28, From 7017488de92997d8e9aac6468d8838bacc09095f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 4 Aug 2024 19:41:12 +0000 Subject: [PATCH 30/32] chore(release): 1.12.0-dev.9 [skip ci] # [1.12.0-dev.9](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.8...v1.12.0-dev.9) (2024-08-04) ### Bug Fixes * **YouTube - Spoof client:** Restore livestream audio only playback with iOS spoofing ([#673](https://github.com/ReVanced/revanced-integrations/issues/673)) ([5bf5fbd](https://github.com/ReVanced/revanced-integrations/commit/5bf5fbd1a79389895991f6b672d87373e96b698c)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 091fba2e7e..6daf562359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.9](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.8...v1.12.0-dev.9) (2024-08-04) + + +### Bug Fixes + +* **YouTube - Spoof client:** Restore livestream audio only playback with iOS spoofing ([#673](https://github.com/ReVanced/revanced-integrations/issues/673)) ([5bf5fbd](https://github.com/ReVanced/revanced-integrations/commit/5bf5fbd1a79389895991f6b672d87373e96b698c)) + # [1.12.0-dev.8](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.7...v1.12.0-dev.8) (2024-08-02) diff --git a/gradle.properties b/gradle.properties index db224d9c5c..c901ca0458 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.8 +version = 1.12.0-dev.9 From 509e1516f817bd736c3b2cc75bb5b48ab7de404a Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 6 Aug 2024 00:07:39 +0200 Subject: [PATCH 31/32] fix(YouTube - Return YouTube Dislike): Fix dislikes not appearing due to new component name (#674) --- .../youtube/patches/ReturnYouTubeDislikePatch.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/ReturnYouTubeDislikePatch.java index 7a8a3a9e0e..0fb8482957 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/ReturnYouTubeDislikePatch.java @@ -221,12 +221,12 @@ private static CharSequence onLithoTextLoaded(@NonNull Object conversionContext, String conversionContextString = conversionContext.toString(); - if (isRollingNumber && !conversionContextString.contains("video_action_bar.eml|")) { + if (isRollingNumber && !conversionContextString.contains("video_action_bar.eml")) { return original; } final CharSequence replacement; - if (conversionContextString.contains("|segmented_like_dislike_button.eml|")) { + if (conversionContextString.contains("segmented_like_dislike_button.eml")) { // Regular video. ReturnYouTubeDislike videoData = currentVideoData; if (videoData == null) { From 36cb36fbfd518a7d7de5d4fe936166857ab8e205 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 5 Aug 2024 22:11:15 +0000 Subject: [PATCH 32/32] chore(release): 1.12.0-dev.10 [skip ci] # [1.12.0-dev.10](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.9...v1.12.0-dev.10) (2024-08-05) ### Bug Fixes * **YouTube - Return YouTube Dislike:** Fix dislikes not appearing due to new component name ([#674](https://github.com/ReVanced/revanced-integrations/issues/674)) ([509e151](https://github.com/ReVanced/revanced-integrations/commit/509e1516f817bd736c3b2cc75bb5b48ab7de404a)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6daf562359..1b36fe09bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.12.0-dev.10](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.9...v1.12.0-dev.10) (2024-08-05) + + +### Bug Fixes + +* **YouTube - Return YouTube Dislike:** Fix dislikes not appearing due to new component name ([#674](https://github.com/ReVanced/revanced-integrations/issues/674)) ([509e151](https://github.com/ReVanced/revanced-integrations/commit/509e1516f817bd736c3b2cc75bb5b48ab7de404a)) + # [1.12.0-dev.9](https://github.com/ReVanced/revanced-integrations/compare/v1.12.0-dev.8...v1.12.0-dev.9) (2024-08-04) diff --git a/gradle.properties b/gradle.properties index c901ca0458..303cef5855 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 1.12.0-dev.9 +version = 1.12.0-dev.10