From da923a38a06baf8c30d38211e8354be4edb0ad51 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:11:54 +0400 Subject: [PATCH 01/53] fix(YouTube - Video Id): Fix video id not showing the currently playing video (#484) Co-authored-by: oSumAtrIX --- .../patches/VideoInformation.java | 41 ++++++++++++++++--- .../patches/spoof/SpoofSignaturePatch.java | 35 +++++++++------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java index ad5bcd1686..ee9034b0b3 100644 --- a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java +++ b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java @@ -1,16 +1,15 @@ package app.revanced.integrations.patches; import androidx.annotation.NonNull; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Method; -import java.util.Objects; - import app.revanced.integrations.patches.playback.speed.RememberPlaybackSpeedPatch; import app.revanced.integrations.shared.VideoState; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.Objects; + /** * Hooking class for the current playing video. */ @@ -25,6 +24,10 @@ public final class VideoInformation { private static String videoId = ""; private static long videoLength = 0; private static long videoTime = -1; + + @NonNull + private static volatile String playerResponseVideoId = ""; + /** * The current playback speed */ @@ -61,6 +64,18 @@ public static void setVideoId(@NonNull String newlyLoadedVideoId) { } } + /** + * Injection point. Called off the main thread. + * + * @param videoId The id of the last video loaded. + */ + public static void setPlayerResponseVideoId(@NonNull String videoId) { + if (!playerResponseVideoId.equals(videoId)) { + LogHelper.printDebug(() -> "New player response video id: " + videoId); + playerResponseVideoId = videoId; + } + } + /** * Injection point. * Called when user selects a playback speed. @@ -141,6 +156,22 @@ public static String getVideoId() { return videoId; } + /** + * Differs from {@link #videoId} as this is the video id for the + * last player response received, which may not be the current video playing. + * + * If Shorts are loading the background, this commonly will be + * different from the Short that is currently on screen. + * + * For most use cases, you should instead use {@link #getVideoId()}. + * + * @return The id of the last video loaded. Empty string if not set yet. + */ + @NonNull + public static String getPlayerResponseVideoId() { + return playerResponseVideoId; + } + /** * @return The current playback speed. */ diff --git a/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java b/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java index 69f00abfd6..42392480ad 100644 --- a/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java @@ -1,19 +1,20 @@ package app.revanced.integrations.patches.spoof; +import static app.revanced.integrations.patches.spoof.requests.StoryboardRendererRequester.getStoryboardRenderer; +import static app.revanced.integrations.utils.ReVancedUtils.containsAny; + import androidx.annotation.Nullable; -import app.revanced.integrations.patches.VideoInformation; -import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.shared.PlayerType; -import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.utils.ReVancedUtils; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static app.revanced.integrations.patches.spoof.requests.StoryboardRendererRequester.getStoryboardRenderer; -import static app.revanced.integrations.utils.ReVancedUtils.containsAny; +import app.revanced.integrations.patches.VideoInformation; +import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.shared.PlayerType; +import app.revanced.integrations.utils.LogHelper; +import app.revanced.integrations.utils.ReVancedUtils; /** @noinspection unused*/ public class SpoofSignaturePatch { @@ -46,7 +47,7 @@ public class SpoofSignaturePatch { /** * Last video id loaded. Used to prevent reloading the same spec multiple times. */ - private static volatile String currentVideoId; + private static volatile String lastPlayerResponseVideoId; private static volatile Future rendererFuture; @@ -83,7 +84,6 @@ public static String spoofParameter(String parameters) { var isClip = parameters.length() > 150; if (isClip) return parameters; - // Shorts do not need to be spoofed. if (parameters.startsWith(SHORTS_PLAYER_PARAMETERS)) return parameters; @@ -96,18 +96,23 @@ public static String spoofParameter(String parameters) { // This will cause playback issues in the feed, but it's better than manipulating the history. parameters; - String videoId = VideoInformation.getVideoId(); - if (!videoId.equals(currentVideoId)) { + fetchStoryboardRenderer(); + + return INCOGNITO_PARAMETERS; + } + + private static void fetchStoryboardRenderer() { + String videoId = VideoInformation.getPlayerResponseVideoId(); + if (!videoId.equals(lastPlayerResponseVideoId)) { rendererFuture = ReVancedUtils.submitOnBackgroundThread(() -> getStoryboardRenderer(videoId)); - currentVideoId = videoId; + lastPlayerResponseVideoId = videoId; } - // Occasionally when a new video is opened the video will be frozen a few seconds while the audio plays. + // Block until the fetch is completed. Without this, occasionally when a new video is opened + // the video will be frozen a few seconds while the audio plays. // This is because the main thread is calling to get the storyboard but the fetch is not completed. // To prevent this, call get() here and block until the fetch is completed. // So later when the main thread calls to get the renderer it will never block as the future is done. getRenderer(); - - return INCOGNITO_PARAMETERS; } /** From 27f49dfd1e8fbfd3e28270da91ad437df8a54761 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:12:14 +0400 Subject: [PATCH 02/53] fix(YouTube - Client spoof): Fix toast shown for live streams (#489) --- .../patches/spoof/SpoofSignaturePatch.java | 23 +++++++++++-------- .../patches/spoof/StoryboardRenderer.java | 13 ++++++++--- .../requests/StoryboardRendererRequester.java | 6 +++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java b/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java index 42392480ad..16a284d049 100644 --- a/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofSignaturePatch.java @@ -128,23 +128,26 @@ public static boolean getSeekbarThumbnailOverrideValue() { */ @Nullable public static String getStoryboardRendererSpec(String originalStoryboardRendererSpec) { - if (!SettingsEnum.SPOOF_SIGNATURE.getBoolean()) return originalStoryboardRendererSpec; - - StoryboardRenderer renderer = getRenderer(); - if (renderer == null) return originalStoryboardRendererSpec; + if (SettingsEnum.SPOOF_SIGNATURE.getBoolean()) { + StoryboardRenderer renderer = getRenderer(); + if (renderer != null) return renderer.getSpec(); + } - return renderer.getSpec(); + return originalStoryboardRendererSpec; } /** * Injection point. */ public static int getRecommendedLevel(int originalLevel) { - if (!SettingsEnum.SPOOF_SIGNATURE.getBoolean()) return originalLevel; - - StoryboardRenderer renderer = getRenderer(); - if (renderer == null) return originalLevel; + if (SettingsEnum.SPOOF_SIGNATURE.getBoolean()) { + StoryboardRenderer renderer = getRenderer(); + if (renderer != null) { + Integer recommendedLevel = renderer.getRecommendedLevel(); + if (recommendedLevel != null) return recommendedLevel; + } + } - return renderer.getRecommendedLevel(); + return originalLevel; } } diff --git a/app/src/main/java/app/revanced/integrations/patches/spoof/StoryboardRenderer.java b/app/src/main/java/app/revanced/integrations/patches/spoof/StoryboardRenderer.java index c7ce43e57d..d0e70988bf 100644 --- a/app/src/main/java/app/revanced/integrations/patches/spoof/StoryboardRenderer.java +++ b/app/src/main/java/app/revanced/integrations/patches/spoof/StoryboardRenderer.java @@ -1,13 +1,16 @@ package app.revanced.integrations.patches.spoof; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.jetbrains.annotations.NotNull; public final class StoryboardRenderer { private final String spec; - private final int recommendedLevel; + @Nullable + private final Integer recommendedLevel; - public StoryboardRenderer(String spec, int recommendedLevel) { + public StoryboardRenderer(String spec, @Nullable Integer recommendedLevel) { this.spec = spec; this.recommendedLevel = recommendedLevel; } @@ -17,7 +20,11 @@ public String getSpec() { return spec; } - public int getRecommendedLevel() { + /** + * @return Recommended image quality level, or NULL if no recommendation exists. + */ + @Nullable + public Integer getRecommendedLevel() { return recommendedLevel; } diff --git a/app/src/main/java/app/revanced/integrations/patches/spoof/requests/StoryboardRendererRequester.java b/app/src/main/java/app/revanced/integrations/patches/spoof/requests/StoryboardRendererRequester.java index 3138630570..61828a04bb 100644 --- a/app/src/main/java/app/revanced/integrations/patches/spoof/requests/StoryboardRendererRequester.java +++ b/app/src/main/java/app/revanced/integrations/patches/spoof/requests/StoryboardRendererRequester.java @@ -49,7 +49,7 @@ private static boolean isPlayabilityStatusOk(@NonNull JSONObject playerResponse) try { return playerResponse.getJSONObject("playabilityStatus").getString("status").equals("OK"); } catch (JSONException e) { - LogHelper.printException(() -> "Failed to get playabilityStatus", e); + LogHelper.printDebug(() -> "Failed to get playabilityStatus for response: " + playerResponse); } return false; @@ -80,7 +80,9 @@ private static StoryboardRenderer getStoryboardRendererUsingResponse(@NonNull JS final var rendererElement = storyboards.getJSONObject(storyboardsRendererTag); StoryboardRenderer renderer = new StoryboardRenderer( rendererElement.getString("spec"), - rendererElement.getInt("recommendedLevel") + rendererElement.has("recommendedLevel") + ? rendererElement.getInt("recommendedLevel") + : null ); LogHelper.printDebug(() -> "Fetched: " + renderer); From 78bea48e4045602e6cdabfac31cd46c3e785e810 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 28 Sep 2023 13:16:02 +0000 Subject: [PATCH 03/53] chore(release): 0.118.0-dev.17 [skip ci] # [0.118.0-dev.17](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.16...v0.118.0-dev.17) (2023-09-28) ### Bug Fixes * **YouTube - Client spoof:** Fix toast shown for live streams ([#489](https://github.com/ReVanced/revanced-integrations/issues/489)) ([27f49df](https://github.com/ReVanced/revanced-integrations/commit/27f49dfd1e8fbfd3e28270da91ad437df8a54761)) * **YouTube - Video Id:** Fix video id not showing the currently playing video ([#484](https://github.com/ReVanced/revanced-integrations/issues/484)) ([da923a3](https://github.com/ReVanced/revanced-integrations/commit/da923a38a06baf8c30d38211e8354be4edb0ad51)) --- CHANGELOG.md | 8 ++++++++ gradle.properties | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea31817b81..377555f42b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [0.118.0-dev.17](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.16...v0.118.0-dev.17) (2023-09-28) + + +### Bug Fixes + +* **YouTube - Client spoof:** Fix toast shown for live streams ([#489](https://github.com/ReVanced/revanced-integrations/issues/489)) ([27f49df](https://github.com/ReVanced/revanced-integrations/commit/27f49dfd1e8fbfd3e28270da91ad437df8a54761)) +* **YouTube - Video Id:** Fix video id not showing the currently playing video ([#484](https://github.com/ReVanced/revanced-integrations/issues/484)) ([da923a3](https://github.com/ReVanced/revanced-integrations/commit/da923a38a06baf8c30d38211e8354be4edb0ad51)) + # [0.118.0-dev.16](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.15...v0.118.0-dev.16) (2023-09-28) diff --git a/gradle.properties b/gradle.properties index 507cb29c63..af8668ee1b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.16 +version = 0.118.0-dev.17 From 165b061fa9c5fd48b0dbb9540fd6ea6a9ffaf312 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:39:11 +0400 Subject: [PATCH 04/53] fix(YouTube - ReturnYouTubeDislike): Revert support for 18.37.36 (#488) --- .../patches/ReturnYouTubeDislikePatch.java | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 383d3185cb..48a7e81aab 100644 --- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -1,25 +1,31 @@ package app.revanced.integrations.patches; +import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote; + import android.graphics.Rect; import android.os.Build; -import android.text.*; +import android.text.Editable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextWatcher; import android.view.View; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; -import app.revanced.integrations.returnyoutubedislike.requests.ReturnYouTubeDislikeApi; -import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.shared.PlayerType; -import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.utils.ReVancedUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote; +import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; +import app.revanced.integrations.returnyoutubedislike.requests.ReturnYouTubeDislikeApi; +import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.shared.PlayerType; +import app.revanced.integrations.utils.LogHelper; +import app.revanced.integrations.utils.ReVancedUtils; /** * Handles all interaction of UI patch components. @@ -143,27 +149,23 @@ public static CharSequence onLithoTextLoaded(@NonNull Object conversionContext, @NonNull AtomicReference textRef, @NonNull CharSequence original) { try { - if (!SettingsEnum.RYD_ENABLED.getBoolean()) { + if (!SettingsEnum.RYD_ENABLED.getBoolean() || PlayerType.getCurrent().isNoneOrHidden()) { return original; } String conversionContextString = conversionContext.toString(); LogHelper.printDebug(() -> "conversionContext: " + conversionContextString); - final Spanned replacement; + final boolean isSegmentedButton; if (conversionContextString.contains("|segmented_like_dislike_button.eml|")) { - replacement = ReturnYouTubeDislike.getDislikesSpanForRegularVideo((Spannable) original, true); - } else if (conversionContextString.contains("|dislike_button.eml|") ) { - // This code path is basically dead because it's only used when spoofing between 17.09.xx and 17.30.xx - // but spoofing to that range gives a broken UI layout. - // Keep this check here anyways just in case the old litho layout is somehow still used. - replacement = ReturnYouTubeDislike.getDislikesSpanForRegularVideo((Spannable) original, false); - } else if (conversionContextString.contains("|shorts_dislike_button.eml|")) { - replacement = ReturnYouTubeDislike.getDislikeSpanForShort((Spannable) original); + isSegmentedButton = true; + } else if (conversionContextString.contains("|dislike_button.eml|")) { + isSegmentedButton = false; } else { return original; } + Spanned replacement = ReturnYouTubeDislike.getDislikesSpanForRegularVideo((Spannable) original, isSegmentedButton); textRef.set(replacement); return replacement; } catch (Exception ex) { From 7dfa0e465344b554b7f88a26f363206467ab9cf5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 28 Sep 2023 13:42:52 +0000 Subject: [PATCH 05/53] chore(release): 0.118.0-dev.18 [skip ci] # [0.118.0-dev.18](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.17...v0.118.0-dev.18) (2023-09-28) ### Bug Fixes * **YouTube - ReturnYouTubeDislike:** Revert support for 18.37.36 ([#488](https://github.com/ReVanced/revanced-integrations/issues/488)) ([165b061](https://github.com/ReVanced/revanced-integrations/commit/165b061fa9c5fd48b0dbb9540fd6ea6a9ffaf312)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 377555f42b..562c8a234b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.118.0-dev.18](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.17...v0.118.0-dev.18) (2023-09-28) + + +### Bug Fixes + +* **YouTube - ReturnYouTubeDislike:** Revert support for 18.37.36 ([#488](https://github.com/ReVanced/revanced-integrations/issues/488)) ([165b061](https://github.com/ReVanced/revanced-integrations/commit/165b061fa9c5fd48b0dbb9540fd6ea6a9ffaf312)) + # [0.118.0-dev.17](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.16...v0.118.0-dev.17) (2023-09-28) diff --git a/gradle.properties b/gradle.properties index af8668ee1b..def176f774 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.17 +version = 0.118.0-dev.18 From b472aeeed7904f6b6d537dfbddda1a97c7ddcd5e Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 1 Oct 2023 05:02:35 +0200 Subject: [PATCH 06/53] feat(YouTube - Hide layout components): Hide timed reactions --- .../patches/components/LayoutComponentsFilter.java | 7 +++++++ .../app/revanced/integrations/settings/SettingsEnum.java | 1 + 2 files changed, 8 insertions(+) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index 7c227ba78c..acc322ae55 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -146,6 +146,12 @@ public LayoutComponentsFilter() { "cell_divider" // layout residue (gray line above the buttoned ad), ); + final var timedReactions = new StringFilterGroup( + SettingsEnum.HIDE_TIMED_REACTIONS, + "emoji_control_panel", + "timed_reaction" + ); + final var chipsShelf = new StringFilterGroup( SettingsEnum.HIDE_CHIPS_SHELF, "chips_shelf" @@ -168,6 +174,7 @@ public LayoutComponentsFilter() { channelGuidelines, audioTrackButton, artistCard, + timedReactions, imageShelf, subscribersCommunityGuidelines, channelMemberShelf, diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 699abe4d75..35a5703272 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -65,6 +65,7 @@ public enum SettingsEnum { HIDE_EMERGENCY_BOX("revanced_hide_emergency_box", BOOLEAN, TRUE), HIDE_FEED_SURVEY("revanced_hide_feed_survey", BOOLEAN, TRUE), HIDE_GRAY_SEPARATOR("revanced_hide_gray_separator", BOOLEAN, TRUE), + HIDE_TIMED_REACTIONS("revanced_hide_timed_reactions", BOOLEAN, TRUE), HIDE_HIDE_CHANNEL_GUIDELINES("revanced_hide_channel_guidelines", BOOLEAN, TRUE), HIDE_IMAGE_SHELF("revanced_hide_image_shelf", BOOLEAN, TRUE), HIDE_HIDE_INFO_PANELS("revanced_hide_info_panels", BOOLEAN, TRUE), From b87d8066597a2c989480de47561007844964a0e4 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 1 Oct 2023 05:04:43 +0200 Subject: [PATCH 07/53] feat(YouTube - Hide layout components): Hide "Notify me" button --- .../patches/components/LayoutComponentsFilter.java | 6 ++++++ .../app/revanced/integrations/settings/SettingsEnum.java | 2 ++ 2 files changed, 8 insertions(+) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index acc322ae55..087855d0a2 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -152,6 +152,11 @@ public LayoutComponentsFilter() { "timed_reaction" ); + final var notifyMe = new StringFilterGroup( + SettingsEnum.HIDE_NOTIFY_ME_BUTTON, + "set_reminder_button" + ); + final var chipsShelf = new StringFilterGroup( SettingsEnum.HIDE_CHIPS_SHELF, "chips_shelf" @@ -170,6 +175,7 @@ public LayoutComponentsFilter() { compactBanner, inFeedSurvey, medicalPanel, + notifyMe, infoPanel, channelGuidelines, audioTrackButton, diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 35a5703272..30a852bd85 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -66,6 +66,8 @@ public enum SettingsEnum { HIDE_FEED_SURVEY("revanced_hide_feed_survey", BOOLEAN, TRUE), HIDE_GRAY_SEPARATOR("revanced_hide_gray_separator", BOOLEAN, TRUE), HIDE_TIMED_REACTIONS("revanced_hide_timed_reactions", BOOLEAN, TRUE), + HIDE_NOTIFY_ME_BUTTON("revanced_hide_notify_me_button", BOOLEAN, TRUE), + HIDE_HIDE_CHANNEL_GUIDELINES("revanced_hide_channel_guidelines", BOOLEAN, TRUE), HIDE_IMAGE_SHELF("revanced_hide_image_shelf", BOOLEAN, TRUE), HIDE_HIDE_INFO_PANELS("revanced_hide_info_panels", BOOLEAN, TRUE), From e2254681cd77481376e4c3f8c556db510fdfce6c Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 1 Oct 2023 05:07:29 +0200 Subject: [PATCH 08/53] feat(YouTube - Hide layout components): Hide "Join" button --- .../patches/components/LayoutComponentsFilter.java | 6 ++++++ .../app/revanced/integrations/settings/SettingsEnum.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index 087855d0a2..83291f6991 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -157,6 +157,11 @@ public LayoutComponentsFilter() { "set_reminder_button" ); + final var joinMembership = new StringFilterGroup( + SettingsEnum.HIDE_JOIN_MEMBERSHIP_BUTTON, + "compact_sponsor_button" + ); + final var chipsShelf = new StringFilterGroup( SettingsEnum.HIDE_CHIPS_SHELF, "chips_shelf" @@ -174,6 +179,7 @@ public LayoutComponentsFilter() { relatedVideos, compactBanner, inFeedSurvey, + joinMembership, medicalPanel, notifyMe, infoPanel, diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 30a852bd85..4a6e895389 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -67,7 +67,7 @@ public enum SettingsEnum { HIDE_GRAY_SEPARATOR("revanced_hide_gray_separator", BOOLEAN, TRUE), HIDE_TIMED_REACTIONS("revanced_hide_timed_reactions", BOOLEAN, TRUE), HIDE_NOTIFY_ME_BUTTON("revanced_hide_notify_me_button", BOOLEAN, TRUE), - + HIDE_JOIN_MEMBERSHIP_BUTTON("revanced_hide_join_membership_button", BOOLEAN, TRUE), HIDE_HIDE_CHANNEL_GUIDELINES("revanced_hide_channel_guidelines", BOOLEAN, TRUE), HIDE_IMAGE_SHELF("revanced_hide_image_shelf", BOOLEAN, TRUE), HIDE_HIDE_INFO_PANELS("revanced_hide_info_panels", BOOLEAN, TRUE), From c992289d59fba5c9439bcec5d37aabb2730a0e61 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 1 Oct 2023 03:11:33 +0000 Subject: [PATCH 09/53] chore(release): 0.118.0-dev.19 [skip ci] # [0.118.0-dev.19](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.18...v0.118.0-dev.19) (2023-10-01) ### Features * **YouTube - Hide layout components:** Hide "Join" button ([e225468](https://github.com/ReVanced/revanced-integrations/commit/e2254681cd77481376e4c3f8c556db510fdfce6c)) * **YouTube - Hide layout components:** Hide "Notify me" button ([b87d806](https://github.com/ReVanced/revanced-integrations/commit/b87d8066597a2c989480de47561007844964a0e4)) * **YouTube - Hide layout components:** Hide timed reactions ([b472aee](https://github.com/ReVanced/revanced-integrations/commit/b472aeeed7904f6b6d537dfbddda1a97c7ddcd5e)) --- CHANGELOG.md | 9 +++++++++ gradle.properties | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 562c8a234b..94966e1eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# [0.118.0-dev.19](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.18...v0.118.0-dev.19) (2023-10-01) + + +### Features + +* **YouTube - Hide layout components:** Hide "Join" button ([e225468](https://github.com/ReVanced/revanced-integrations/commit/e2254681cd77481376e4c3f8c556db510fdfce6c)) +* **YouTube - Hide layout components:** Hide "Notify me" button ([b87d806](https://github.com/ReVanced/revanced-integrations/commit/b87d8066597a2c989480de47561007844964a0e4)) +* **YouTube - Hide layout components:** Hide timed reactions ([b472aee](https://github.com/ReVanced/revanced-integrations/commit/b472aeeed7904f6b6d537dfbddda1a97c7ddcd5e)) + # [0.118.0-dev.18](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.17...v0.118.0-dev.18) (2023-09-28) diff --git a/gradle.properties b/gradle.properties index def176f774..b067ac1d36 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.18 +version = 0.118.0-dev.19 From 1689bf412593558244587ffaf291fb9587f27103 Mon Sep 17 00:00:00 2001 From: Temm Date: Sun, 1 Oct 2023 05:12:00 +0200 Subject: [PATCH 10/53] refactor(Tumblr): Use a common filter patch (#479) Co-authored-by: oSumAtrIX --- .../tumblr/patches/TimelineFilterPatch.java | 32 +++++++++++++++++++ .../tumblr/rumblr/model/TimelineObject.java | 8 +++++ .../rumblr/model/TimelineObjectType.java | 4 +++ .../com/tumblr/rumblr/model/Timelineable.java | 5 +++ 4 files changed, 49 insertions(+) create mode 100644 app/src/main/java/app/revanced/tumblr/patches/TimelineFilterPatch.java create mode 100644 dummy/src/main/java/com/tumblr/rumblr/model/TimelineObject.java create mode 100644 dummy/src/main/java/com/tumblr/rumblr/model/TimelineObjectType.java create mode 100644 dummy/src/main/java/com/tumblr/rumblr/model/Timelineable.java diff --git a/app/src/main/java/app/revanced/tumblr/patches/TimelineFilterPatch.java b/app/src/main/java/app/revanced/tumblr/patches/TimelineFilterPatch.java new file mode 100644 index 0000000000..1a4d50eff3 --- /dev/null +++ b/app/src/main/java/app/revanced/tumblr/patches/TimelineFilterPatch.java @@ -0,0 +1,32 @@ +package app.revanced.tumblr.patches; + +import com.tumblr.rumblr.model.TimelineObject; +import com.tumblr.rumblr.model.Timelineable; + +import java.util.HashSet; +import java.util.List; + +public final class TimelineFilterPatch { + private static final HashSet blockedObjectTypes = new HashSet<>(); + + static { + // This dummy gets removed by the TimelineFilterPatch and in its place, + // equivalent instructions with a different constant string + // will be inserted for each Timeline object type filter. + // Modifying this line may break the patch. + blockedObjectTypes.add("BLOCKED_OBJECT_DUMMY"); + } + + // Calls to this method are injected where the list of Timeline objects is first received. + // We modify the list filter out elements that we want to hide. + public static void filterTimeline(final List> timelineObjects) { + final var iterator = timelineObjects.iterator(); + while (iterator.hasNext()) { + var timelineElement = iterator.next(); + if (timelineElement == null) continue; + + String elementType = timelineElement.getData().getTimelineObjectType().toString(); + if (blockedObjectTypes.contains(elementType)) iterator.remove(); + } + } +} diff --git a/dummy/src/main/java/com/tumblr/rumblr/model/TimelineObject.java b/dummy/src/main/java/com/tumblr/rumblr/model/TimelineObject.java new file mode 100644 index 0000000000..8bb2c885d4 --- /dev/null +++ b/dummy/src/main/java/com/tumblr/rumblr/model/TimelineObject.java @@ -0,0 +1,8 @@ +package com.tumblr.rumblr.model; + +public class TimelineObject { + public final T getData() { + throw new UnsupportedOperationException("Stub"); + } + +} diff --git a/dummy/src/main/java/com/tumblr/rumblr/model/TimelineObjectType.java b/dummy/src/main/java/com/tumblr/rumblr/model/TimelineObjectType.java new file mode 100644 index 0000000000..f9b7d7abca --- /dev/null +++ b/dummy/src/main/java/com/tumblr/rumblr/model/TimelineObjectType.java @@ -0,0 +1,4 @@ +package com.tumblr.rumblr.model; + +public enum TimelineObjectType { +} diff --git a/dummy/src/main/java/com/tumblr/rumblr/model/Timelineable.java b/dummy/src/main/java/com/tumblr/rumblr/model/Timelineable.java new file mode 100644 index 0000000000..bf84887def --- /dev/null +++ b/dummy/src/main/java/com/tumblr/rumblr/model/Timelineable.java @@ -0,0 +1,5 @@ +package com.tumblr.rumblr.model; + +public interface Timelineable { + TimelineObjectType getTimelineObjectType(); +} From 9685070eda5b448eb33324b4bfabd4c7eae42f9f Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Oct 2023 00:50:18 +0200 Subject: [PATCH 11/53] fix(YouTube - Hide shorts components): Hide subscribe button in paused state --- .../revanced/integrations/patches/components/ShortsFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index e253d9173f..6b03173b07 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -55,7 +55,8 @@ public ShortsFilter() { ); var subscribeButton = new StringFilterGroup( SettingsEnum.HIDE_SHORTS_SUBSCRIBE_BUTTON, - "subscribe_button" + "subscribe_button", + "shorts_paused_state" ); channelBar = new StringFilterGroup( From d156951460f9521842302c849a8d31af20670f01 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 1 Oct 2023 22:54:38 +0000 Subject: [PATCH 12/53] chore(release): 0.118.0-dev.20 [skip ci] # [0.118.0-dev.20](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.19...v0.118.0-dev.20) (2023-10-01) ### Bug Fixes * **YouTube - Hide shorts components:** Hide subscribe button in paused state ([9685070](https://github.com/ReVanced/revanced-integrations/commit/9685070eda5b448eb33324b4bfabd4c7eae42f9f)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94966e1eaa..aed0936615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.118.0-dev.20](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.19...v0.118.0-dev.20) (2023-10-01) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Hide subscribe button in paused state ([9685070](https://github.com/ReVanced/revanced-integrations/commit/9685070eda5b448eb33324b4bfabd4c7eae42f9f)) + # [0.118.0-dev.19](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.18...v0.118.0-dev.19) (2023-10-01) diff --git a/gradle.properties b/gradle.properties index b067ac1d36..a218275c56 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.19 +version = 0.118.0-dev.20 From 93a30453d9693e015b1f58a12f85cf355770a4ca Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Oct 2023 01:12:59 +0200 Subject: [PATCH 13/53] feat(YouTube - Hide layout components): Hide search result shelf header --- .../components/LayoutComponentsFilter.java | 8 ++++++- .../patches/components/LithoFilterPatch.java | 12 ++++++++++ .../integrations/settings/SettingsEnum.java | 1 + .../integrations/utils/ReVancedUtils.java | 22 ++++++++----------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index 83291f6991..d03ccbb015 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -152,6 +152,11 @@ public LayoutComponentsFilter() { "timed_reaction" ); + final var searchResultShelfHeader = new StartsWithStringFilterGroup( + SettingsEnum.HIDE_SEARCH_RESULT_SHELF_HEADER, + "shelf_header.eml" + ); + final var notifyMe = new StringFilterGroup( SettingsEnum.HIDE_NOTIFY_ME_BUTTON, "set_reminder_button" @@ -183,12 +188,13 @@ public LayoutComponentsFilter() { medicalPanel, notifyMe, infoPanel, + subscribersCommunityGuidelines, channelGuidelines, audioTrackButton, artistCard, timedReactions, imageShelf, - subscribersCommunityGuidelines, + searchResultShelfHeader, channelMemberShelf, custom ); diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index 7cfe060b1d..da030a3725 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -85,6 +85,18 @@ public FilterGroupResult check(final String string) { } } +class StartsWithStringFilterGroup extends StringFilterGroup { + + public StartsWithStringFilterGroup(final SettingsEnum setting, final String... filters) { + super(setting, filters); + } + + @Override + public FilterGroupResult check(final String string) { + return new FilterGroupResult(setting, isEnabled() && ReVancedUtils.startsWithAny(string, filters)); + } +} + final class CustomFilterGroup extends StringFilterGroup { public CustomFilterGroup(final SettingsEnum setting, final SettingsEnum filter) { diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 4a6e895389..5e5c56ffd1 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -66,6 +66,7 @@ public enum SettingsEnum { HIDE_FEED_SURVEY("revanced_hide_feed_survey", BOOLEAN, TRUE), HIDE_GRAY_SEPARATOR("revanced_hide_gray_separator", BOOLEAN, TRUE), HIDE_TIMED_REACTIONS("revanced_hide_timed_reactions", BOOLEAN, TRUE), + HIDE_SEARCH_RESULT_SHELF_HEADER("revanced_hide_search_result_shelf_header", BOOLEAN, TRUE), HIDE_NOTIFY_ME_BUTTON("revanced_hide_notify_me_button", BOOLEAN, TRUE), HIDE_JOIN_MEMBERSHIP_BUTTON("revanced_hide_join_membership_button", BOOLEAN, TRUE), HIDE_HIDE_CHANNEL_GUIDELINES("revanced_hide_channel_guidelines", BOOLEAN, TRUE), diff --git a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java index 564de2c384..a145bbfc75 100644 --- a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java +++ b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java @@ -10,25 +10,15 @@ import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.Toast; -import android.widget.Toolbar; - +import android.widget.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import app.revanced.integrations.settings.SettingsEnum; import java.text.Bidi; import java.util.Locale; import java.util.Objects; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import app.revanced.integrations.settings.SettingsEnum; +import java.util.concurrent.*; public class ReVancedUtils { @@ -98,6 +88,12 @@ public static boolean containsAny(@NonNull String value, @NonNull String... targ return false; } + public static boolean startsWithAny(@NonNull String value, @NonNull String... targets) { + for (String string : targets) + if (!string.isEmpty() && value.startsWith(string)) return true; + return false; + } + /** * @return zero, if the resource is not found */ From 5185673780252f14f97d18c56ef25648a71a5b5e Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Oct 2023 15:26:40 +0200 Subject: [PATCH 14/53] refactor: Move classes to correct path --- .../patches/ReturnYouTubeDislikePatch.java | 23 ++++++++----------- .../{ => spoof}/SpoofAppVersionPatch.java | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) rename app/src/main/java/app/revanced/integrations/patches/{ => spoof}/SpoofAppVersionPatch.java (87%) diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 48a7e81aab..2c3b3d0fe1 100644 --- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -1,25 +1,13 @@ package app.revanced.integrations.patches; -import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote; - import android.graphics.Rect; import android.os.Build; -import android.text.Editable; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.TextWatcher; +import android.text.*; import android.view.View; import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - +import app.revanced.integrations.patches.spoof.SpoofAppVersionPatch; import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; import app.revanced.integrations.returnyoutubedislike.requests.ReturnYouTubeDislikeApi; import app.revanced.integrations.settings.SettingsEnum; @@ -27,6 +15,13 @@ import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote; + /** * Handles all interaction of UI patch components. * diff --git a/app/src/main/java/app/revanced/integrations/patches/SpoofAppVersionPatch.java b/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofAppVersionPatch.java similarity index 87% rename from app/src/main/java/app/revanced/integrations/patches/SpoofAppVersionPatch.java rename to app/src/main/java/app/revanced/integrations/patches/spoof/SpoofAppVersionPatch.java index 4967bb9519..c43d603127 100644 --- a/app/src/main/java/app/revanced/integrations/patches/SpoofAppVersionPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/spoof/SpoofAppVersionPatch.java @@ -1,4 +1,4 @@ -package app.revanced.integrations.patches; +package app.revanced.integrations.patches.spoof; import app.revanced.integrations.settings.SettingsEnum; From f451d67dcb14fd5cd5d2e8ae736372ca3046fdcd Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 2 Oct 2023 14:29:22 +0000 Subject: [PATCH 15/53] chore(release): 0.118.0-dev.21 [skip ci] # [0.118.0-dev.21](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.20...v0.118.0-dev.21) (2023-10-02) ### Features * **YouTube - Hide layout components:** Hide search result shelf header ([93a3045](https://github.com/ReVanced/revanced-integrations/commit/93a30453d9693e015b1f58a12f85cf355770a4ca)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aed0936615..a84b385311 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.118.0-dev.21](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.20...v0.118.0-dev.21) (2023-10-02) + + +### Features + +* **YouTube - Hide layout components:** Hide search result shelf header ([93a3045](https://github.com/ReVanced/revanced-integrations/commit/93a30453d9693e015b1f58a12f85cf355770a4ca)) + # [0.118.0-dev.20](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.19...v0.118.0-dev.20) (2023-10-01) diff --git a/gradle.properties b/gradle.properties index a218275c56..4831a7515d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.20 +version = 0.118.0-dev.21 From 25f73eb3a93699301d1211c306b7f4a896377b5e Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Oct 2023 22:05:31 +0200 Subject: [PATCH 16/53] refactor: Simplify filtering a component --- .../patches/components/LayoutComponentsFilter.java | 6 ++++-- .../patches/components/LithoFilterPatch.java | 12 ------------ .../revanced/integrations/utils/ReVancedUtils.java | 6 ------ 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index d03ccbb015..e197d4c8a2 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -19,6 +19,7 @@ public final class LayoutComponentsFilter extends Filter { SettingsEnum.HIDE_MIX_PLAYLISTS, "&list=" ); + private final StringFilterGroup searchResultShelfHeader; @RequiresApi(api = Build.VERSION_CODES.N) public LayoutComponentsFilter() { @@ -152,7 +153,7 @@ public LayoutComponentsFilter() { "timed_reaction" ); - final var searchResultShelfHeader = new StartsWithStringFilterGroup( + searchResultShelfHeader = new StringFilterGroup( SettingsEnum.HIDE_SEARCH_RESULT_SHELF_HEADER, "shelf_header.eml" ); @@ -194,7 +195,6 @@ public LayoutComponentsFilter() { artistCard, timedReactions, imageShelf, - searchResultShelfHeader, channelMemberShelf, custom ); @@ -211,6 +211,8 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto if (matchedGroup != custom && exceptions.matches(path)) return false; // Exceptions are not filtered. + if (matchedGroup == searchResultShelfHeader && matchedIndex == 0) return true; + return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index da030a3725..7cfe060b1d 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -85,18 +85,6 @@ public FilterGroupResult check(final String string) { } } -class StartsWithStringFilterGroup extends StringFilterGroup { - - public StartsWithStringFilterGroup(final SettingsEnum setting, final String... filters) { - super(setting, filters); - } - - @Override - public FilterGroupResult check(final String string) { - return new FilterGroupResult(setting, isEnabled() && ReVancedUtils.startsWithAny(string, filters)); - } -} - final class CustomFilterGroup extends StringFilterGroup { public CustomFilterGroup(final SettingsEnum setting, final SettingsEnum filter) { diff --git a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java index a145bbfc75..940dd50819 100644 --- a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java +++ b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java @@ -88,12 +88,6 @@ public static boolean containsAny(@NonNull String value, @NonNull String... targ return false; } - public static boolean startsWithAny(@NonNull String value, @NonNull String... targets) { - for (String string : targets) - if (!string.isEmpty() && value.startsWith(string)) return true; - return false; - } - /** * @return zero, if the resource is not found */ From 3d0fc1d610cdf50bb7cc4687d899e0acbf3fb83e Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Oct 2023 22:15:29 +0200 Subject: [PATCH 17/53] fix: Do not always hide the component --- .../patches/components/LayoutComponentsFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index e197d4c8a2..b2d626510d 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -211,7 +211,8 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto if (matchedGroup != custom && exceptions.matches(path)) return false; // Exceptions are not filtered. - if (matchedGroup == searchResultShelfHeader && matchedIndex == 0) return true; + // TODO: This also hides the feed Shorts shelf header + if (matchedGroup == searchResultShelfHeader && matchedIndex != 0) return false; return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); } From b280de31957631180f07057cc7e466bd26e2f7fb Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Oct 2023 22:16:06 +0200 Subject: [PATCH 18/53] feat(YouTube - Hide layout components): Disable hiding search result shelf header by default The reason for this is that it also hides Shorts shelves unintentionally. --- .../java/app/revanced/integrations/settings/SettingsEnum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 5e5c56ffd1..581f934057 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -66,7 +66,7 @@ public enum SettingsEnum { HIDE_FEED_SURVEY("revanced_hide_feed_survey", BOOLEAN, TRUE), HIDE_GRAY_SEPARATOR("revanced_hide_gray_separator", BOOLEAN, TRUE), HIDE_TIMED_REACTIONS("revanced_hide_timed_reactions", BOOLEAN, TRUE), - HIDE_SEARCH_RESULT_SHELF_HEADER("revanced_hide_search_result_shelf_header", BOOLEAN, TRUE), + HIDE_SEARCH_RESULT_SHELF_HEADER("revanced_hide_search_result_shelf_header", BOOLEAN, FALSE), HIDE_NOTIFY_ME_BUTTON("revanced_hide_notify_me_button", BOOLEAN, TRUE), HIDE_JOIN_MEMBERSHIP_BUTTON("revanced_hide_join_membership_button", BOOLEAN, TRUE), HIDE_HIDE_CHANNEL_GUIDELINES("revanced_hide_channel_guidelines", BOOLEAN, TRUE), From a198ef83dd89360db9a16e529be4cba9efedbac9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 2 Oct 2023 20:20:31 +0000 Subject: [PATCH 19/53] chore(release): 0.118.0-dev.22 [skip ci] # [0.118.0-dev.22](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.21...v0.118.0-dev.22) (2023-10-02) ### Bug Fixes * Do not always hide the component ([3d0fc1d](https://github.com/ReVanced/revanced-integrations/commit/3d0fc1d610cdf50bb7cc4687d899e0acbf3fb83e)) ### Features * **YouTube - Hide layout components:** Disable hiding search result shelf header by default ([b280de3](https://github.com/ReVanced/revanced-integrations/commit/b280de31957631180f07057cc7e466bd26e2f7fb)) --- CHANGELOG.md | 12 ++++++++++++ gradle.properties | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84b385311..b004914b8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# [0.118.0-dev.22](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.21...v0.118.0-dev.22) (2023-10-02) + + +### Bug Fixes + +* Do not always hide the component ([3d0fc1d](https://github.com/ReVanced/revanced-integrations/commit/3d0fc1d610cdf50bb7cc4687d899e0acbf3fb83e)) + + +### Features + +* **YouTube - Hide layout components:** Disable hiding search result shelf header by default ([b280de3](https://github.com/ReVanced/revanced-integrations/commit/b280de31957631180f07057cc7e466bd26e2f7fb)) + # [0.118.0-dev.21](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.20...v0.118.0-dev.21) (2023-10-02) diff --git a/gradle.properties b/gradle.properties index 4831a7515d..bf03d2e098 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.21 +version = 0.118.0-dev.22 From 4215be4250d195ecf89b041c96834be56c164f34 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 3 Oct 2023 01:27:27 +0400 Subject: [PATCH 20/53] fix(YouTube - SponsorBlock): Adjust import/export UI text (#491) --- .../settingsmenu/SponsorBlockSettingsFragment.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java b/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java index e1de088de3..456bcdc8a9 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java @@ -72,7 +72,7 @@ private void updateUI() { } else if (!SettingsEnum.SB_CREATE_NEW_SEGMENT.getBoolean()) { SponsorBlockViewController.hideNewSegmentLayout(); } - // voting and add new segment buttons automatically shows/hides themselves + // Voting and add new segment buttons automatically shows/hide themselves. sbEnabled.setChecked(enabled); @@ -109,6 +109,12 @@ private void updateUI() { privateUserId.setText(SettingsEnum.SB_PRIVATE_USER_ID.getString()); privateUserId.setEnabled(enabled); + // If the user has a private user id, then include a subtext that mentions not to share it. + String exportSummarySubText = SponsorBlockSettings.userHasSBPrivateId() + ? str("sb_settings_ie_sum_warning") + : ""; + importExport.setSummary(str("sb_settings_ie_sum", exportSummarySubText)); + apiUrl.setEnabled(enabled); importExport.setEnabled(enabled); segmentCategory.setEnabled(enabled); @@ -329,6 +335,7 @@ private void addGeneralCategory(final Context context, PreferenceScreen screen) return false; } SettingsEnum.SB_PRIVATE_USER_ID.saveValue(newUUID); + updateUI(); fetchAndDisplayStats(); return true; }); @@ -375,7 +382,7 @@ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { } }; importExport.setTitle(str("sb_settings_ie")); - importExport.setSummary(str("sb_settings_ie_sum")); + // Summary is set in updateUI() importExport.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); From 6075c9ed17c7220d8ef4a99a44ae1ad42c73c9b3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 2 Oct 2023 21:31:31 +0000 Subject: [PATCH 21/53] chore(release): 0.118.0-dev.23 [skip ci] # [0.118.0-dev.23](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.22...v0.118.0-dev.23) (2023-10-02) ### Bug Fixes * **YouTube - SponsorBlock:** Adjust import/export UI text ([#491](https://github.com/ReVanced/revanced-integrations/issues/491)) ([4215be4](https://github.com/ReVanced/revanced-integrations/commit/4215be4250d195ecf89b041c96834be56c164f34)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b004914b8b..b7c0ca6f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.118.0-dev.23](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.22...v0.118.0-dev.23) (2023-10-02) + + +### Bug Fixes + +* **YouTube - SponsorBlock:** Adjust import/export UI text ([#491](https://github.com/ReVanced/revanced-integrations/issues/491)) ([4215be4](https://github.com/ReVanced/revanced-integrations/commit/4215be4250d195ecf89b041c96834be56c164f34)) + # [0.118.0-dev.22](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.21...v0.118.0-dev.22) (2023-10-02) diff --git a/gradle.properties b/gradle.properties index bf03d2e098..376d6c52b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.22 +version = 0.118.0-dev.23 From bedb02e4f6122f3dcdc106648648eec4d6a3cbe5 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 3 Oct 2023 03:28:28 +0200 Subject: [PATCH 22/53] fix(YouTube - Hide layout components): Do not hide chapters in feed unexpectedly --- .../patches/components/LayoutComponentsFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index b2d626510d..39be57c924 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -178,7 +178,6 @@ public LayoutComponentsFilter() { communityPosts, paidContent, latestPosts, - chapters, communityGuidelines, quickActions, expandableMetadata, @@ -201,7 +200,8 @@ public LayoutComponentsFilter() { this.identifierFilterGroupList.addAll( graySeparator, - chipsShelf + chipsShelf, + chapters ); } From 1a702bce601aa8cd12214d2337a3618cca8a8d72 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 3 Oct 2023 01:32:28 +0000 Subject: [PATCH 23/53] chore(release): 0.118.0-dev.24 [skip ci] # [0.118.0-dev.24](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.23...v0.118.0-dev.24) (2023-10-03) ### Bug Fixes * **YouTube - Hide layout components:** Do not hide chapters in feed unexpectedly ([bedb02e](https://github.com/ReVanced/revanced-integrations/commit/bedb02e4f6122f3dcdc106648648eec4d6a3cbe5)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7c0ca6f3d..6657e8bdb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.118.0-dev.24](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.23...v0.118.0-dev.24) (2023-10-03) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Do not hide chapters in feed unexpectedly ([bedb02e](https://github.com/ReVanced/revanced-integrations/commit/bedb02e4f6122f3dcdc106648648eec4d6a3cbe5)) + # [0.118.0-dev.23](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.22...v0.118.0-dev.23) (2023-10-02) diff --git a/gradle.properties b/gradle.properties index 376d6c52b9..848e696fac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.23 +version = 0.118.0-dev.24 From 1efd5c8315cd87ee8736dccecec8035d20c22c30 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 4 Oct 2023 23:41:56 +0000 Subject: [PATCH 24/53] chore(release): 0.118.0 [skip ci] # [0.118.0](https://github.com/ReVanced/revanced-integrations/compare/v0.117.1...v0.118.0) (2023-10-04) ### Bug Fixes * Do not always hide the component ([3d0fc1d](https://github.com/ReVanced/revanced-integrations/commit/3d0fc1d610cdf50bb7cc4687d899e0acbf3fb83e)) * Remove parameter from route ([4b0925e](https://github.com/ReVanced/revanced-integrations/commit/4b0925e33762c02e95ef9b1aadcae1038af71a50)) * **YouTube - Client spoof:** Display seekbar thumbnails in high quality ([f71c1a0](https://github.com/ReVanced/revanced-integrations/commit/f71c1a0c156b2320e06dd98b3e5b276560d438aa)) * **YouTube - Client spoof:** Do not record feed videos to history by default ([#478](https://github.com/ReVanced/revanced-integrations/issues/478)) ([ef1cca0](https://github.com/ReVanced/revanced-integrations/commit/ef1cca02c165d9c24e64b43fae375ae57bf90a52)) * **YouTube - Client spoof:** fix occasionally frozen video playback ([#486](https://github.com/ReVanced/revanced-integrations/issues/486)) ([b0b6ff6](https://github.com/ReVanced/revanced-integrations/commit/b0b6ff6a82820d4578c5cfc5f69ae7aaaac49c7f)) * **YouTube - Client spoof:** fix storyboard fetched out of order ([#481](https://github.com/ReVanced/revanced-integrations/issues/481)) ([8398774](https://github.com/ReVanced/revanced-integrations/commit/83987747e67541cd44221ede8c4020baba36c7b8)) * **YouTube - Client spoof:** Fix toast shown for live streams ([#489](https://github.com/ReVanced/revanced-integrations/issues/489)) ([27f49df](https://github.com/ReVanced/revanced-integrations/commit/27f49dfd1e8fbfd3e28270da91ad437df8a54761)) * **YouTube - Client spoof:** fix toast shown if opening paid or age restricted video ([#482](https://github.com/ReVanced/revanced-integrations/issues/482)) ([e72b65b](https://github.com/ReVanced/revanced-integrations/commit/e72b65b599353715a6467463226abc603bc850f7)) * **YouTube - Client spoof:** Removed unused code ([#480](https://github.com/ReVanced/revanced-integrations/issues/480)) ([e6903bf](https://github.com/ReVanced/revanced-integrations/commit/e6903bff95b485d21773537bbcc162411b616618)) * **YouTube - Client spoof:** Restore clipping videos functionality ([2cd1738](https://github.com/ReVanced/revanced-integrations/commit/2cd1738d2494add13c48b64ccc9aad2432b2d8e3)) * **YouTube - Client spoof:** Restore seekbar thumbnails ([978f630](https://github.com/ReVanced/revanced-integrations/commit/978f630c0267ec2b0d9bb9b5b0b3cdc9abef65ec)) * **YouTube - Client spoof:** Show seekbar thumbnail for age restricted and paid videos ([01019b0](https://github.com/ReVanced/revanced-integrations/commit/01019b09c1c106ed814b994dd8af558a18873c1d)) * **YouTube - Custom filter:** Use new lines between components instead of commas ([#475](https://github.com/ReVanced/revanced-integrations/issues/475)) ([17ed396](https://github.com/ReVanced/revanced-integrations/commit/17ed39673954a5b571bc1654be20afc235682ca4)) * **YouTube - Hide info cards:** Fix info cards not hiding for some users ([#487](https://github.com/ReVanced/revanced-integrations/issues/487)) ([00c4c40](https://github.com/ReVanced/revanced-integrations/commit/00c4c4025bc27495e490fdb231ac803881c9887f)) * **YouTube - Hide layout components:** Always hide redundant 'player audio track' button ([#473](https://github.com/ReVanced/revanced-integrations/issues/473)) ([d86851b](https://github.com/ReVanced/revanced-integrations/commit/d86851baf1ef1993f5ba9543a4a3fe8d50c3a199)) * **YouTube - Hide layout components:** Do not hide chapters in feed unexpectedly ([bedb02e](https://github.com/ReVanced/revanced-integrations/commit/bedb02e4f6122f3dcdc106648648eec4d6a3cbe5)) * **YouTube - Hide shorts components:** Hide subscribe button in paused state ([9685070](https://github.com/ReVanced/revanced-integrations/commit/9685070eda5b448eb33324b4bfabd4c7eae42f9f)) * **YouTube - ReturnYouTubeDislike:** Add debug logging to litho text ([#476](https://github.com/ReVanced/revanced-integrations/issues/476)) ([e3b8e8b](https://github.com/ReVanced/revanced-integrations/commit/e3b8e8be41796d0300c8421e28e5b8cf43ffb25e)) * **YouTube - ReturnYouTubeDislike:** Revert support for 18.37.36 ([#488](https://github.com/ReVanced/revanced-integrations/issues/488)) ([165b061](https://github.com/ReVanced/revanced-integrations/commit/165b061fa9c5fd48b0dbb9540fd6ea6a9ffaf312)) * **YouTube - SponsorBlock:** Adjust import/export UI text ([#491](https://github.com/ReVanced/revanced-integrations/issues/491)) ([4215be4](https://github.com/ReVanced/revanced-integrations/commit/4215be4250d195ecf89b041c96834be56c164f34)) * **YouTube - Video Id:** Fix video id not showing the currently playing video ([#484](https://github.com/ReVanced/revanced-integrations/issues/484)) ([da923a3](https://github.com/ReVanced/revanced-integrations/commit/da923a38a06baf8c30d38211e8354be4edb0ad51)) * **YouTube:** fix old quality and custom speed not working on tablets ([#477](https://github.com/ReVanced/revanced-integrations/issues/477)) ([2352fa5](https://github.com/ReVanced/revanced-integrations/commit/2352fa542658035c5f4400fb5892217887710e4d)) ### Features * **TU Dortmund:** Add `Show on lockscreen` patch ([#472](https://github.com/ReVanced/revanced-integrations/issues/472)) ([526d66f](https://github.com/ReVanced/revanced-integrations/commit/526d66f6a91e0ed907db609a4adaa97f3239898b)) * **Twitch - Block embedded ads:** Switch from `ttv.lol` to `luminous.dev` ([2c34180](https://github.com/ReVanced/revanced-integrations/commit/2c3418041cf19ae4c1c7b67eda8398578384b753)) * **YouTube - Hide layout components:** Disable hiding search result shelf header by default ([b280de3](https://github.com/ReVanced/revanced-integrations/commit/b280de31957631180f07057cc7e466bd26e2f7fb)) * **YouTube - Hide layout components:** Hide "Join" button ([e225468](https://github.com/ReVanced/revanced-integrations/commit/e2254681cd77481376e4c3f8c556db510fdfce6c)) * **YouTube - Hide layout components:** Hide "Notify me" button ([b87d806](https://github.com/ReVanced/revanced-integrations/commit/b87d8066597a2c989480de47561007844964a0e4)) * **YouTube - Hide layout components:** Hide search result shelf header ([93a3045](https://github.com/ReVanced/revanced-integrations/commit/93a30453d9693e015b1f58a12f85cf355770a4ca)) * **YouTube - Hide layout components:** Hide timed reactions ([b472aee](https://github.com/ReVanced/revanced-integrations/commit/b472aeeed7904f6b6d537dfbddda1a97c7ddcd5e)) * **YouTube:** Add `Bypass URL redirects` patch ([9109653](https://github.com/ReVanced/revanced-integrations/commit/91096532eedf396920d69932638f667cbf850cbe)) * **YouTube:** Bump compatibility to `18.37.36` ([#483](https://github.com/ReVanced/revanced-integrations/issues/483)) ([5dadb0d](https://github.com/ReVanced/revanced-integrations/commit/5dadb0d523f2b1eb4216d43770af37a156c8a477)) ### Performance Improvements * Only request required fields ([d20b768](https://github.com/ReVanced/revanced-integrations/commit/d20b768bc23d167d9f0d2c651c75b3f92944e731)) * Remove unnecessary api key parameter ([ba5e7d8](https://github.com/ReVanced/revanced-integrations/commit/ba5e7d870ee88ad45c233d914e1e2795de920cb2)) --- CHANGELOG.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ gradle.properties | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6657e8bdb6..5e95436597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,50 @@ +# [0.118.0](https://github.com/ReVanced/revanced-integrations/compare/v0.117.1...v0.118.0) (2023-10-04) + + +### Bug Fixes + +* Do not always hide the component ([3d0fc1d](https://github.com/ReVanced/revanced-integrations/commit/3d0fc1d610cdf50bb7cc4687d899e0acbf3fb83e)) +* Remove parameter from route ([4b0925e](https://github.com/ReVanced/revanced-integrations/commit/4b0925e33762c02e95ef9b1aadcae1038af71a50)) +* **YouTube - Client spoof:** Display seekbar thumbnails in high quality ([f71c1a0](https://github.com/ReVanced/revanced-integrations/commit/f71c1a0c156b2320e06dd98b3e5b276560d438aa)) +* **YouTube - Client spoof:** Do not record feed videos to history by default ([#478](https://github.com/ReVanced/revanced-integrations/issues/478)) ([ef1cca0](https://github.com/ReVanced/revanced-integrations/commit/ef1cca02c165d9c24e64b43fae375ae57bf90a52)) +* **YouTube - Client spoof:** fix occasionally frozen video playback ([#486](https://github.com/ReVanced/revanced-integrations/issues/486)) ([b0b6ff6](https://github.com/ReVanced/revanced-integrations/commit/b0b6ff6a82820d4578c5cfc5f69ae7aaaac49c7f)) +* **YouTube - Client spoof:** fix storyboard fetched out of order ([#481](https://github.com/ReVanced/revanced-integrations/issues/481)) ([8398774](https://github.com/ReVanced/revanced-integrations/commit/83987747e67541cd44221ede8c4020baba36c7b8)) +* **YouTube - Client spoof:** Fix toast shown for live streams ([#489](https://github.com/ReVanced/revanced-integrations/issues/489)) ([27f49df](https://github.com/ReVanced/revanced-integrations/commit/27f49dfd1e8fbfd3e28270da91ad437df8a54761)) +* **YouTube - Client spoof:** fix toast shown if opening paid or age restricted video ([#482](https://github.com/ReVanced/revanced-integrations/issues/482)) ([e72b65b](https://github.com/ReVanced/revanced-integrations/commit/e72b65b599353715a6467463226abc603bc850f7)) +* **YouTube - Client spoof:** Removed unused code ([#480](https://github.com/ReVanced/revanced-integrations/issues/480)) ([e6903bf](https://github.com/ReVanced/revanced-integrations/commit/e6903bff95b485d21773537bbcc162411b616618)) +* **YouTube - Client spoof:** Restore clipping videos functionality ([2cd1738](https://github.com/ReVanced/revanced-integrations/commit/2cd1738d2494add13c48b64ccc9aad2432b2d8e3)) +* **YouTube - Client spoof:** Restore seekbar thumbnails ([978f630](https://github.com/ReVanced/revanced-integrations/commit/978f630c0267ec2b0d9bb9b5b0b3cdc9abef65ec)) +* **YouTube - Client spoof:** Show seekbar thumbnail for age restricted and paid videos ([01019b0](https://github.com/ReVanced/revanced-integrations/commit/01019b09c1c106ed814b994dd8af558a18873c1d)) +* **YouTube - Custom filter:** Use new lines between components instead of commas ([#475](https://github.com/ReVanced/revanced-integrations/issues/475)) ([17ed396](https://github.com/ReVanced/revanced-integrations/commit/17ed39673954a5b571bc1654be20afc235682ca4)) +* **YouTube - Hide info cards:** Fix info cards not hiding for some users ([#487](https://github.com/ReVanced/revanced-integrations/issues/487)) ([00c4c40](https://github.com/ReVanced/revanced-integrations/commit/00c4c4025bc27495e490fdb231ac803881c9887f)) +* **YouTube - Hide layout components:** Always hide redundant 'player audio track' button ([#473](https://github.com/ReVanced/revanced-integrations/issues/473)) ([d86851b](https://github.com/ReVanced/revanced-integrations/commit/d86851baf1ef1993f5ba9543a4a3fe8d50c3a199)) +* **YouTube - Hide layout components:** Do not hide chapters in feed unexpectedly ([bedb02e](https://github.com/ReVanced/revanced-integrations/commit/bedb02e4f6122f3dcdc106648648eec4d6a3cbe5)) +* **YouTube - Hide shorts components:** Hide subscribe button in paused state ([9685070](https://github.com/ReVanced/revanced-integrations/commit/9685070eda5b448eb33324b4bfabd4c7eae42f9f)) +* **YouTube - ReturnYouTubeDislike:** Add debug logging to litho text ([#476](https://github.com/ReVanced/revanced-integrations/issues/476)) ([e3b8e8b](https://github.com/ReVanced/revanced-integrations/commit/e3b8e8be41796d0300c8421e28e5b8cf43ffb25e)) +* **YouTube - ReturnYouTubeDislike:** Revert support for 18.37.36 ([#488](https://github.com/ReVanced/revanced-integrations/issues/488)) ([165b061](https://github.com/ReVanced/revanced-integrations/commit/165b061fa9c5fd48b0dbb9540fd6ea6a9ffaf312)) +* **YouTube - SponsorBlock:** Adjust import/export UI text ([#491](https://github.com/ReVanced/revanced-integrations/issues/491)) ([4215be4](https://github.com/ReVanced/revanced-integrations/commit/4215be4250d195ecf89b041c96834be56c164f34)) +* **YouTube - Video Id:** Fix video id not showing the currently playing video ([#484](https://github.com/ReVanced/revanced-integrations/issues/484)) ([da923a3](https://github.com/ReVanced/revanced-integrations/commit/da923a38a06baf8c30d38211e8354be4edb0ad51)) +* **YouTube:** fix old quality and custom speed not working on tablets ([#477](https://github.com/ReVanced/revanced-integrations/issues/477)) ([2352fa5](https://github.com/ReVanced/revanced-integrations/commit/2352fa542658035c5f4400fb5892217887710e4d)) + + +### Features + +* **TU Dortmund:** Add `Show on lockscreen` patch ([#472](https://github.com/ReVanced/revanced-integrations/issues/472)) ([526d66f](https://github.com/ReVanced/revanced-integrations/commit/526d66f6a91e0ed907db609a4adaa97f3239898b)) +* **Twitch - Block embedded ads:** Switch from `ttv.lol` to `luminous.dev` ([2c34180](https://github.com/ReVanced/revanced-integrations/commit/2c3418041cf19ae4c1c7b67eda8398578384b753)) +* **YouTube - Hide layout components:** Disable hiding search result shelf header by default ([b280de3](https://github.com/ReVanced/revanced-integrations/commit/b280de31957631180f07057cc7e466bd26e2f7fb)) +* **YouTube - Hide layout components:** Hide "Join" button ([e225468](https://github.com/ReVanced/revanced-integrations/commit/e2254681cd77481376e4c3f8c556db510fdfce6c)) +* **YouTube - Hide layout components:** Hide "Notify me" button ([b87d806](https://github.com/ReVanced/revanced-integrations/commit/b87d8066597a2c989480de47561007844964a0e4)) +* **YouTube - Hide layout components:** Hide search result shelf header ([93a3045](https://github.com/ReVanced/revanced-integrations/commit/93a30453d9693e015b1f58a12f85cf355770a4ca)) +* **YouTube - Hide layout components:** Hide timed reactions ([b472aee](https://github.com/ReVanced/revanced-integrations/commit/b472aeeed7904f6b6d537dfbddda1a97c7ddcd5e)) +* **YouTube:** Add `Bypass URL redirects` patch ([9109653](https://github.com/ReVanced/revanced-integrations/commit/91096532eedf396920d69932638f667cbf850cbe)) +* **YouTube:** Bump compatibility to `18.37.36` ([#483](https://github.com/ReVanced/revanced-integrations/issues/483)) ([5dadb0d](https://github.com/ReVanced/revanced-integrations/commit/5dadb0d523f2b1eb4216d43770af37a156c8a477)) + + +### Performance Improvements + +* Only request required fields ([d20b768](https://github.com/ReVanced/revanced-integrations/commit/d20b768bc23d167d9f0d2c651c75b3f92944e731)) +* Remove unnecessary api key parameter ([ba5e7d8](https://github.com/ReVanced/revanced-integrations/commit/ba5e7d870ee88ad45c233d914e1e2795de920cb2)) + # [0.118.0-dev.24](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0-dev.23...v0.118.0-dev.24) (2023-10-03) diff --git a/gradle.properties b/gradle.properties index 848e696fac..ce275ea685 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0-dev.24 +version = 0.118.0 From 6730aaf2b864b747a6b77411cdaceee653b36218 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 5 Oct 2023 03:41:52 +0200 Subject: [PATCH 25/53] fix(YouTube - Hide shorts components): Hide the subscribe button when paused --- .../patches/components/ShortsFilter.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index 6b03173b07..a214944726 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -16,6 +16,7 @@ public final class ShortsFilter extends Filter { private final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.eml"; private final StringFilterGroup channelBar; + private final StringFilterGroup subscribeButton; private final StringFilterGroup soundButton; private final StringFilterGroup infoPanel; private final StringFilterGroup shelfHeader; @@ -53,7 +54,8 @@ public ShortsFilter() { SettingsEnum.HIDE_SHORTS_JOIN_BUTTON, "sponsor_button" ); - var subscribeButton = new StringFilterGroup( + + subscribeButton = new StringFilterGroup( SettingsEnum.HIDE_SHORTS_SUBSCRIBE_BUTTON, "subscribe_button", "shorts_paused_state" @@ -63,6 +65,7 @@ public ShortsFilter() { SettingsEnum.HIDE_SHORTS_CHANNEL_BAR, REEL_CHANNEL_BAR_PATH ); + soundButton = new StringFilterGroup( SettingsEnum.HIDE_SHORTS_SOUND_BUTTON, "reel_pivot_button" @@ -105,8 +108,11 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { if (matchedList == pathFilterGroupList) { // Always filter if matched. - if (matchedGroup == soundButton || matchedGroup == infoPanel || matchedGroup == channelBar) - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + if (matchedGroup == soundButton || + matchedGroup == infoPanel || + matchedGroup == channelBar || + matchedGroup == subscribeButton + ) return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); // Video action buttons (comment, share, remix) have the same path. if (matchedGroup == videoActionButton) { From d47fd19d0b99815debe10887be70f746be623661 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 5 Oct 2023 02:44:51 +0000 Subject: [PATCH 26/53] chore(release): 0.118.1-dev.1 [skip ci] ## [0.118.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0...v0.118.1-dev.1) (2023-10-05) ### Bug Fixes * **YouTube - Hide shorts components:** Hide the subscribe button when paused ([6730aaf](https://github.com/ReVanced/revanced-integrations/commit/6730aaf2b864b747a6b77411cdaceee653b36218)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e95436597..c72e6f91dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.118.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0...v0.118.1-dev.1) (2023-10-05) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Hide the subscribe button when paused ([6730aaf](https://github.com/ReVanced/revanced-integrations/commit/6730aaf2b864b747a6b77411cdaceee653b36218)) + # [0.118.0](https://github.com/ReVanced/revanced-integrations/compare/v0.117.1...v0.118.0) (2023-10-04) diff --git a/gradle.properties b/gradle.properties index ce275ea685..9b6f0520eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.0 +version = 0.118.1-dev.1 From 3ac869fa6ae095f074481d98d9a4eea207eda00d Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 5 Oct 2023 18:48:53 +0200 Subject: [PATCH 27/53] feat(YouTube - Hide shorts components): Hide subscribe button when paused separately from subscribe button --- .../integrations/patches/components/ShortsFilter.java | 10 ++++++++-- .../revanced/integrations/settings/SettingsEnum.java | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index a214944726..6315b0b4e1 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -17,6 +17,7 @@ public final class ShortsFilter extends Filter { private final StringFilterGroup channelBar; private final StringFilterGroup subscribeButton; + private final StringFilterGroup subscribeButtonPaused; private final StringFilterGroup soundButton; private final StringFilterGroup infoPanel; private final StringFilterGroup shelfHeader; @@ -57,7 +58,11 @@ public ShortsFilter() { subscribeButton = new StringFilterGroup( SettingsEnum.HIDE_SHORTS_SUBSCRIBE_BUTTON, - "subscribe_button", + "subscribe_button" + ); + + subscribeButtonPaused = new StringFilterGroup( + SettingsEnum.HIDE_SHORTS_SUBSCRIBE_BUTTON_PAUSED, "shorts_paused_state" ); @@ -111,7 +116,8 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff if (matchedGroup == soundButton || matchedGroup == infoPanel || matchedGroup == channelBar || - matchedGroup == subscribeButton + matchedGroup == subscribeButton || + matchedGroup == subscribeButtonPaused ) return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); // Video action buttons (comment, share, remix) have the same path. diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 581f934057..1c7979d1eb 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -136,7 +136,8 @@ public enum SettingsEnum { HIDE_FILTER_BAR_FEED_IN_SEARCH("revanced_hide_filter_bar_feed_in_search", BOOLEAN, FALSE, true), HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS("revanced_hide_filter_bar_feed_in_related_videos", BOOLEAN, FALSE, true), HIDE_SHORTS_JOIN_BUTTON("revanced_hide_shorts_join_button", BOOLEAN, TRUE), - HIDE_SHORTS_SUBSCRIBE_BUTTON("revanced_hide_shorts_subscribe_button", BOOLEAN, FALSE), + HIDE_SHORTS_SUBSCRIBE_BUTTON("revanced_hide_shorts_subscribe_button", BOOLEAN, TRUE), + HIDE_SHORTS_SUBSCRIBE_BUTTON_PAUSED("revanced_hide_shorts_subscribe_button_paused", BOOLEAN, FALSE), HIDE_SHORTS_THANKS_BUTTON("revanced_hide_shorts_thanks_button", BOOLEAN, TRUE), HIDE_SHORTS_COMMENTS_BUTTON("revanced_hide_shorts_comments_button", BOOLEAN, FALSE), HIDE_SHORTS_REMIX_BUTTON("revanced_hide_shorts_remix_button", BOOLEAN, TRUE), From ed6571734eb049e0e57256bc89acbcdc627b97a6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 5 Oct 2023 16:53:23 +0000 Subject: [PATCH 28/53] chore(release): 0.119.0-dev.1 [skip ci] # [0.119.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.118.1-dev.1...v0.119.0-dev.1) (2023-10-05) ### Features * **YouTube - Hide shorts components:** Hide subscribe button when paused separately from subscribe button ([3ac869f](https://github.com/ReVanced/revanced-integrations/commit/3ac869fa6ae095f074481d98d9a4eea207eda00d)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c72e6f91dd..3ab15c14e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.119.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.118.1-dev.1...v0.119.0-dev.1) (2023-10-05) + + +### Features + +* **YouTube - Hide shorts components:** Hide subscribe button when paused separately from subscribe button ([3ac869f](https://github.com/ReVanced/revanced-integrations/commit/3ac869fa6ae095f074481d98d9a4eea207eda00d)) + ## [0.118.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0...v0.118.1-dev.1) (2023-10-05) diff --git a/gradle.properties b/gradle.properties index 9b6f0520eb..d3a353e082 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.118.1-dev.1 +version = 0.119.0-dev.1 From 6eb301776e202cf1d923f96cc83ddf6f0430b211 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 6 Oct 2023 02:36:27 +0200 Subject: [PATCH 29/53] fix(YouTube - Hide shorts components): Do not prevent filtering components Previously, the exceptions group prevented filtering the "Notify me" button and in feed surveys. --- .../patches/components/LayoutComponentsFilter.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index 39be57c924..4ee419d38d 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -20,14 +20,16 @@ public final class LayoutComponentsFilter extends Filter { "&list=" ); private final StringFilterGroup searchResultShelfHeader; + private final StringFilterGroup inFeedSurvey; + private final StringFilterGroup notifyMe; @RequiresApi(api = Build.VERSION_CODES.N) public LayoutComponentsFilter() { exceptions.addPatterns( "home_video_with_context", "related_video_with_context", - "comment_thread", // skip filtering anything in the comments - "|comment.", // skip filtering anything in the comments replies + "comment_thread", // Whitelist comments + "|comment.", // Whitelist comment replies "library_recent_shelf" ); @@ -62,7 +64,7 @@ public LayoutComponentsFilter() { "compact_banner" ); - final var inFeedSurvey = new StringFilterGroup( + inFeedSurvey = new StringFilterGroup( SettingsEnum.HIDE_FEED_SURVEY, "in_feed_survey", "slimline_survey" @@ -158,7 +160,7 @@ public LayoutComponentsFilter() { "shelf_header.eml" ); - final var notifyMe = new StringFilterGroup( + notifyMe = new StringFilterGroup( SettingsEnum.HIDE_NOTIFY_ME_BUTTON, "set_reminder_button" ); @@ -208,6 +210,9 @@ public LayoutComponentsFilter() { @Override public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + + if (matchedGroup == notifyMe || matchedGroup == inFeedSurvey) return true; + if (matchedGroup != custom && exceptions.matches(path)) return false; // Exceptions are not filtered. From 1d13cf2d5d5f80ba774f81e043ff6af1ecd1ff52 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 6 Oct 2023 00:40:20 +0000 Subject: [PATCH 30/53] chore(release): 0.119.0-dev.2 [skip ci] # [0.119.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.1...v0.119.0-dev.2) (2023-10-06) ### Bug Fixes * **YouTube - Hide shorts components:** Do not prevent filtering components ([6eb3017](https://github.com/ReVanced/revanced-integrations/commit/6eb301776e202cf1d923f96cc83ddf6f0430b211)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ab15c14e3..d2575ec968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.119.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.1...v0.119.0-dev.2) (2023-10-06) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Do not prevent filtering components ([6eb3017](https://github.com/ReVanced/revanced-integrations/commit/6eb301776e202cf1d923f96cc83ddf6f0430b211)) + # [0.119.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.118.1-dev.1...v0.119.0-dev.1) (2023-10-05) diff --git a/gradle.properties b/gradle.properties index d3a353e082..1408765acc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0-dev.1 +version = 0.119.0-dev.2 From 30788ba1a3e8d666b55a37e9389246e4bfa039cb Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 6 Oct 2023 12:37:50 +0200 Subject: [PATCH 31/53] fix(YouTube - Hide shorts components): Add filter to filter group list --- .../revanced/integrations/patches/components/ShortsFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index 6315b0b4e1..a5602476f3 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -87,7 +87,8 @@ public ShortsFilter() { ); pathFilterGroupList.addAll( - joinButton, subscribeButton, channelBar, soundButton, infoPanel, videoActionButton + joinButton, subscribeButton, subscribeButtonPaused, + channelBar, soundButton, infoPanel, videoActionButton ); var shortsCommentButton = new ByteArrayAsStringFilterGroup( From 176196b52c4deaa6bfcd8616fe95f956022bd9a0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 6 Oct 2023 10:42:02 +0000 Subject: [PATCH 32/53] chore(release): 0.119.0-dev.3 [skip ci] # [0.119.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.2...v0.119.0-dev.3) (2023-10-06) ### Bug Fixes * **YouTube - Hide shorts components:** Add filter to filter group list ([30788ba](https://github.com/ReVanced/revanced-integrations/commit/30788ba1a3e8d666b55a37e9389246e4bfa039cb)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2575ec968..9d45d95591 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.119.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.2...v0.119.0-dev.3) (2023-10-06) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Add filter to filter group list ([30788ba](https://github.com/ReVanced/revanced-integrations/commit/30788ba1a3e8d666b55a37e9389246e4bfa039cb)) + # [0.119.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.1...v0.119.0-dev.2) (2023-10-06) diff --git a/gradle.properties b/gradle.properties index 1408765acc..83d5dca87f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0-dev.2 +version = 0.119.0-dev.3 From 4498f39b8c4900fccdc359d0c687c26db23526c3 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 7 Oct 2023 03:50:41 +0200 Subject: [PATCH 33/53] feat(YouTube): Add `Disable fine scrubbing gesture` patch --- .../DisableFineScrubbingGesturePatch.java | 18 ++++++++++++++++++ .../integrations/settings/SettingsEnum.java | 1 + 2 files changed, 19 insertions(+) create mode 100644 app/src/main/java/app/revanced/integrations/patches/DisableFineScrubbingGesturePatch.java diff --git a/app/src/main/java/app/revanced/integrations/patches/DisableFineScrubbingGesturePatch.java b/app/src/main/java/app/revanced/integrations/patches/DisableFineScrubbingGesturePatch.java new file mode 100644 index 0000000000..72a6859065 --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/patches/DisableFineScrubbingGesturePatch.java @@ -0,0 +1,18 @@ +package app.revanced.integrations.patches; + +import android.view.MotionEvent; +import android.view.VelocityTracker; +import app.revanced.integrations.settings.SettingsEnum; + +public final class DisableFineScrubbingGesturePatch { + /** + * Disables the fine scrubbing gesture. + * @param tracker The velocity tracker that is used to determine the gesture. + * @param event The motion event that is used to determine the gesture. + */ + public static void disableGesture(VelocityTracker tracker, MotionEvent event) { + if (SettingsEnum.DISABLE_FINE_SCRUBBING_GESTURE.getBoolean()) return; + + tracker.addMovement(event); + } +} diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 1c7979d1eb..3affe38447 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -170,6 +170,7 @@ public enum SettingsEnum { EXTERNAL_BROWSER("revanced_external_browser", BOOLEAN, TRUE, true), AUTO_REPEAT("revanced_auto_repeat", BOOLEAN, FALSE), SEEKBAR_TAPPING("revanced_seekbar_tapping", BOOLEAN, TRUE), + DISABLE_FINE_SCRUBBING_GESTURE("revanced_disable_fine_scrubbing_gesture", BOOLEAN, TRUE), SPOOF_SIGNATURE("revanced_spoof_signature_verification_enabled", BOOLEAN, TRUE, true, "revanced_spoof_signature_verification_enabled_user_dialog_message"), SPOOF_SIGNATURE_IN_FEED("revanced_spoof_signature_in_feed_enabled", BOOLEAN, FALSE, false, From d4b859d6fb7a8a2713fb92bfe885ca34829ef7af Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 7 Oct 2023 01:54:40 +0000 Subject: [PATCH 34/53] chore(release): 0.119.0-dev.4 [skip ci] # [0.119.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.3...v0.119.0-dev.4) (2023-10-07) ### Features * **YouTube:** Add `Disable fine scrubbing gesture` patch ([4498f39](https://github.com/ReVanced/revanced-integrations/commit/4498f39b8c4900fccdc359d0c687c26db23526c3)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d45d95591..41d66863a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.119.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.3...v0.119.0-dev.4) (2023-10-07) + + +### Features + +* **YouTube:** Add `Disable fine scrubbing gesture` patch ([4498f39](https://github.com/ReVanced/revanced-integrations/commit/4498f39b8c4900fccdc359d0c687c26db23526c3)) + # [0.119.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.2...v0.119.0-dev.3) (2023-10-06) diff --git a/gradle.properties b/gradle.properties index 83d5dca87f..a5fba830f5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0-dev.3 +version = 0.119.0-dev.4 From 245c3b35373313d49cc5b1c2fd8e9deebb6258a5 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 7 Oct 2023 11:31:25 +0200 Subject: [PATCH 35/53] feat(YouTube - Return YouTube Dislike): Support version `18.37.36` (#490) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> --- .../patches/ReturnYouTubeDislikePatch.java | 216 +++++- .../patches/components/LithoFilterPatch.java | 74 +- .../ReturnYouTubeDislikeFilterPatch.java | 76 +++ .../ReturnYouTubeDislike.java | 638 ++++++++---------- .../requests/RYDVoteData.java | 28 +- .../requests/ReturnYouTubeDislikeApi.java | 28 +- .../ReturnYouTubeDislikeSettingsFragment.java | 7 +- .../integrations/utils/ReVancedUtils.java | 14 +- .../integrations/utils/TrieSearch.java | 9 +- 9 files changed, 661 insertions(+), 429 deletions(-) create mode 100644 app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 2c3b3d0fe1..1dd5fb5347 100644 --- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -7,9 +7,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; + +import app.revanced.integrations.patches.components.ReturnYouTubeDislikeFilterPatch; import app.revanced.integrations.patches.spoof.SpoofAppVersionPatch; import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; -import app.revanced.integrations.returnyoutubedislike.requests.ReturnYouTubeDislikeApi; import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.shared.PlayerType; import app.revanced.integrations.utils.LogHelper; @@ -24,14 +25,50 @@ /** * Handles all interaction of UI patch components. - * - * Does not handle creating dislike spans or anything to do with {@link ReturnYouTubeDislikeApi}. */ public class ReturnYouTubeDislikePatch { + /** + * RYD data for the current video on screen. + */ + @Nullable + private static volatile ReturnYouTubeDislike currentVideoData; + + /** + * The last litho based Shorts loaded. + * May be the same value as {@link #currentVideoData}, but usually is the next short to swipe to. + */ @Nullable - private static String currentVideoId; + private static volatile ReturnYouTubeDislike lastLithoShortsVideoData; + + /** + * Because the litho Shorts spans are created after {@link ReturnYouTubeDislikeFilterPatch} + * detects the video ids, after the user votes the litho will update + * but {@link #lastLithoShortsVideoData} is not the correct data to use. + * If this is true, then instead use {@link #currentVideoData}. + */ + private static volatile boolean lithoShortsShouldUseCurrentData; + + /** + * Last video id prefetched. Field is prevent prefetching the same video id multiple times in a row. + */ + @Nullable + private static volatile String lastPrefetchedVideoId; + + public static void onRYDStatusChange(boolean rydEnabled) { + if (!rydEnabled) { + // Must remove all values to protect against using stale data + // if the user enables RYD while a video is on screen. + currentVideoData = null; + lastLithoShortsVideoData = null; + lithoShortsShouldUseCurrentData = false; + } + } + + // + // 17.x non litho regular video player. + // /** * Resource identifier of old UI dislike button. @@ -76,11 +113,15 @@ public void afterTextChanged(Editable s) { }; private static void updateOldUIDislikesTextView() { + ReturnYouTubeDislike videoData = currentVideoData; + if (videoData == null) { + return; + } TextView oldUITextView = oldUITextViewRef.get(); if (oldUITextView == null) { return; } - oldUIReplacementSpan = ReturnYouTubeDislike.getDislikesSpanForRegularVideo(oldUIOriginalSpan, false); + oldUIReplacementSpan = videoData.getDislikesSpanForRegularVideo(oldUIOriginalSpan, false); if (!oldUIReplacementSpan.equals(oldUITextView.getText())) { oldUITextView.setText(oldUIReplacementSpan); } @@ -124,6 +165,10 @@ public static void setOldUILayoutDislikes(int buttonViewResourceId, @Nullable Te } + // + // Litho player for both regular videos and Shorts. + // + /** * Injection point. * @@ -144,23 +189,56 @@ public static CharSequence onLithoTextLoaded(@NonNull Object conversionContext, @NonNull AtomicReference textRef, @NonNull CharSequence original) { try { - if (!SettingsEnum.RYD_ENABLED.getBoolean() || PlayerType.getCurrent().isNoneOrHidden()) { + if (!SettingsEnum.RYD_ENABLED.getBoolean()) { return original; } String conversionContextString = conversionContext.toString(); + // Remove this log statement after the a/b new litho dislikes is fixed. LogHelper.printDebug(() -> "conversionContext: " + conversionContextString); - final boolean isSegmentedButton; + final Spanned replacement; if (conversionContextString.contains("|segmented_like_dislike_button.eml|")) { - isSegmentedButton = true; - } else if (conversionContextString.contains("|dislike_button.eml|")) { - isSegmentedButton = false; + // Regular video + ReturnYouTubeDislike videoData = currentVideoData; + if (videoData == null) { + return original; // User enabled RYD while a video was on screen. + } + replacement = videoData.getDislikesSpanForRegularVideo((Spannable) original, true); + // When spoofing between 17.09.xx and 17.30.xx the UI is the old layout but uses litho + // and the dislikes is "|dislike_button.eml|" + // but spoofing to that range gives a broken UI layout so no point checking for that. + } else if (conversionContextString.contains("|shorts_dislike_button.eml|")) { + // Litho Shorts player. + if (!SettingsEnum.RYD_SHORTS.getBoolean()) { + // Must clear the current video here, otherwise if the user opens a regular video + // then opens a litho short (while keeping the regular video on screen), then closes the short, + // the original video may show the incorrect dislike value. + currentVideoData = null; + return original; + } + ReturnYouTubeDislike videoData = lastLithoShortsVideoData; + if (videoData == null) { + // Should not happen, as user cannot turn on RYD while leaving a short on screen. + // If this does happen, then the litho video id filter did not detect the video id. + LogHelper.printDebug(() -> "Error: Litho video data is null, but it should not be"); + return original; + } + // Use the correct dislikes data after voting. + if (lithoShortsShouldUseCurrentData) { + lithoShortsShouldUseCurrentData = false; + videoData = currentVideoData; + if (videoData == null) { + LogHelper.printException(() -> "currentVideoData is null"); // Should never happen + return original; + } + LogHelper.printDebug(() -> "Using current video data for litho span"); + } + replacement = videoData.getDislikeSpanForShort((Spannable) original); } else { return original; } - Spanned replacement = ReturnYouTubeDislike.getDislikesSpanForRegularVideo((Spannable) original, isSegmentedButton); textRef.set(replacement); return replacement; } catch (Exception ex) { @@ -170,6 +248,10 @@ public static CharSequence onLithoTextLoaded(@NonNull Object conversionContext, } + // + // Non litho Shorts player. + // + /** * Replacement text to use for "Dislikes" while RYD is fetching. */ @@ -184,18 +266,16 @@ public static CharSequence onLithoTextLoaded(@NonNull Object conversionContext, private static final List> shortsTextViewRefs = new ArrayList<>(); private static void clearRemovedShortsTextViews() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // YouTube requires Android N or greater shortsTextViewRefs.removeIf(ref -> ref.get() == null); - return; } - throw new IllegalStateException(); // YouTube requires Android N or greater } /** - * Injection point. Called when a Shorts dislike is updated. + * Injection point. Called when a Shorts dislike is updated. Always on main thread. * Handles update asynchronously, otherwise Shorts video will be frozen while the UI thread is blocked. * - * @return if RYD is enabled and the TextView was updated + * @return if RYD is enabled and the TextView was updated. */ public static boolean setShortsDislikes(@NonNull View likeDislikeView) { try { @@ -205,21 +285,22 @@ public static boolean setShortsDislikes(@NonNull View likeDislikeView) { if (!SettingsEnum.RYD_SHORTS.getBoolean()) { // Must clear the data here, in case a new video was loaded while PlayerType // suggested the video was not a short (can happen when spoofing to an old app version). - ReturnYouTubeDislike.setCurrentVideoId(null); + currentVideoData = null; return false; } LogHelper.printDebug(() -> "setShortsDislikes"); TextView textView = (TextView) likeDislikeView; - textView.setText(SHORTS_LOADING_SPAN); // Change 'Dislike' text to the loading text + textView.setText(SHORTS_LOADING_SPAN); // Change 'Dislike' text to the loading text. shortsTextViewRefs.add(new WeakReference<>(textView)); if (likeDislikeView.isSelected() && isShortTextViewOnScreen(textView)) { LogHelper.printDebug(() -> "Shorts dislike is already selected"); - ReturnYouTubeDislike.setUserVote(Vote.DISLIKE); + ReturnYouTubeDislike videoData = currentVideoData; + if (videoData != null) videoData.setUserVote(Vote.DISLIKE); } - // For the first short played, the shorts dislike hook is called after the video id hook. + // For the first short played, the Shorts dislike hook is called after the video id hook. // But for most other times this hook is called before the video id (which is not ideal). // Must update the TextViews here, and also after the videoId changes. updateOnScreenShortsTextViews(false); @@ -241,13 +322,17 @@ private static void updateOnScreenShortsTextViews(boolean forceUpdate) { if (shortsTextViewRefs.isEmpty()) { return; } + ReturnYouTubeDislike videoData = currentVideoData; + if (videoData == null) { + return; + } LogHelper.printDebug(() -> "updateShortsTextViews"); - String videoId = VideoInformation.getVideoId(); Runnable update = () -> { - Spanned shortsDislikesSpan = ReturnYouTubeDislike.getDislikeSpanForShort(SHORTS_LOADING_SPAN); + Spanned shortsDislikesSpan = videoData.getDislikeSpanForShort(SHORTS_LOADING_SPAN); ReVancedUtils.runOnMainThreadNowOrLater(() -> { + String videoId = videoData.getVideoId(); if (!videoId.equals(VideoInformation.getVideoId())) { // User swiped to new video before fetch completed LogHelper.printDebug(() -> "Ignoring stale dislikes data for short: " + videoId); @@ -271,13 +356,13 @@ private static void updateOnScreenShortsTextViews(boolean forceUpdate) { } }); }; - if (ReturnYouTubeDislike.fetchCompleted()) { + if (videoData.fetchCompleted()) { update.run(); // Network call is completed, no need to wait on background thread. } else { ReVancedUtils.runOnBackgroundThread(update); } } catch (Exception ex) { - LogHelper.printException(() -> "updateVisibleShortsTextViews failure", ex); + LogHelper.printException(() -> "updateOnScreenShortsTextViews failure", ex); } } @@ -295,35 +380,85 @@ private static boolean isShortTextViewOnScreen(@NonNull View view) { return location[0] < windowRect.width() && location[1] < windowRect.height(); } + + // + // Video Id and voting hooks (all players). + // + /** - * Injection point. + * Injection point. Uses 'playback response' video id hook to preload RYD. + */ + public static void preloadVideoId(@NonNull String videoId) { + if (!SettingsEnum.RYD_ENABLED.getBoolean()) { + return; + } + if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneOrHidden()) { + return; + } + if (videoId.equals(lastPrefetchedVideoId)) { + return; + } + lastPrefetchedVideoId = videoId; + LogHelper.printDebug(() -> "Prefetching RYD for video: " + videoId); + ReturnYouTubeDislike.getFetchForVideoId(videoId); + } + + /** + * Injection point. Uses 'current playing' video id hook. Always called on main thread. */ public static void newVideoLoaded(@NonNull String videoId) { + newVideoLoaded(videoId, false); + } + + /** + * Called both on and off main thread. + * + * @param isShortsLithoVideoId If the video id is from {@link ReturnYouTubeDislikeFilterPatch}. + */ + public static void newVideoLoaded(@NonNull String videoId, boolean isShortsLithoVideoId) { try { if (!SettingsEnum.RYD_ENABLED.getBoolean()) return; - if (!videoId.equals(currentVideoId)) { - currentVideoId = videoId; + PlayerType currentPlayerType = PlayerType.getCurrent(); + final boolean isNoneOrHidden = currentPlayerType.isNoneOrHidden(); + if (isNoneOrHidden && !SettingsEnum.RYD_SHORTS.getBoolean()) { + return; + } - final boolean noneHiddenOrMinimized = PlayerType.getCurrent().isNoneOrHidden(); - if (noneHiddenOrMinimized && !SettingsEnum.RYD_SHORTS.getBoolean()) { - ReturnYouTubeDislike.setCurrentVideoId(null); + if (isShortsLithoVideoId) { + // Litho Shorts video. + if (videoIdIsSame(lastLithoShortsVideoData, videoId)) { + return; + } + ReturnYouTubeDislike videoData = ReturnYouTubeDislike.getFetchForVideoId(videoId); + videoData.setVideoIdIsShort(true); + lastLithoShortsVideoData = videoData; + lithoShortsShouldUseCurrentData = false; + } else { + if (videoIdIsSame(currentVideoData, videoId)) { return; } + // All other playback (including litho Shorts). + currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId); + } - ReturnYouTubeDislike.newVideoLoaded(videoId); + LogHelper.printDebug(() -> "New video id: " + videoId + " playerType: " + currentPlayerType + + " isShortsLithoHook: " + isShortsLithoVideoId); - if (noneHiddenOrMinimized) { - // Shorts TextView hook can be called out of order with the video id hook. - // Must manually update again here. - updateOnScreenShortsTextViews(true); - } + if (isNoneOrHidden) { + // Current video id hook can be called out of order with the non litho Shorts text view hook. + // Must manually update again here. + updateOnScreenShortsTextViews(true); } } catch (Exception ex) { LogHelper.printException(() -> "newVideoLoaded failure", ex); } } + private static boolean videoIdIsSame(@Nullable ReturnYouTubeDislike fetch, String videoId) { + return fetch != null && fetch.getVideoId().equals(videoId); + } + /** * Injection point. * @@ -339,11 +474,18 @@ public static void sendVote(int vote) { if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneHiddenOrMinimized()) { return; } + ReturnYouTubeDislike videoData = currentVideoData; + if (videoData == null) { + return; // User enabled RYD while a regular video was minimized. + } for (Vote v : Vote.values()) { if (v.value == vote) { - ReturnYouTubeDislike.sendVote(v); + videoData.sendVote(v); + if (lastLithoShortsVideoData != null) { + lithoShortsShouldUseCurrentData = true; + } updateOldUIDislikesTextView(); return; } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index 7cfe060b1d..5099a4df28 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; + import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.*; @@ -13,12 +14,24 @@ abstract class FilterGroup { final static class FilterGroupResult { - SettingsEnum setting; - boolean filtered; + private SettingsEnum setting; + private int matchedIndex; + private int matchedLength; + // In the future it might be useful to include which pattern matched, + // but for now that is not needed. + + FilterGroupResult() { + this(null, -1, 0); + } - FilterGroupResult(SettingsEnum setting, boolean filtered) { + FilterGroupResult(SettingsEnum setting, int matchedIndex, int matchedLength) { + setValues(setting, matchedIndex, matchedLength); + } + + public void setValues(SettingsEnum setting, int matchedIndex, int matchedLength) { this.setting = setting; - this.filtered = filtered; + this.matchedIndex = matchedIndex; + this.matchedLength = matchedLength; } /** @@ -30,7 +43,21 @@ public SettingsEnum getSetting() { } public boolean isFiltered() { - return filtered; + return matchedIndex >= 0; + } + + /** + * Matched index of first pattern that matched, or -1 if nothing matched. + */ + public int getMatchedIndex() { + return matchedIndex; + } + + /** + * Length of the matched filter pattern. + */ + public int getMatchedLength() { + return matchedLength; } } @@ -81,7 +108,21 @@ public StringFilterGroup(final SettingsEnum setting, final String... filters) { @Override public FilterGroupResult check(final String string) { - return new FilterGroupResult(setting, isEnabled() && ReVancedUtils.containsAny(string, filters)); + int matchedIndex = -1; + int matchedLength = 0; + if (isEnabled()) { + for (String pattern : filters) { + if (!string.isEmpty()) { + final int indexOf = pattern.indexOf(string); + if (indexOf >= 0) { + matchedIndex = indexOf; + matchedLength = pattern.length(); + break; + } + } + } + } + return new FilterGroupResult(setting, matchedIndex, matchedLength); } } @@ -155,19 +196,22 @@ private synchronized void buildFailurePatterns() { @Override public FilterGroupResult check(final byte[] bytes) { - var matched = false; + int matchedLength = 0; + int matchedIndex = -1; if (isEnabled()) { if (failurePatterns == null) { buildFailurePatterns(); // Lazy load. } for (int i = 0, length = filters.length; i < length; i++) { - if (indexOf(bytes, filters[i], failurePatterns[i]) >= 0) { - matched = true; + byte[] filter = filters[i]; + matchedIndex = indexOf(bytes, filter, failurePatterns[i]); + if (matchedIndex >= 0) { + matchedLength = filter.length; break; } } } - return new FilterGroupResult(setting, matched); + return new FilterGroupResult(setting, matchedIndex, matchedLength); } } @@ -204,11 +248,10 @@ protected final synchronized void buildSearch() { continue; } for (V pattern : group.filters) { - search.addPattern(pattern, (textSearched, matchedStartIndex, callbackParameter) -> { + search.addPattern(pattern, (textSearched, matchedStartIndex, matchedLength, callbackParameter) -> { if (group.isEnabled()) { FilterGroup.FilterGroupResult result = (FilterGroup.FilterGroupResult) callbackParameter; - result.setting = group.setting; - result.filtered = true; + result.setValues(group.setting, matchedStartIndex, matchedLength); return true; } return false; @@ -241,9 +284,10 @@ protected FilterGroup.FilterGroupResult check(V stack) { if (search == null) { buildSearch(); // Lazy load. } - FilterGroup.FilterGroupResult result = new FilterGroup.FilterGroupResult(null, false); + FilterGroup.FilterGroupResult result = new FilterGroup.FilterGroupResult(); search.matches(stack, result); return result; + } protected abstract TrieSearch createSearchGraph(); @@ -399,7 +443,7 @@ private static void filterGroupLists(TrieSearch pathSearchTree, continue; } for (T pattern : group.filters) { - pathSearchTree.addPattern(pattern, (textSearched, matchedStartIndex, callbackParameter) -> { + pathSearchTree.addPattern(pattern, (textSearched, matchedStartIndex, matchedLength, callbackParameter) -> { if (!group.isEnabled()) return false; LithoFilterParameters parameters = (LithoFilterParameters) callbackParameter; return filter.isFiltered(parameters.identifier, parameters.path, parameters.protoBuffer, diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java new file mode 100644 index 0000000000..54d068ad45 --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java @@ -0,0 +1,76 @@ +package app.revanced.integrations.patches.components; + +import android.os.Build; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import java.nio.charset.StandardCharsets; + +import app.revanced.integrations.patches.ReturnYouTubeDislikePatch; +import app.revanced.integrations.settings.SettingsEnum; + +@RequiresApi(api = Build.VERSION_CODES.N) +public final class ReturnYouTubeDislikeFilterPatch extends Filter { + + private final ByteArrayFilterGroupList videoIdFilterGroup = new ByteArrayFilterGroupList(); + + public ReturnYouTubeDislikeFilterPatch() { + pathFilterGroupList.addAll( + new StringFilterGroup(SettingsEnum.RYD_SHORTS, "|shorts_dislike_button.eml|") + ); + // After the dislikes icon name is some binary data and then the video id for that specific short. + videoIdFilterGroup.addAll( + // Video was previously disliked before video was opened. + new ByteArrayAsStringFilterGroup(null, "ic_right_dislike_on_shadowed"), + // Video was not already disliked. + new ByteArrayAsStringFilterGroup(null, "ic_right_dislike_off_shadowed") + ); + } + + @Override + public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, + FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + FilterGroup.FilterGroupResult result = videoIdFilterGroup.check(protobufBufferArray); + if (result.isFiltered()) { + // The video length must be hard coded to 11, as there is additional ASCII text that + // appears immediately after the id if the dislike button is already selected. + final int videoIdLength = 11; + final int subStringSearchStartIndex = result.getMatchedIndex() + result.getMatchedLength(); + String videoId = findSubString(protobufBufferArray, subStringSearchStartIndex, videoIdLength); + if (videoId != null) { + ReturnYouTubeDislikePatch.newVideoLoaded(videoId, true); + } + } + + return false; + } + + /** + * Find an exact length ASCII substring starting from a given index. + * + * Similar to the String finding code in {@link LithoFilterPatch}, + * but refactoring it to also handle this use case became messy and overly complicated. + */ + @Nullable + private static String findSubString(byte[] buffer, int bufferStartIndex, int subStringLength) { + // Valid ASCII values (ignore control characters). + final int minimumAscii = 32; // 32 = space character + final int maximumAscii = 126; // 127 = delete character + + final int bufferLength = buffer.length; + int start = bufferStartIndex; + int end = bufferStartIndex; + do { + final int value = buffer[end]; + if (value < minimumAscii || value > maximumAscii) { + start = end + 1; + } else if (end - start == subStringLength) { + return new String(buffer, start, subStringLength, StandardCharsets.US_ASCII); + } + end++; + } while (end < bufferLength); + + return null; + } +} diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java index 21f72b9d39..d68d0c1edc 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java @@ -45,40 +45,21 @@ import app.revanced.integrations.utils.ThemeHelper; /** + * Handles fetching and creation/replacing of RYD dislike text spans. + * * Because Litho creates spans using multiple threads, this entire class supports multithreading as well. */ public class ReturnYouTubeDislike { - /** - * Simple wrapper to cache a Future. - */ - private static class RYDCachedFetch { - /** - * How long to retain cached RYD fetches. - */ - static final long CACHE_TIMEOUT_MILLISECONDS = 4 * 60 * 1000; // 4 Minutes - - @NonNull - final Future future; - final String videoId; - final long timeFetched; - RYDCachedFetch(@NonNull Future future, @NonNull String videoId) { - this.future = Objects.requireNonNull(future); - this.videoId = Objects.requireNonNull(videoId); - this.timeFetched = System.currentTimeMillis(); - } + public enum Vote { + LIKE(1), + DISLIKE(-1), + LIKE_REMOVE(0); - boolean isExpired(long now) { - return (now - timeFetched) > CACHE_TIMEOUT_MILLISECONDS; - } + public final int value; - boolean futureInProgressOrFinishedSuccessfully() { - try { - return !future.isDone() || future.get(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH, TimeUnit.MILLISECONDS) != null; - } catch (ExecutionException | InterruptedException | TimeoutException ex) { - LogHelper.printInfo(() -> "failed to lookup cache", ex); // will never happen - } - return false; + Vote(int value) { + this.value = value; } } @@ -90,6 +71,11 @@ boolean futureInProgressOrFinishedSuccessfully() { */ private static final long MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH = 4000; + /** + * How long to retain cached RYD fetches. + */ + private static final long CACHE_TIMEOUT_MILLISECONDS = 5 * 60 * 1000; // 5 Minutes + /** * Unique placeholder character, used to detect if a segmented span already has dislikes added to it. * Can be any almost any non-visible character. @@ -97,59 +83,16 @@ boolean futureInProgressOrFinishedSuccessfully() { private static final char MIDDLE_SEPARATOR_CHARACTER = '\u2009'; // 'narrow space' character /** - * Cached lookup of RYD fetches. + * Cached lookup of all video ids. */ - @GuardedBy("videoIdLockObject") - private static final Map futureCache = new HashMap<>(); + @GuardedBy("itself") + private static final Map fetchCache = new HashMap<>(); /** * Used to send votes, one by one, in the same order the user created them. */ private static final ExecutorService voteSerialExecutor = Executors.newSingleThreadExecutor(); - /** - * Used to guard {@link #currentVideoId} and {@link #voteFetchFuture}. - */ - private static final Object videoIdLockObject = new Object(); - - @Nullable - @GuardedBy("videoIdLockObject") - private static String currentVideoId; - - /** - * If {@link #currentVideoId} and the RYD data is for the last shorts loaded. - */ - private static volatile boolean dislikeDataIsShort; - - /** - * Stores the results of the vote api fetch, and used as a barrier to wait until fetch completes. - */ - @Nullable - @GuardedBy("videoIdLockObject") - private static Future voteFetchFuture; - - /** - * Optional current vote status of the UI. Used to apply a user vote that was done on a previous video viewing. - */ - @Nullable - @GuardedBy("videoIdLockObject") - private static Vote userVote; - - /** - * Original dislike span, before modifications. - */ - @Nullable - @GuardedBy("videoIdLockObject") - private static Spanned originalDislikeSpan; - - /** - * Replacement like/dislike span that includes formatted dislikes. - * Used to prevent recreating the same span multiple times. - */ - @Nullable - @GuardedBy("videoIdLockObject") - private static SpannableString replacementLikeDislikeSpan; - /** * For formatting dislikes as number. */ @@ -162,298 +105,65 @@ boolean futureInProgressOrFinishedSuccessfully() { @GuardedBy("ReturnYouTubeDislike.class") private static NumberFormat dislikePercentageFormatter; - public enum Vote { - LIKE(1), - DISLIKE(-1), - LIKE_REMOVE(0); - - public final int value; + // Used for segmented dislike spans in Litho regular player. + private static final Rect leftSeparatorBounds; + private static final Rect middleSeparatorBounds; - Vote(int value) { - this.value = value; - } - } - - private ReturnYouTubeDislike() { - } // only static methods + static { + DisplayMetrics dp = Objects.requireNonNull(ReVancedUtils.getContext()).getResources().getDisplayMetrics(); - public static void onEnabledChange(boolean enabled) { - if (!enabled) { - // Must clear old values, to protect against using stale data - // if the user re-enables RYD while watching a video. - setCurrentVideoId(null); - } + leftSeparatorBounds = new Rect(0, 0, + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.2f, dp), + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18, dp)); + final int middleSeparatorSize = + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp); + middleSeparatorBounds = new Rect(0, 0, middleSeparatorSize, middleSeparatorSize); } - public static void setCurrentVideoId(@Nullable String videoId) { - synchronized (videoIdLockObject) { - if (videoId == null && currentVideoId != null) { - LogHelper.printDebug(() -> "Clearing data"); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - final long now = System.currentTimeMillis(); - futureCache.values().removeIf(value -> { - final boolean expired = value.isExpired(now); - if (expired) LogHelper.printDebug(() -> "Removing expired fetch: " + value.videoId); - return expired; - }); - } else { - throw new IllegalStateException(); // YouTube requires Android N or greater - } - currentVideoId = videoId; - dislikeDataIsShort = false; - userVote = null; - voteFetchFuture = null; - originalDislikeSpan = null; - replacementLikeDislikeSpan = null; - } - } + private final String videoId; /** - * Should be called after a user dislikes, or if the user changes settings for dislikes appearance. + * Stores the results of the vote api fetch, and used as a barrier to wait until fetch completes. + * Absolutely cannot be holding any lock during calls to {@link Future#get()}. */ - public static void clearCache() { - synchronized (videoIdLockObject) { - if (replacementLikeDislikeSpan != null) { - LogHelper.printDebug(() -> "Clearing replacement spans"); - } - replacementLikeDislikeSpan = null; - } - } - - @Nullable - private static String getCurrentVideoId() { - synchronized (videoIdLockObject) { - return currentVideoId; - } - } - - @Nullable - private static Future getVoteFetchFuture() { - synchronized (videoIdLockObject) { - return voteFetchFuture; - } - } - - public static void newVideoLoaded(@NonNull String videoId) { - Objects.requireNonNull(videoId); - - synchronized (videoIdLockObject) { - if (videoId.equals(currentVideoId)) { - return; // already loaded - } - if (!ReVancedUtils.isNetworkConnected()) { // must do network check after verifying it's a new video id - LogHelper.printDebug(() -> "Network not connected, ignoring video: " + videoId); - setCurrentVideoId(null); - return; - } - PlayerType currentPlayerType = PlayerType.getCurrent(); - LogHelper.printDebug(() -> "New video loaded: " + videoId + " playerType: " + currentPlayerType); - setCurrentVideoId(videoId); - - // If a Short is opened while a regular video is on screen, this will incorrectly set this as false. - // But this check is needed to fix unusual situations of opening/closing the app - // while both a regular video and a short are on screen. - dislikeDataIsShort = currentPlayerType.isNoneOrHidden(); - - RYDCachedFetch entry = futureCache.get(videoId); - if (entry != null && entry.futureInProgressOrFinishedSuccessfully()) { - LogHelper.printDebug(() -> "Using cached RYD fetch: "+ entry.videoId); - voteFetchFuture = entry.future; - return; - } - voteFetchFuture = ReVancedUtils.submitOnBackgroundThread(() -> ReturnYouTubeDislikeApi.fetchVotes(videoId)); - futureCache.put(videoId, new RYDCachedFetch(voteFetchFuture, videoId)); - } - } + private final Future future; /** - * @return the replacement span containing dislikes, or the original span if RYD is not available. + * Time this instance and the future was created. */ - @NonNull - public static Spanned getDislikesSpanForRegularVideo(@NonNull Spanned original, boolean isSegmentedButton) { - if (dislikeDataIsShort) { - // user: - // 1, opened a video - // 2. opened a short (without closing the regular video) - // 3. closed the short - // 4. regular video is now present, but the videoId and RYD data is still for the short - LogHelper.printDebug(() -> "Ignoring dislike span, as data loaded is for prior short"); - return original; - } - return waitForFetchAndUpdateReplacementSpan(original, isSegmentedButton); - } + private final long timeFetched; /** - * Called when a Shorts dislike Spannable is created. + * If the video id is for a Short. + * Value of TRUE indicates it was previously loaded for a Short + * and FALSE indicates a regular video. + * NULL values means short status is not yet known. */ - @NonNull - public static Spanned getDislikeSpanForShort(@NonNull Spanned original) { - dislikeDataIsShort = true; // it's now certain the video and data are a short - return waitForFetchAndUpdateReplacementSpan(original, false); - } - - // Alternatively, this could check if the span contains one of the custom created spans, but this is simple and quick. - private static boolean isPreviouslyCreatedSegmentedSpan(@NonNull Spanned span) { - return span.toString().indexOf(MIDDLE_SEPARATOR_CHARACTER) != -1; - } - - @NonNull - private static Spanned waitForFetchAndUpdateReplacementSpan(@NonNull Spanned oldSpannable, boolean isSegmentedButton) { - try { - Future fetchFuture = getVoteFetchFuture(); - if (fetchFuture == null) { - LogHelper.printDebug(() -> "fetch future not available (user enabled RYD while video was playing?)"); - return oldSpannable; - } - // Absolutely cannot be holding any lock during get(). - RYDVoteData votingData = fetchFuture.get(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH, TimeUnit.MILLISECONDS); - if (votingData == null) { - LogHelper.printDebug(() -> "Cannot add dislike to UI (RYD data not available)"); - return oldSpannable; - } - - // Must check against existing replacements, after the fetch, - // otherwise concurrent threads can create the same replacement same multiple times. - // Also do the replacement comparison and creation in a single synchronized block. - synchronized (videoIdLockObject) { - if (originalDislikeSpan != null && replacementLikeDislikeSpan != null) { - if (spansHaveEqualTextAndColor(oldSpannable, replacementLikeDislikeSpan)) { - LogHelper.printDebug(() -> "Ignoring previously created dislikes span"); - return oldSpannable; - } - if (spansHaveEqualTextAndColor(oldSpannable, originalDislikeSpan)) { - LogHelper.printDebug(() -> "Replacing span with previously created dislike span"); - return replacementLikeDislikeSpan; - } - } - if (isSegmentedButton && isPreviouslyCreatedSegmentedSpan(oldSpannable)) { - // need to recreate using original, as oldSpannable has prior outdated dislike values - if (originalDislikeSpan == null) { - LogHelper.printDebug(() -> "Cannot add dislikes - original span is null"); // should never happen - return oldSpannable; - } - oldSpannable = originalDislikeSpan; - } - - // No replacement span exist, create it now. - - if (userVote != null) { - votingData.updateUsingVote(userVote); - } - originalDislikeSpan = oldSpannable; - replacementLikeDislikeSpan = createDislikeSpan(oldSpannable, isSegmentedButton, votingData); - LogHelper.printDebug(() -> "Replaced: '" + originalDislikeSpan + "' with: '" + replacementLikeDislikeSpan + "'"); - - return replacementLikeDislikeSpan; - } - } catch (TimeoutException e) { - LogHelper.printDebug(() -> "UI timed out while waiting for fetch votes to complete"); // show no toast - } catch (Exception e) { - LogHelper.printException(() -> "waitForFetchAndUpdateReplacementSpan failure", e); // should never happen - } - return oldSpannable; - } + @Nullable + @GuardedBy("this") + private Boolean isShort; /** - * @return if the RYD fetch call has completed. + * Optional current vote status of the UI. Used to apply a user vote that was done on a previous video viewing. */ - public static boolean fetchCompleted() { - Future future = getVoteFetchFuture(); - return future != null && future.isDone(); - } - - public static void sendVote(@NonNull Vote vote) { - ReVancedUtils.verifyOnMainThread(); - Objects.requireNonNull(vote); - try { - // Must make a local copy of videoId, since it may change between now and when the vote thread runs. - String videoIdToVoteFor = getCurrentVideoId(); - if (videoIdToVoteFor == null || - (SettingsEnum.RYD_SHORTS.getBoolean() && dislikeDataIsShort != PlayerType.getCurrent().isNoneOrHidden())) { - // User enabled RYD after starting playback of a video. - // Or shorts was loaded with regular video present, then shorts was closed, - // and then user voted on the now visible original video. - // Cannot send a vote, because the loaded videoId is for the wrong video. - ReVancedUtils.showToastLong(str("revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted")); - return; - } - - voteSerialExecutor.execute(() -> { - try { // must wrap in try/catch to properly log exceptions - String userId = getUserId(); - if (userId != null) { - ReturnYouTubeDislikeApi.sendVote(videoIdToVoteFor, userId, vote); - } - } catch (Exception ex) { - LogHelper.printException(() -> "Failed to send vote", ex); - } - }); - - setUserVote(vote); - } catch (Exception ex) { - LogHelper.printException(() -> "Error trying to send vote", ex); - } - } - - public static void setUserVote(@NonNull Vote vote) { - Objects.requireNonNull(vote); - try { - LogHelper.printDebug(() -> "setUserVote: " + vote); - - // Update the downloaded vote data. - Future future = getVoteFetchFuture(); - if (future != null && future.isDone()) { - RYDVoteData voteData; - try { - voteData = future.get(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH, TimeUnit.MILLISECONDS); - } catch (ExecutionException | InterruptedException | TimeoutException ex) { - // Should never happen - LogHelper.printInfo(() -> "Could not update vote data", ex); - return; - } - if (voteData == null) { - // RYD fetch failed - LogHelper.printDebug(() -> "Cannot update UI (vote data not available)"); - return; - } - - voteData.updateUsingVote(vote); - } // Else, vote will be applied after vote data is received - - synchronized (videoIdLockObject) { - if (userVote != vote) { - userVote = vote; - clearCache(); // UI needs updating - } - } - } catch (Exception ex) { - LogHelper.printException(() -> "setUserVote failure", ex); - } - } + @Nullable + @GuardedBy("this") + private Vote userVote; /** - * Must call off main thread, as this will make a network call if user is not yet registered. - * - * @return ReturnYouTubeDislike user ID. If user registration has never happened - * and the network call fails, this returns NULL. + * Original dislike span, before modifications. */ @Nullable - private static String getUserId() { - ReVancedUtils.verifyOffMainThread(); + @GuardedBy("this") + private Spanned originalDislikeSpan; - String userId = SettingsEnum.RYD_USER_ID.getString(); - if (!userId.isEmpty()) { - return userId; - } - - userId = ReturnYouTubeDislikeApi.registerAsNewUser(); - if (userId != null) { - SettingsEnum.RYD_USER_ID.saveValue(userId); - } - return userId; - } + /** + * Replacement like/dislike span that includes formatted dislikes. + * Used to prevent recreating the same span multiple times. + */ + @Nullable + @GuardedBy("this") + private SpannableString replacementLikeDislikeSpan; /** * @param isSegmentedButton If UI is using the segmented single UI component for both like and dislike. @@ -493,13 +203,9 @@ private static SpannableString createDislikeSpan(@NonNull Spanned oldSpannable, final int separatorColor = ThemeHelper.isDarkTheme() ? 0x29AAAAAA // transparent dark gray : 0xFFD9D9D9; // light gray - DisplayMetrics dp = Objects.requireNonNull(ReVancedUtils.getContext()).getResources().getDisplayMetrics(); if (!compactLayout) { // left separator - final Rect leftSeparatorBounds = new Rect(0, 0, - (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.2f, dp), - (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18, dp)); String leftSeparatorString = ReVancedUtils.isRightToLeftTextLayout() ? "\u200F " // u200F = right to left character : "\u200E "; // u200E = left to right character @@ -520,8 +226,6 @@ private static SpannableString createDislikeSpan(@NonNull Spanned oldSpannable, ? " " + MIDDLE_SEPARATOR_CHARACTER + " " : " \u2009" + MIDDLE_SEPARATOR_CHARACTER + "\u2009 "; // u2009 = 'narrow space' character final int shapeInsertionIndex = middleSeparatorString.length() / 2; - final int middleSeparatorSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp); - final Rect middleSeparatorBounds = new Rect(0, 0, middleSeparatorSize, middleSeparatorSize); Spannable middleSeparatorSpan = new SpannableString(middleSeparatorString); ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape()); shapeDrawable.getPaint().setColor(separatorColor); @@ -536,6 +240,11 @@ private static SpannableString createDislikeSpan(@NonNull Spanned oldSpannable, return new SpannableString(builder); } + // Alternatively, this could check if the span contains one of the custom created spans, but this is simple and quick. + private static boolean isPreviouslyCreatedSegmentedSpan(@NonNull Spanned span) { + return span.toString().indexOf(MIDDLE_SEPARATOR_CHARACTER) != -1; + } + /** * Correctly handles any unicode numbers (such as Arabic numbers). * @@ -603,7 +312,7 @@ private static String formatDislikeCount(long dislikeCount) { } } - // will never be reached, as the oldest supported YouTube app requires Android N or greater + // Will never be reached, as the oldest supported YouTube app requires Android N or greater. return String.valueOf(dislikeCount); } @@ -622,6 +331,231 @@ private static String formatDislikePercentage(float dislikePercentage) { return dislikePercentageFormatter.format(dislikePercentage); } } + + @NonNull + public static ReturnYouTubeDislike getFetchForVideoId(@Nullable String videoId) { + Objects.requireNonNull(videoId); + synchronized (fetchCache) { + // Remove any expired entries. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + final long now = System.currentTimeMillis(); + fetchCache.values().removeIf(value -> { + final boolean expired = value.isExpired(now); + if (expired) + LogHelper.printDebug(() -> "Removing expired fetch: " + value.videoId); + return expired; + }); + } + + ReturnYouTubeDislike fetch = fetchCache.get(videoId); + if (fetch == null || !fetch.futureInProgressOrFinishedSuccessfully()) { + fetch = new ReturnYouTubeDislike(videoId); + fetchCache.put(videoId, fetch); + } + return fetch; + } + } + + /** + * Should be called if the user changes settings for dislikes appearance. + */ + public static void clearAllUICaches() { + synchronized (fetchCache) { + for (ReturnYouTubeDislike fetch : fetchCache.values()) { + fetch.clearUICache(); + } + } + } + + private ReturnYouTubeDislike(@NonNull String videoId) { + this.videoId = Objects.requireNonNull(videoId); + this.timeFetched = System.currentTimeMillis(); + this.future = ReVancedUtils.submitOnBackgroundThread(() -> ReturnYouTubeDislikeApi.fetchVotes(videoId)); + } + + private boolean isExpired(long now) { + return timeFetched != 0 && (now - timeFetched) > CACHE_TIMEOUT_MILLISECONDS; + } + + @Nullable + public RYDVoteData getFetchData(long maxTimeToWait) { + try { + return future.get(maxTimeToWait, TimeUnit.MILLISECONDS); + } catch (TimeoutException ex) { + LogHelper.printDebug(() -> "Waited but future was not complete after: " + maxTimeToWait + "ms"); + } catch (ExecutionException | InterruptedException ex) { + LogHelper.printException(() -> "Future failure ", ex); // will never happen + } + return null; + } + + private boolean futureInProgressOrFinishedSuccessfully() { + return !future.isDone() || getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH) != null; + } + + private synchronized void clearUICache() { + if (replacementLikeDislikeSpan != null) { + LogHelper.printDebug(() -> "Clearing replacement span for: " + videoId); + } + replacementLikeDislikeSpan = null; + } + + @NonNull + public String getVideoId() { + return videoId; + } + + /** + * Pre-emptively set this as a Short. + * Should only be used immediately after creation of this instance. + */ + public synchronized void setVideoIdIsShort(boolean isShort) { + this.isShort = isShort; + } + + /** + * @return the replacement span containing dislikes, or the original span if RYD is not available. + */ + @NonNull + public synchronized Spanned getDislikesSpanForRegularVideo(@NonNull Spanned original, boolean isSegmentedButton) { + return waitForFetchAndUpdateReplacementSpan(original, isSegmentedButton, false); + } + + /** + * Called when a Shorts dislike Spannable is created. + */ + @NonNull + public synchronized Spanned getDislikeSpanForShort(@NonNull Spanned original) { + return waitForFetchAndUpdateReplacementSpan(original, false, true); + } + + @NonNull + private Spanned waitForFetchAndUpdateReplacementSpan(@NonNull Spanned original, + boolean isSegmentedButton, + boolean spanIsForShort) { + try { + RYDVoteData votingData = getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH); + if (votingData == null) { + LogHelper.printDebug(() -> "Cannot add dislike to UI (RYD data not available)"); + return original; + } + + synchronized (this) { + if (isShort != null) { + if (isShort != spanIsForShort) { + // user: + // 1, opened a video + // 2. opened a short (without closing the regular video) + // 3. closed the short + // 4. regular video is now present, but the videoId and RYD data is still for the short + LogHelper.printDebug(() -> "Ignoring dislike span, as data loaded was previously" + + " used for a different video type."); + return original; + } + } else { + isShort = spanIsForShort; + } + + if (originalDislikeSpan != null && replacementLikeDislikeSpan != null) { + if (spansHaveEqualTextAndColor(original, replacementLikeDislikeSpan)) { + LogHelper.printDebug(() -> "Ignoring previously created dislikes span"); + return original; + } + if (spansHaveEqualTextAndColor(original, originalDislikeSpan)) { + LogHelper.printDebug(() -> "Replacing span with previously created dislike span"); + return replacementLikeDislikeSpan; + } + } + if (isSegmentedButton && isPreviouslyCreatedSegmentedSpan(original)) { + // need to recreate using original, as original has prior outdated dislike values + if (originalDislikeSpan == null) { + LogHelper.printDebug(() -> "Cannot add dislikes - original span is null"); // should never happen + return original; + } + original = originalDislikeSpan; + } + + // No replacement span exist, create it now. + + if (userVote != null) { + votingData.updateUsingVote(userVote); + } + originalDislikeSpan = original; + replacementLikeDislikeSpan = createDislikeSpan(original, isSegmentedButton, votingData); + LogHelper.printDebug(() -> "Replaced: '" + originalDislikeSpan + "' with: '" + + replacementLikeDislikeSpan + "'" + " using video: " + videoId); + + return replacementLikeDislikeSpan; + } + } catch (Exception e) { + LogHelper.printException(() -> "waitForFetchAndUpdateReplacementSpan failure", e); // should never happen + } + return original; + } + + /** + * @return if the RYD fetch call has completed. + */ + public boolean fetchCompleted() { + return future.isDone(); + } + + public void sendVote(@NonNull Vote vote) { + ReVancedUtils.verifyOnMainThread(); + Objects.requireNonNull(vote); + try { + if (isShort != null && isShort != PlayerType.getCurrent().isNoneOrHidden()) { + // Shorts was loaded with regular video present, then Shorts was closed. + // and then user voted on the now visible original video. + // Cannot send a vote, because the loaded videoId is for the wrong video. + ReVancedUtils.showToastLong(str("revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted")); + return; + } + + setUserVote(vote); + + voteSerialExecutor.execute(() -> { + try { // Must wrap in try/catch to properly log exceptions. + ReturnYouTubeDislikeApi.sendVote(videoId, vote); + } catch (Exception ex) { + LogHelper.printException(() -> "Failed to send vote", ex); + } + }); + } catch (Exception ex) { + LogHelper.printException(() -> "Error trying to send vote", ex); + } + } + + /** + * Sets the current user vote value, and does not send the vote to the RYD API. + * + * Only used to set value if thumbs up/down is already selected on video load. + */ + public void setUserVote(@NonNull Vote vote) { + Objects.requireNonNull(vote); + try { + LogHelper.printDebug(() -> "setUserVote: " + vote); + + synchronized (this) { + userVote = vote; + clearUICache(); + } + + if (future.isDone()) { + // Update the fetched vote data. + RYDVoteData voteData = getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH); + if (voteData == null) { + // RYD fetch failed. + LogHelper.printDebug(() -> "Cannot update UI (vote data not available)"); + return; + } + voteData.updateUsingVote(vote); + } // Else, vote will be applied after fetch completes. + + } catch (Exception ex) { + LogHelper.printException(() -> "setUserVote failure", ex); + } + } } class VerticallyCenteredImageSpan extends ImageSpan { diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/RYDVoteData.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/RYDVoteData.java index 149f7ffd74..faf6161950 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/RYDVoteData.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/RYDVoteData.java @@ -7,8 +7,6 @@ import org.json.JSONException; import org.json.JSONObject; -import app.revanced.integrations.utils.LogHelper; - /** * ReturnYouTubeDislike API estimated like/dislike/view counts. * @@ -81,17 +79,21 @@ public float getDislikePercentage() { } public void updateUsingVote(Vote vote) { - if (vote == Vote.LIKE) { - likeCount = fetchedLikeCount + 1; - dislikeCount = fetchedDislikeCount; - } else if (vote == Vote.DISLIKE) { - likeCount = fetchedLikeCount; - dislikeCount = fetchedDislikeCount + 1; - } else if (vote == Vote.LIKE_REMOVE) { - likeCount = fetchedLikeCount; - dislikeCount = fetchedDislikeCount; - } else { - throw new IllegalStateException(); + switch (vote) { + case LIKE: + likeCount = fetchedLikeCount + 1; + dislikeCount = fetchedDislikeCount; + break; + case DISLIKE: + likeCount = fetchedLikeCount; + dislikeCount = fetchedDislikeCount + 1; + break; + case LIKE_REMOVE: + likeCount = fetchedLikeCount; + dislikeCount = fetchedDislikeCount; + break; + default: + throw new IllegalStateException(); } updatePercentages(); } diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java index 0965f493d0..a7e82576d4 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java @@ -391,13 +391,37 @@ private static String confirmRegistration(String userId, String solution) { return null; } - public static boolean sendVote(String videoId, String userId, ReturnYouTubeDislike.Vote vote) { + /** + * Must call off main thread, as this will make a network call if user is not yet registered. + * + * @return ReturnYouTubeDislike user ID. If user registration has never happened + * and the network call fails, this returns NULL. + */ + @Nullable + private static String getUserId() { + ReVancedUtils.verifyOffMainThread(); + + String userId = SettingsEnum.RYD_USER_ID.getString(); + if (!userId.isEmpty()) { + return userId; + } + + userId = registerAsNewUser(); + if (userId != null) { + SettingsEnum.RYD_USER_ID.saveValue(userId); + } + return userId; + } + + public static boolean sendVote(String videoId, ReturnYouTubeDislike.Vote vote) { ReVancedUtils.verifyOffMainThread(); Objects.requireNonNull(videoId); - Objects.requireNonNull(userId); Objects.requireNonNull(vote); try { + String userId = getUserId(); + if (userId == null) return false; + if (checkIfRateLimitInEffect("sendVote")) { return false; } diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java b/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java index dadc85beb7..711d0f20e0 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java @@ -12,6 +12,7 @@ import android.preference.PreferenceScreen; import android.preference.SwitchPreference; +import app.revanced.integrations.patches.ReturnYouTubeDislikePatch; import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; import app.revanced.integrations.returnyoutubedislike.requests.ReturnYouTubeDislikeApi; import app.revanced.integrations.settings.SettingsEnum; @@ -63,7 +64,7 @@ public void onCreate(Bundle savedInstanceState) { enabledPreference.setOnPreferenceChangeListener((pref, newValue) -> { final boolean rydIsEnabled = (Boolean) newValue; SettingsEnum.RYD_ENABLED.saveValue(rydIsEnabled); - ReturnYouTubeDislike.onEnabledChange(rydIsEnabled); + ReturnYouTubeDislikePatch.onRYDStatusChange(rydIsEnabled); updateUIState(); return true; @@ -89,7 +90,7 @@ public void onCreate(Bundle savedInstanceState) { percentagePreference.setSummaryOff(str("revanced_ryd_dislike_percentage_summary_off")); percentagePreference.setOnPreferenceChangeListener((pref, newValue) -> { SettingsEnum.RYD_DISLIKE_PERCENTAGE.saveValue(newValue); - ReturnYouTubeDislike.clearCache(); + ReturnYouTubeDislike.clearAllUICaches(); updateUIState(); return true; }); @@ -102,7 +103,7 @@ public void onCreate(Bundle savedInstanceState) { compactLayoutPreference.setSummaryOff(str("revanced_ryd_compact_layout_summary_off")); compactLayoutPreference.setOnPreferenceChangeListener((pref, newValue) -> { SettingsEnum.RYD_COMPACT_LAYOUT.saveValue(newValue); - ReturnYouTubeDislike.clearCache(); + ReturnYouTubeDislike.clearAllUICaches(); updateUIState(); return true; }); diff --git a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java index 940dd50819..286a03bf23 100644 --- a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java +++ b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java @@ -83,9 +83,17 @@ public static Future submitOnBackgroundThread(@NonNull Callable call) } public static boolean containsAny(@NonNull String value, @NonNull String... targets) { - for (String string : targets) - if (!string.isEmpty() && value.contains(string)) return true; - return false; + return indexOfFirstFound(value, targets) >= 0; + } + + public static int indexOfFirstFound(@NonNull String value, @NonNull String... targets) { + for (String string : targets) { + if (!string.isEmpty()) { + final int indexOf = value.indexOf(string); + if (indexOf >= 0) return indexOf; + } + } + return -1; } /** diff --git a/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java b/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java index 6458f07cb5..8b9fecb8f4 100644 --- a/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java +++ b/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java @@ -23,11 +23,12 @@ public interface TriePatternMatchedCallback { * * @param textSearched Text that was searched. * @param matchedStartIndex Start index of the search text, where the pattern was matched. + * @param matchedLength Length of the match. * @param callbackParameter Optional parameter passed into {@link TrieSearch#matches(Object, Object)}. * @return True, if the search should stop here. * If false, searching will continue to look for other matches. */ - boolean patternMatched(T textSearched, int matchedStartIndex, Object callbackParameter); + boolean patternMatched(T textSearched, int matchedStartIndex, int matchedLength, Object callbackParameter); } /** @@ -64,8 +65,8 @@ boolean matches(TrieNode enclosingNode, // Used only for the get character me return false; } } - return callback == null - || callback.patternMatched(searchText, searchTextIndex - patternStartIndex, callbackParameter); + return callback == null || callback.patternMatched(searchText, + searchTextIndex - patternStartIndex, patternLength, callbackParameter); } } @@ -161,7 +162,7 @@ private boolean matches(T searchText, int searchTextLength, int searchTextIndex, if (callback == null) { return true; // No callback and all matches are valid. } - if (callback.patternMatched(searchText, matchStartIndex, callbackParameter)) { + if (callback.patternMatched(searchText, matchStartIndex, currentMatchLength, callbackParameter)) { return true; // Callback confirmed the match. } } From 78b5fe2128a15d119af96cd0a1e8afa4e864d5eb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 7 Oct 2023 09:35:05 +0000 Subject: [PATCH 36/53] chore(release): 0.119.0-dev.5 [skip ci] # [0.119.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.4...v0.119.0-dev.5) (2023-10-07) ### Features * **YouTube - Return YouTube Dislike:** Support version `18.37.36` ([#490](https://github.com/ReVanced/revanced-integrations/issues/490)) ([245c3b3](https://github.com/ReVanced/revanced-integrations/commit/245c3b35373313d49cc5b1c2fd8e9deebb6258a5)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41d66863a1..114d5a9e46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.119.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.4...v0.119.0-dev.5) (2023-10-07) + + +### Features + +* **YouTube - Return YouTube Dislike:** Support version `18.37.36` ([#490](https://github.com/ReVanced/revanced-integrations/issues/490)) ([245c3b3](https://github.com/ReVanced/revanced-integrations/commit/245c3b35373313d49cc5b1c2fd8e9deebb6258a5)) + # [0.119.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.3...v0.119.0-dev.4) (2023-10-07) diff --git a/gradle.properties b/gradle.properties index a5fba830f5..5890fa2f41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0-dev.4 +version = 0.119.0-dev.5 From 486c894257e91dedc04b38191e0e01e38c66b5c4 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 7 Oct 2023 23:06:10 +0400 Subject: [PATCH 37/53] fix(YouTube - ReturnYouTubeDislike): Do not retry API call if same fetch recently failed (#493) --- .../patches/ReturnYouTubeDislikePatch.java | 13 ++++++- .../ReturnYouTubeDislike.java | 38 ++++++++++++------- .../requests/ReturnYouTubeDislikeApi.java | 6 +-- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 1dd5fb5347..89ad8a66bf 100644 --- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -25,6 +25,17 @@ /** * Handles all interaction of UI patch components. + * + * Known limitation: + * Litho based Shorts player can experience temporarily frozen video playback if the RYD fetch takes too long. + * + * Temporary work around: + * Enable app spoofing to version 18.20.39 or older, as that uses a non litho Shorts player. + * + * Permanent fix (yet to be implemented), either of: + * - Modify patch to hook onto the Shorts Litho TextView, and update the dislikes asynchronously. + * - Find a way to force Litho to rebuild it's component tree + * (and use that hook to force the shorts dislikes to update after the fetch is completed). */ public class ReturnYouTubeDislikePatch { @@ -435,10 +446,10 @@ public static void newVideoLoaded(@NonNull String videoId, boolean isShortsLitho lastLithoShortsVideoData = videoData; lithoShortsShouldUseCurrentData = false; } else { + // All other playback (including non-litho Shorts). if (videoIdIsSame(currentVideoData, videoId)) { return; } - // All other playback (including litho Shorts). currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId); } diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java index d68d0c1edc..e4829964c4 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java @@ -69,12 +69,18 @@ public enum Vote { * Must be less than 5 seconds, as per: * https://developer.android.com/topic/performance/vitals/anr */ - private static final long MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH = 4000; + private static final long MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH = 4500; /** - * How long to retain cached RYD fetches. + * How long to retain successful RYD fetches. */ - private static final long CACHE_TIMEOUT_MILLISECONDS = 5 * 60 * 1000; // 5 Minutes + private static final long CACHE_TIMEOUT_SUCCESS_MILLISECONDS = 5 * 60 * 1000; // 5 Minutes + + /** + * How long to retain unsuccessful RYD fetches, + * and also the minimum time before retrying again. + */ + private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 60 * 1000; // 1 Minute /** * Unique placeholder character, used to detect if a segmented span already has dislikes added to it. @@ -348,7 +354,7 @@ public static ReturnYouTubeDislike getFetchForVideoId(@Nullable String videoId) } ReturnYouTubeDislike fetch = fetchCache.get(videoId); - if (fetch == null || !fetch.futureInProgressOrFinishedSuccessfully()) { + if (fetch == null) { fetch = new ReturnYouTubeDislike(videoId); fetchCache.put(videoId, fetch); } @@ -374,7 +380,15 @@ private ReturnYouTubeDislike(@NonNull String videoId) { } private boolean isExpired(long now) { - return timeFetched != 0 && (now - timeFetched) > CACHE_TIMEOUT_MILLISECONDS; + final long timeSinceCreation = now - timeFetched; + if (timeSinceCreation < CACHE_TIMEOUT_FAILURE_MILLISECONDS) { + return false; // Not expired, even if the API call failed. + } + if (timeSinceCreation > CACHE_TIMEOUT_SUCCESS_MILLISECONDS) { + return true; // Always expired. + } + // Only expired if the fetch failed (API null response). + return (!fetchCompleted() || getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH) == null); } @Nullable @@ -389,8 +403,11 @@ public RYDVoteData getFetchData(long maxTimeToWait) { return null; } - private boolean futureInProgressOrFinishedSuccessfully() { - return !future.isDone() || getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH) != null; + /** + * @return if the RYD fetch call has completed. + */ + public boolean fetchCompleted() { + return future.isDone(); } private synchronized void clearUICache() { @@ -493,13 +510,6 @@ private Spanned waitForFetchAndUpdateReplacementSpan(@NonNull Spanned original, return original; } - /** - * @return if the RYD fetch call has completed. - */ - public boolean fetchCompleted() { - return future.isDone(); - } - public void sendVote(@NonNull Vote vote) { ReVancedUtils.verifyOnMainThread(); Objects.requireNonNull(vote); diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java index a7e82576d4..f10ed8210f 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java @@ -35,10 +35,10 @@ public class ReturnYouTubeDislikeApi { private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2000; /** - * {@link #fetchVotes(String)} HTTP read timeout - * To locally debug and force timeouts, change this to a very small number (ie: 100) + * {@link #fetchVotes(String)} HTTP read timeout. + * To locally debug and force timeouts, change this to a very small number (ie: 100) */ - private static final int API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS = 4000; + private static final int API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS = 5000; /** * Default connection and response timeout for voting and registration. From a1477c097c956fc0ed3b99f42b1a3c7b493ff56d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 7 Oct 2023 19:09:57 +0000 Subject: [PATCH 38/53] chore(release): 0.119.0-dev.6 [skip ci] # [0.119.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.5...v0.119.0-dev.6) (2023-10-07) ### Bug Fixes * **YouTube - ReturnYouTubeDislike:** Do not retry API call if same fetch recently failed ([#493](https://github.com/ReVanced/revanced-integrations/issues/493)) ([486c894](https://github.com/ReVanced/revanced-integrations/commit/486c894257e91dedc04b38191e0e01e38c66b5c4)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 114d5a9e46..0ec912f863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.119.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.5...v0.119.0-dev.6) (2023-10-07) + + +### Bug Fixes + +* **YouTube - ReturnYouTubeDislike:** Do not retry API call if same fetch recently failed ([#493](https://github.com/ReVanced/revanced-integrations/issues/493)) ([486c894](https://github.com/ReVanced/revanced-integrations/commit/486c894257e91dedc04b38191e0e01e38c66b5c4)) + # [0.119.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.4...v0.119.0-dev.5) (2023-10-07) diff --git a/gradle.properties b/gradle.properties index 5890fa2f41..da50146187 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0-dev.5 +version = 0.119.0-dev.6 From 771dd608dc32511acdec3d1ebb6cd4d4e8211c31 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 8 Oct 2023 01:48:56 +0000 Subject: [PATCH 39/53] chore(release): 0.119.0 [skip ci] # [0.119.0](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0...v0.119.0) (2023-10-08) ### Bug Fixes * **YouTube - Hide shorts components:** Add filter to filter group list ([30788ba](https://github.com/ReVanced/revanced-integrations/commit/30788ba1a3e8d666b55a37e9389246e4bfa039cb)) * **YouTube - Hide shorts components:** Do not prevent filtering components ([6eb3017](https://github.com/ReVanced/revanced-integrations/commit/6eb301776e202cf1d923f96cc83ddf6f0430b211)) * **YouTube - Hide shorts components:** Hide the subscribe button when paused ([6730aaf](https://github.com/ReVanced/revanced-integrations/commit/6730aaf2b864b747a6b77411cdaceee653b36218)) * **YouTube - ReturnYouTubeDislike:** Do not retry API call if same fetch recently failed ([#493](https://github.com/ReVanced/revanced-integrations/issues/493)) ([486c894](https://github.com/ReVanced/revanced-integrations/commit/486c894257e91dedc04b38191e0e01e38c66b5c4)) ### Features * **YouTube - Hide shorts components:** Hide subscribe button when paused separately from subscribe button ([3ac869f](https://github.com/ReVanced/revanced-integrations/commit/3ac869fa6ae095f074481d98d9a4eea207eda00d)) * **YouTube - Return YouTube Dislike:** Support version `18.37.36` ([#490](https://github.com/ReVanced/revanced-integrations/issues/490)) ([245c3b3](https://github.com/ReVanced/revanced-integrations/commit/245c3b35373313d49cc5b1c2fd8e9deebb6258a5)) * **YouTube:** Add `Disable fine scrubbing gesture` patch ([4498f39](https://github.com/ReVanced/revanced-integrations/commit/4498f39b8c4900fccdc359d0c687c26db23526c3)) --- CHANGELOG.md | 17 +++++++++++++++++ gradle.properties | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ec912f863..24aa6f245e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +# [0.119.0](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0...v0.119.0) (2023-10-08) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Add filter to filter group list ([30788ba](https://github.com/ReVanced/revanced-integrations/commit/30788ba1a3e8d666b55a37e9389246e4bfa039cb)) +* **YouTube - Hide shorts components:** Do not prevent filtering components ([6eb3017](https://github.com/ReVanced/revanced-integrations/commit/6eb301776e202cf1d923f96cc83ddf6f0430b211)) +* **YouTube - Hide shorts components:** Hide the subscribe button when paused ([6730aaf](https://github.com/ReVanced/revanced-integrations/commit/6730aaf2b864b747a6b77411cdaceee653b36218)) +* **YouTube - ReturnYouTubeDislike:** Do not retry API call if same fetch recently failed ([#493](https://github.com/ReVanced/revanced-integrations/issues/493)) ([486c894](https://github.com/ReVanced/revanced-integrations/commit/486c894257e91dedc04b38191e0e01e38c66b5c4)) + + +### Features + +* **YouTube - Hide shorts components:** Hide subscribe button when paused separately from subscribe button ([3ac869f](https://github.com/ReVanced/revanced-integrations/commit/3ac869fa6ae095f074481d98d9a4eea207eda00d)) +* **YouTube - Return YouTube Dislike:** Support version `18.37.36` ([#490](https://github.com/ReVanced/revanced-integrations/issues/490)) ([245c3b3](https://github.com/ReVanced/revanced-integrations/commit/245c3b35373313d49cc5b1c2fd8e9deebb6258a5)) +* **YouTube:** Add `Disable fine scrubbing gesture` patch ([4498f39](https://github.com/ReVanced/revanced-integrations/commit/4498f39b8c4900fccdc359d0c687c26db23526c3)) + # [0.119.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0-dev.5...v0.119.0-dev.6) (2023-10-07) diff --git a/gradle.properties b/gradle.properties index da50146187..362609c067 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0-dev.6 +version = 0.119.0 From 1479d6bc2668758ea55f9d640684547f710099f0 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 8 Oct 2023 21:08:29 +0200 Subject: [PATCH 40/53] fix(YouTube - Hide shorts components): Do not hide subscribe button outside of Shorts --- .../patches/components/ShortsFilter.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index a5602476f3..7ab5a54296 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -10,6 +10,7 @@ import static app.revanced.integrations.utils.ReVancedUtils.hideViewBy1dpUnderCondition; import static app.revanced.integrations.utils.ReVancedUtils.hideViewUnderCondition; +/** @noinspection unused*/ @RequiresApi(api = Build.VERSION_CODES.N) public final class ShortsFilter extends Filter { public static PivotBar pivotBar; // Set by patch. @@ -117,21 +118,25 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff if (matchedGroup == soundButton || matchedGroup == infoPanel || matchedGroup == channelBar || - matchedGroup == subscribeButton || matchedGroup == subscribeButtonPaused ) return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); // Video action buttons (comment, share, remix) have the same path. if (matchedGroup == videoActionButton) { - if (videoActionButtonGroupList.check(protobufBufferArray).isFiltered()) - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + if (videoActionButtonGroupList.check(protobufBufferArray).isFiltered()) return super.isFiltered( + identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex + ); return false; } // Filter other path groups from pathFilterGroupList, only when reelChannelBar is visible // to avoid false positives. - if (!path.startsWith(REEL_CHANNEL_BAR_PATH)) - return false; + if (path.startsWith(REEL_CHANNEL_BAR_PATH)) + if (matchedGroup == subscribeButton) return super.isFiltered( + identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex + ); + + return false; } else if (matchedGroup == shelfHeader) { // Because the header is used in watch history and possibly other places, check for the index, // which is 0 when the shelf header is used for Shorts. From 8a40ca616e9ca02861a8b52cfafa09088ee601e5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 8 Oct 2023 19:13:01 +0000 Subject: [PATCH 41/53] chore(release): 0.119.1-dev.1 [skip ci] ## [0.119.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0...v0.119.1-dev.1) (2023-10-08) ### Bug Fixes * **YouTube - Hide shorts components:** Do not hide subscribe button outside of Shorts ([1479d6b](https://github.com/ReVanced/revanced-integrations/commit/1479d6bc2668758ea55f9d640684547f710099f0)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24aa6f245e..07439ffead 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.119.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0...v0.119.1-dev.1) (2023-10-08) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Do not hide subscribe button outside of Shorts ([1479d6b](https://github.com/ReVanced/revanced-integrations/commit/1479d6bc2668758ea55f9d640684547f710099f0)) + # [0.119.0](https://github.com/ReVanced/revanced-integrations/compare/v0.118.0...v0.119.0) (2023-10-08) diff --git a/gradle.properties b/gradle.properties index 362609c067..707ccfa03d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.0 +version = 0.119.1-dev.1 From dceaf7a1ecc644f65de5140c724c1c70aac719af Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 9 Oct 2023 17:02:49 +0000 Subject: [PATCH 42/53] chore(release): 0.119.1 [skip ci] ## [0.119.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0...v0.119.1) (2023-10-09) ### Bug Fixes * **YouTube - Hide shorts components:** Do not hide subscribe button outside of Shorts ([1479d6b](https://github.com/ReVanced/revanced-integrations/commit/1479d6bc2668758ea55f9d640684547f710099f0)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07439ffead..566dc59ec9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.119.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0...v0.119.1) (2023-10-09) + + +### Bug Fixes + +* **YouTube - Hide shorts components:** Do not hide subscribe button outside of Shorts ([1479d6b](https://github.com/ReVanced/revanced-integrations/commit/1479d6bc2668758ea55f9d640684547f710099f0)) + ## [0.119.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0...v0.119.1-dev.1) (2023-10-08) diff --git a/gradle.properties b/gradle.properties index 707ccfa03d..d9a7d70ee7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.1-dev.1 +version = 0.119.1 From 9b2add7553488436c63fa14bd62966dfb92705bf Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Thu, 12 Oct 2023 12:27:38 +0300 Subject: [PATCH 43/53] fix(YouTube - ReturnYouTubeDislike): Fix dislikes not showing on Shorts (#495) --- .../patches/ReturnYouTubeDislikePatch.java | 84 ++++++++---- .../ReturnYouTubeDislikeFilterPatch.java | 123 +++++++++++++----- .../ReturnYouTubeDislike.java | 53 ++++---- .../ReturnYouTubeDislikeSettingsFragment.java | 10 +- .../integrations/shared/PlayerType.kt | 36 ++++- 5 files changed, 212 insertions(+), 94 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 89ad8a66bf..7bbcb8b852 100644 --- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -1,28 +1,33 @@ package app.revanced.integrations.patches; +import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote; + import android.graphics.Rect; import android.os.Build; -import android.text.*; +import android.text.Editable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextWatcher; import android.view.View; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + import app.revanced.integrations.patches.components.ReturnYouTubeDislikeFilterPatch; -import app.revanced.integrations.patches.spoof.SpoofAppVersionPatch; import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.shared.PlayerType; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote; - /** * Handles all interaction of UI patch components. * @@ -108,7 +113,7 @@ public static void onRYDStatusChange(boolean rydEnabled) { /** * Old UI dislikes can be set multiple times by YouTube. - * To prevent it from reverting changes made here, this listener overrides any future changes YouTube makes. + * To prevent reverting changes made here, this listener overrides any future changes YouTube makes. */ private static final TextWatcher oldUiTextWatcher = new TextWatcher() { public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -141,7 +146,7 @@ private static void updateOldUIDislikesTextView() { /** * Injection point. Called on main thread. * - * Used when spoofing the older app versions of {@link SpoofAppVersionPatch}. + * Used when spoofing to 16.x and 17.x versions. */ public static void setOldUILayoutDislikes(int buttonViewResourceId, @Nullable TextView textView) { try { @@ -230,9 +235,9 @@ public static CharSequence onLithoTextLoaded(@NonNull Object conversionContext, } ReturnYouTubeDislike videoData = lastLithoShortsVideoData; if (videoData == null) { - // Should not happen, as user cannot turn on RYD while leaving a short on screen. - // If this does happen, then the litho video id filter did not detect the video id. - LogHelper.printDebug(() -> "Error: Litho video data is null, but it should not be"); + // The Shorts litho video id filter did not detect the video id. + // This is normal if in incognito mode, but otherwise is not normal. + LogHelper.printDebug(() -> "Cannot modify Shorts litho span, data is null"); return original; } // Use the correct dislikes data after voting. @@ -425,14 +430,18 @@ public static void newVideoLoaded(@NonNull String videoId) { * Called both on and off main thread. * * @param isShortsLithoVideoId If the video id is from {@link ReturnYouTubeDislikeFilterPatch}. + * if true, then the video id can be null indicating the filter did + * not find any video id. */ - public static void newVideoLoaded(@NonNull String videoId, boolean isShortsLithoVideoId) { + public static void newVideoLoaded(@Nullable String videoId, boolean isShortsLithoVideoId) { try { if (!SettingsEnum.RYD_ENABLED.getBoolean()) return; PlayerType currentPlayerType = PlayerType.getCurrent(); - final boolean isNoneOrHidden = currentPlayerType.isNoneOrHidden(); - if (isNoneOrHidden && !SettingsEnum.RYD_SHORTS.getBoolean()) { + final boolean isNoneHiddenOrSlidingMinimized = currentPlayerType.isNoneHiddenOrSlidingMinimized(); + if (isNoneHiddenOrSlidingMinimized && !SettingsEnum.RYD_SHORTS.getBoolean()) { + // Must clear here, otherwise the wrong data can be used for a minimized regular video. + currentVideoData = null; return; } @@ -441,24 +450,41 @@ public static void newVideoLoaded(@NonNull String videoId, boolean isShortsLitho if (videoIdIsSame(lastLithoShortsVideoData, videoId)) { return; } + if (videoId == null) { + // Litho filter did not detect the video id. App is in incognito mode, + // or the proto buffer structure was changed and the video id is no longer present. + // Must clear both currently playing and last litho data otherwise the + // next regular video may use the wrong data. + LogHelper.printDebug(() -> "Litho filter did not find any video ids"); + currentVideoData = null; + lastLithoShortsVideoData = null; + lithoShortsShouldUseCurrentData = false; + return; + } ReturnYouTubeDislike videoData = ReturnYouTubeDislike.getFetchForVideoId(videoId); videoData.setVideoIdIsShort(true); lastLithoShortsVideoData = videoData; lithoShortsShouldUseCurrentData = false; } else { + Objects.requireNonNull(videoId); // All other playback (including non-litho Shorts). if (videoIdIsSame(currentVideoData, videoId)) { return; } currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId); + // Pre-emptively set the data to short status. + // Required to prevent Shorts data from being used on a minimized video in incognito mode. + if (isNoneHiddenOrSlidingMinimized) { + currentVideoData.setVideoIdIsShort(true); + } } LogHelper.printDebug(() -> "New video id: " + videoId + " playerType: " + currentPlayerType + " isShortsLithoHook: " + isShortsLithoVideoId); - if (isNoneOrHidden) { - // Current video id hook can be called out of order with the non litho Shorts text view hook. - // Must manually update again here. + // Current video id hook can be called out of order with the non litho Shorts text view hook. + // Must manually update again here. + if (!isShortsLithoVideoId && isNoneHiddenOrSlidingMinimized) { updateOnScreenShortsTextViews(true); } } catch (Exception ex) { @@ -466,8 +492,9 @@ public static void newVideoLoaded(@NonNull String videoId, boolean isShortsLitho } } - private static boolean videoIdIsSame(@Nullable ReturnYouTubeDislike fetch, String videoId) { - return fetch != null && fetch.getVideoId().equals(videoId); + private static boolean videoIdIsSame(@Nullable ReturnYouTubeDislike fetch, @Nullable String videoId) { + return (fetch == null && videoId == null) + || (fetch != null && fetch.getVideoId().equals(videoId)); } /** @@ -482,11 +509,13 @@ public static void sendVote(int vote) { if (!SettingsEnum.RYD_ENABLED.getBoolean()) { return; } - if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneHiddenOrMinimized()) { + final boolean isNoneHiddenOrMinimized = PlayerType.getCurrent().isNoneHiddenOrMinimized(); + if (isNoneHiddenOrMinimized && !SettingsEnum.RYD_SHORTS.getBoolean()) { return; } ReturnYouTubeDislike videoData = currentVideoData; if (videoData == null) { + LogHelper.printDebug(() -> "Cannot send vote, as current video data is null"); return; // User enabled RYD while a regular video was minimized. } @@ -494,10 +523,13 @@ public static void sendVote(int vote) { if (v.value == vote) { videoData.sendVote(v); - if (lastLithoShortsVideoData != null) { - lithoShortsShouldUseCurrentData = true; + if (isNoneHiddenOrMinimized) { + if (lastLithoShortsVideoData != null) { + lithoShortsShouldUseCurrentData = true; + } + updateOldUIDislikesTextView(); } - updateOldUIDislikesTextView(); + return; } } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java index 54d068ad45..b52fd486fc 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java @@ -2,17 +2,72 @@ import android.os.Build; +import androidx.annotation.GuardedBy; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; import app.revanced.integrations.patches.ReturnYouTubeDislikePatch; +import app.revanced.integrations.patches.VideoInformation; import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.utils.LogHelper; +import app.revanced.integrations.utils.TrieSearch; +/** + * Searches for video id's in the proto buffer of Shorts dislike. + * + * Because multiple litho dislike spans are created in the background + * (and also anytime litho refreshes the components, which is somewhat arbitrary), + * that makes the value of {@link VideoInformation#getVideoId()} and {@link VideoInformation#getPlayerResponseVideoId()} + * unreliable to determine which video id a Shorts litho span belongs to. + * + * But the correct video id does appear in the protobuffer just before a Shorts litho span is created. + * + * Once a way to asynchronously update litho text is found, this strategy will no longer be needed. + */ @RequiresApi(api = Build.VERSION_CODES.N) public final class ReturnYouTubeDislikeFilterPatch extends Filter { + /** + * Last unique video id's loaded. Value is ignored and Map is treated as a Set. + * Cannot use {@link LinkedHashSet} because it's missing #removeEldestEntry(). + */ + @GuardedBy("itself") + private static final Map lastVideoIds = new LinkedHashMap<>() { + /** + * Number of video id's to keep track of for searching thru the buffer. + * A minimum value of 3 should be sufficient, but check a few more just in case. + */ + private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 5; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK; + } + }; + + /** + * Injection point. + */ + public static void newPlayerResponseVideoId(String videoId) { + try { + if (!SettingsEnum.RYD_SHORTS.getBoolean()) { + return; + } + synchronized (lastVideoIds) { + if (lastVideoIds.put(videoId, Boolean.TRUE) == null) { + LogHelper.printDebug(() -> "New video id: " + videoId); + } + } + } catch (Exception ex) { + LogHelper.printException(() -> "newPlayerResponseVideoId failure", ex); + } + } + private final ByteArrayFilterGroupList videoIdFilterGroup = new ByteArrayFilterGroupList(); public ReturnYouTubeDislikeFilterPatch() { @@ -33,44 +88,46 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { FilterGroup.FilterGroupResult result = videoIdFilterGroup.check(protobufBufferArray); if (result.isFiltered()) { - // The video length must be hard coded to 11, as there is additional ASCII text that - // appears immediately after the id if the dislike button is already selected. - final int videoIdLength = 11; - final int subStringSearchStartIndex = result.getMatchedIndex() + result.getMatchedLength(); - String videoId = findSubString(protobufBufferArray, subStringSearchStartIndex, videoIdLength); - if (videoId != null) { - ReturnYouTubeDislikePatch.newVideoLoaded(videoId, true); - } + String matchedVideoId = findVideoId(protobufBufferArray); + // Matched video will be null if in incognito mode. + // Must pass a null id to correctly clear out the current video data. + // Otherwise if a Short is opened in non-incognito, then incognito is enabled and another Short is opened, + // the new incognito Short will show the old prior data. + ReturnYouTubeDislikePatch.newVideoLoaded(matchedVideoId, true); } return false; } - /** - * Find an exact length ASCII substring starting from a given index. - * - * Similar to the String finding code in {@link LithoFilterPatch}, - * but refactoring it to also handle this use case became messy and overly complicated. - */ @Nullable - private static String findSubString(byte[] buffer, int bufferStartIndex, int subStringLength) { - // Valid ASCII values (ignore control characters). - final int minimumAscii = 32; // 32 = space character - final int maximumAscii = 126; // 127 = delete character - - final int bufferLength = buffer.length; - int start = bufferStartIndex; - int end = bufferStartIndex; - do { - final int value = buffer[end]; - if (value < minimumAscii || value > maximumAscii) { - start = end + 1; - } else if (end - start == subStringLength) { - return new String(buffer, start, subStringLength, StandardCharsets.US_ASCII); + private String findVideoId(byte[] protobufBufferArray) { + synchronized (lastVideoIds) { + for (String videoId : lastVideoIds.keySet()) { + if (byteArrayContainsString(protobufBufferArray, videoId)) { + return videoId; + } } - end++; - } while (end < bufferLength); + return null; + } + } - return null; + /** + * This could use {@link TrieSearch}, but since the video ids are constantly changing + * the overhead of updating the Trie might negate the search performance gain. + */ + private static boolean byteArrayContainsString(@NonNull byte[] array, @NonNull String text) { + for (int i = 0, lastArrayStartIndex = array.length - text.length(); i <= lastArrayStartIndex; i++) { + boolean found = true; + for (int j = 0, textLength = text.length(); j < textLength; j++) { + if (array[i + j] != (byte) text.charAt(j)) { + found = false; + break; + } + } + if (found) { + return true; + } + } + return false; } -} +} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java index e4829964c4..da8cd810a9 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java @@ -74,13 +74,13 @@ public enum Vote { /** * How long to retain successful RYD fetches. */ - private static final long CACHE_TIMEOUT_SUCCESS_MILLISECONDS = 5 * 60 * 1000; // 5 Minutes + private static final long CACHE_TIMEOUT_SUCCESS_MILLISECONDS = 7 * 60 * 1000; // 7 Minutes /** * How long to retain unsuccessful RYD fetches, * and also the minimum time before retrying again. */ - private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 60 * 1000; // 1 Minute + private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 2 * 60 * 1000; // 2 Minutes /** * Unique placeholder character, used to detect if a segmented span already has dislikes added to it. @@ -140,14 +140,10 @@ public enum Vote { private final long timeFetched; /** - * If the video id is for a Short. - * Value of TRUE indicates it was previously loaded for a Short - * and FALSE indicates a regular video. - * NULL values means short status is not yet known. + * If this instance was previously used for a Short. */ - @Nullable @GuardedBy("this") - private Boolean isShort; + private boolean isShort; /** * Optional current vote status of the UI. Used to apply a user vote that was done on a previous video viewing. @@ -424,7 +420,6 @@ public String getVideoId() { /** * Pre-emptively set this as a Short. - * Should only be used immediately after creation of this instance. */ public synchronized void setVideoIdIsShort(boolean isShort) { this.isShort = isShort; @@ -458,35 +453,39 @@ private Spanned waitForFetchAndUpdateReplacementSpan(@NonNull Spanned original, } synchronized (this) { - if (isShort != null) { - if (isShort != spanIsForShort) { - // user: - // 1, opened a video - // 2. opened a short (without closing the regular video) - // 3. closed the short - // 4. regular video is now present, but the videoId and RYD data is still for the short - LogHelper.printDebug(() -> "Ignoring dislike span, as data loaded was previously" - + " used for a different video type."); - return original; - } - } else { - isShort = spanIsForShort; + if (spanIsForShort) { + // Cannot set this to false if span is not for a Short. + // When spoofing to an old version and a Short is opened while a regular video + // is on screen, this instance can be loaded for the minimized regular video. + // But this Shorts data won't be displayed for that call + // and when it is un-minimized it will reload again and the load will be ignored. + isShort = true; + } else if (isShort) { + // user: + // 1, opened a video + // 2. opened a short (without closing the regular video) + // 3. closed the short + // 4. regular video is now present, but the videoId and RYD data is still for the short + LogHelper.printDebug(() -> "Ignoring regular video dislike span," + + " as data loaded was previously used for a Short: " + videoId); + return original; } if (originalDislikeSpan != null && replacementLikeDislikeSpan != null) { if (spansHaveEqualTextAndColor(original, replacementLikeDislikeSpan)) { - LogHelper.printDebug(() -> "Ignoring previously created dislikes span"); + LogHelper.printDebug(() -> "Ignoring previously created dislikes span of data: " + videoId); return original; } if (spansHaveEqualTextAndColor(original, originalDislikeSpan)) { - LogHelper.printDebug(() -> "Replacing span with previously created dislike span"); + LogHelper.printDebug(() -> "Replacing span with previously created dislike span of data: " + videoId); return replacementLikeDislikeSpan; } } if (isSegmentedButton && isPreviouslyCreatedSegmentedSpan(original)) { // need to recreate using original, as original has prior outdated dislike values if (originalDislikeSpan == null) { - LogHelper.printDebug(() -> "Cannot add dislikes - original span is null"); // should never happen + // Should never happen. + LogHelper.printDebug(() -> "Cannot add dislikes - original span is null. videoId: " + videoId); return original; } original = originalDislikeSpan; @@ -514,10 +513,10 @@ public void sendVote(@NonNull Vote vote) { ReVancedUtils.verifyOnMainThread(); Objects.requireNonNull(vote); try { - if (isShort != null && isShort != PlayerType.getCurrent().isNoneOrHidden()) { + if (isShort != PlayerType.getCurrent().isNoneOrHidden()) { // Shorts was loaded with regular video present, then Shorts was closed. // and then user voted on the now visible original video. - // Cannot send a vote, because the loaded videoId is for the wrong video. + // Cannot send a vote, because this instance is for the wrong video. ReVancedUtils.showToastLong(str("revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted")); return; } diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java b/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java index 711d0f20e0..45fffc2cef 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java @@ -20,6 +20,10 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment { + private static final boolean IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER = + SettingsEnum.SPOOF_APP_VERSION.getBoolean() + && SettingsEnum.SPOOF_APP_VERSION_TARGET.getString().compareTo("18.33.40") <= 0; + /** * If dislikes are shown on Shorts. */ @@ -74,7 +78,11 @@ public void onCreate(Bundle savedInstanceState) { shortsPreference = new SwitchPreference(context); shortsPreference.setChecked(SettingsEnum.RYD_SHORTS.getBoolean()); shortsPreference.setTitle(str("revanced_ryd_shorts_title")); - shortsPreference.setSummaryOn(str("revanced_ryd_shorts_summary_on")); + String shortsSummary = str("revanced_ryd_shorts_summary_on", + IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER + ? "" + : "\n\n" + str("revanced_ryd_shorts_summary_disclaimer")); + shortsPreference.setSummaryOn(shortsSummary); shortsPreference.setSummaryOff(str("revanced_ryd_shorts_summary_off")); shortsPreference.setOnPreferenceChangeListener((pref, newValue) -> { SettingsEnum.RYD_SHORTS.saveValue(newValue); diff --git a/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt b/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt index a8dec9ccec..e2777c867c 100644 --- a/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt +++ b/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt @@ -17,6 +17,8 @@ enum class PlayerType { */ HIDDEN, /** + * A regular video is minimized. + * * When spoofing to 16.x YouTube and watching a short with a regular video in the background, * the type can be this (and not [HIDDEN]). */ @@ -26,7 +28,9 @@ enum class PlayerType { WATCH_WHILE_SLIDING_MAXIMIZED_FULLSCREEN, WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED, /** - * When opening a short while a regular video is minimized, the type can momentarily be this. + * Player is either sliding to [HIDDEN] state because a Short was opened while a regular video is on screen. + * OR + * The user has swiped a minimized player away to be closed (and no Short is being opened). */ WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED, WATCH_WHILE_SLIDING_FULLSCREEN_DISMISSED, @@ -84,20 +88,38 @@ enum class PlayerType { return this == NONE || this == HIDDEN } + /** + * Check if the current player type is + * [NONE], [HIDDEN], [WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED]. + * + * Useful to check if a Short is being played or opened. + * + * Usually covers all use cases with no false positives, except if called from some hooks + * when spoofing to an old version this will return false even + * though a Short is being opened or is on screen (see [isNoneHiddenOrMinimized]). + * + * @return If nothing, a Short, or a regular video is sliding off screen to a dismissed or hidden state. + */ + fun isNoneHiddenOrSlidingMinimized(): Boolean { + return isNoneOrHidden() || this == WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED + } + /** * Check if the current player type is * [NONE], [HIDDEN], [WATCH_WHILE_MINIMIZED], [WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED]. * * Useful to check if a Short is being played, - * although will return false positive if a regular video is opened and minimized (and no short is playing). + * although will return false positive if a regular video is + * opened and minimized (and a Short is not playing or being opened). * - * @return If nothing, a Short, - * or a regular video is minimized video or sliding off screen to a dismissed or hidden state. + * Typically used to detect if a Short is playing when the player cannot be in a minimized state, + * such as the user interacting with a button or element of the player. + * + * @return If nothing, a Short, a regular video is sliding off screen to a dismissed or hidden state, + * a regular video is minimized (and a new video is not being opened). */ fun isNoneHiddenOrMinimized(): Boolean { - return this == NONE || this == HIDDEN - || this == WATCH_WHILE_MINIMIZED - || this == WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED + return isNoneHiddenOrSlidingMinimized() || this == WATCH_WHILE_MINIMIZED } } \ No newline at end of file From b25ab1a0d860cb35ee3b1d16231480c288c5f560 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 12 Oct 2023 09:31:39 +0000 Subject: [PATCH 44/53] chore(release): 0.119.2-dev.1 [skip ci] ## [0.119.2-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.1...v0.119.2-dev.1) (2023-10-12) ### Bug Fixes * **YouTube - ReturnYouTubeDislike:** Fix dislikes not showing on Shorts ([#495](https://github.com/ReVanced/revanced-integrations/issues/495)) ([9b2add7](https://github.com/ReVanced/revanced-integrations/commit/9b2add7553488436c63fa14bd62966dfb92705bf)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 566dc59ec9..728a238139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.119.2-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.1...v0.119.2-dev.1) (2023-10-12) + + +### Bug Fixes + +* **YouTube - ReturnYouTubeDislike:** Fix dislikes not showing on Shorts ([#495](https://github.com/ReVanced/revanced-integrations/issues/495)) ([9b2add7](https://github.com/ReVanced/revanced-integrations/commit/9b2add7553488436c63fa14bd62966dfb92705bf)) + ## [0.119.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.0...v0.119.1) (2023-10-09) diff --git a/gradle.properties b/gradle.properties index d9a7d70ee7..367d6e6ab5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.1 +version = 0.119.2-dev.1 From f7e99832fda33a7b1c0c8a10210560e020c191e6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 12 Oct 2023 21:28:19 +0000 Subject: [PATCH 45/53] chore(release): 0.119.2 [skip ci] ## [0.119.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.1...v0.119.2) (2023-10-12) ### Bug Fixes * **YouTube - ReturnYouTubeDislike:** Fix dislikes not showing on Shorts ([#495](https://github.com/ReVanced/revanced-integrations/issues/495)) ([9b2add7](https://github.com/ReVanced/revanced-integrations/commit/9b2add7553488436c63fa14bd62966dfb92705bf)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 728a238139..a225f11bdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.119.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.1...v0.119.2) (2023-10-12) + + +### Bug Fixes + +* **YouTube - ReturnYouTubeDislike:** Fix dislikes not showing on Shorts ([#495](https://github.com/ReVanced/revanced-integrations/issues/495)) ([9b2add7](https://github.com/ReVanced/revanced-integrations/commit/9b2add7553488436c63fa14bd62966dfb92705bf)) + ## [0.119.2-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.1...v0.119.2-dev.1) (2023-10-12) diff --git a/gradle.properties b/gradle.properties index 367d6e6ab5..e75081b5d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.2-dev.1 +version = 0.119.2 From 9670bd305b3b9bbbc900af3b64152aaac125ec14 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 13 Oct 2023 17:13:47 +0200 Subject: [PATCH 46/53] fix(YouTube - Hide layout components): Hide new channel watermark component --- .../patches/BrandingWaterMarkPatch.java | 11 ----------- .../patches/components/LayoutComponentsFilter.java | 13 ++++++++++++- .../integrations/settings/SettingsEnum.java | 3 +++ 3 files changed, 15 insertions(+), 12 deletions(-) delete mode 100644 app/src/main/java/app/revanced/integrations/patches/BrandingWaterMarkPatch.java diff --git a/app/src/main/java/app/revanced/integrations/patches/BrandingWaterMarkPatch.java b/app/src/main/java/app/revanced/integrations/patches/BrandingWaterMarkPatch.java deleted file mode 100644 index e729e153fd..0000000000 --- a/app/src/main/java/app/revanced/integrations/patches/BrandingWaterMarkPatch.java +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.integrations.patches; - -import app.revanced.integrations.settings.SettingsEnum; - -public class BrandingWaterMarkPatch { - - // Used by: app.revanced.patches.youtube.layout.watermark.patch.HideWatermarkPatch - public static boolean isBrandingWatermarkShown() { - return SettingsEnum.HIDE_VIDEO_WATERMARK.getBoolean() == false; - } -} diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index 4ee419d38d..fa1d9b3696 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -175,11 +175,17 @@ public LayoutComponentsFilter() { "chips_shelf" ); + final var channelWatermark = new StringFilterGroup( + SettingsEnum.HIDE_VIDEO_CHANNEL_WATERMARK, + "featured_channel_watermark_overlay" + ); + this.pathFilterGroupList.addAll( channelBar, communityPosts, paidContent, latestPosts, + channelWatermark, communityGuidelines, quickActions, expandableMetadata, @@ -211,6 +217,8 @@ public LayoutComponentsFilter() { public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + // The groups are excluded from the filter due to the exceptions list below. + // Filter them separately here. if (matchedGroup == notifyMe || matchedGroup == inFeedSurvey) return true; if (matchedGroup != custom && exceptions.matches(path)) @@ -225,7 +233,6 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto /** * Injection point. - * * Called from a different place then the other filters. */ public static boolean filterMixPlaylists(final byte[] bytes) { @@ -236,4 +243,8 @@ public static boolean filterMixPlaylists(final byte[] bytes) { return isMixPlaylistFiltered; } + + public static boolean showWatermark() { + return !SettingsEnum.HIDE_VIDEO_CHANNEL_WATERMARK.getBoolean(); + } } diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 3affe38447..0d72259bd8 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -123,6 +123,7 @@ public enum SettingsEnum { HIDE_SUBSCRIPTIONS_BUTTON("revanced_hide_subscriptions_button", BOOLEAN, FALSE, true), HIDE_TIMESTAMP("revanced_hide_timestamp", BOOLEAN, FALSE), HIDE_VIDEO_WATERMARK("revanced_hide_video_watermark", BOOLEAN, TRUE), + HIDE_VIDEO_CHANNEL_WATERMARK("revanced_hide_channel_watermark", BOOLEAN, TRUE), PLAYER_POPUP_PANELS("revanced_hide_player_popup_panels", BOOLEAN, FALSE), SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON("revanced_switch_create_with_notifications_button", BOOLEAN, TRUE, true), SPOOF_APP_VERSION("revanced_spoof_app_version", BOOLEAN, FALSE, true, "revanced_spoof_app_version_user_dialog_message"), @@ -374,6 +375,8 @@ private static void loadAllSettings() { // region Migration + migrateOldSettingToNew(HIDE_VIDEO_WATERMARK, HIDE_VIDEO_CHANNEL_WATERMARK); + // Do _not_ delete this SB private user id migration property until sometime in 2024. // This is the only setting that cannot be reconfigured if lost, // and more time should be given for users who rarely upgrade. From 4f50ac6c492e6b0972d1896c801300bb6282f690 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 13 Oct 2023 15:17:50 +0000 Subject: [PATCH 47/53] chore(release): 0.119.3-dev.1 [skip ci] ## [0.119.3-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.2...v0.119.3-dev.1) (2023-10-13) ### Bug Fixes * **YouTube - Hide layout components:** Hide new channel watermark component ([9670bd3](https://github.com/ReVanced/revanced-integrations/commit/9670bd305b3b9bbbc900af3b64152aaac125ec14)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a225f11bdd..3e93805773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.119.3-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.2...v0.119.3-dev.1) (2023-10-13) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Hide new channel watermark component ([9670bd3](https://github.com/ReVanced/revanced-integrations/commit/9670bd305b3b9bbbc900af3b64152aaac125ec14)) + ## [0.119.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.1...v0.119.2) (2023-10-12) diff --git a/gradle.properties b/gradle.properties index e75081b5d9..8f0a1db4bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.2 +version = 0.119.3-dev.1 From 6f79746d788f196f3aa63b8e7c24b7f15ecd3f50 Mon Sep 17 00:00:00 2001 From: nullptr <107796137+johnconner122@users.noreply.github.com> Date: Fri, 13 Oct 2023 20:18:42 +0500 Subject: [PATCH 48/53] fix(YouTube - Hide Layout components): Exempt expandable chips from exceptions (#498) Co-authored-by: oSumAtrIX --- .../patches/components/LayoutComponentsFilter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index fa1d9b3696..a5882d2210 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -22,6 +22,7 @@ public final class LayoutComponentsFilter extends Filter { private final StringFilterGroup searchResultShelfHeader; private final StringFilterGroup inFeedSurvey; private final StringFilterGroup notifyMe; + private final StringFilterGroup expandableMetadata; @RequiresApi(api = Build.VERSION_CODES.N) public LayoutComponentsFilter() { @@ -114,7 +115,7 @@ public LayoutComponentsFilter() { "official_card" ); - final var expandableMetadata = new StringFilterGroup( + expandableMetadata = new StringFilterGroup( SettingsEnum.HIDE_EXPANDABLE_CHIP, "inline_expander" ); @@ -219,7 +220,8 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto // The groups are excluded from the filter due to the exceptions list below. // Filter them separately here. - if (matchedGroup == notifyMe || matchedGroup == inFeedSurvey) return true; + if (matchedGroup == notifyMe || matchedGroup == inFeedSurvey || matchedGroup == expandableMetadata) + return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); if (matchedGroup != custom && exceptions.matches(path)) return false; // Exceptions are not filtered. From d97b390866bd33d831094c16c18f32edc0294d1e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 13 Oct 2023 15:23:09 +0000 Subject: [PATCH 49/53] chore(release): 0.119.3-dev.2 [skip ci] ## [0.119.3-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.3-dev.1...v0.119.3-dev.2) (2023-10-13) ### Bug Fixes * **YouTube - Hide Layout components:** Exempt expandable chips from exceptions ([#498](https://github.com/ReVanced/revanced-integrations/issues/498)) ([6f79746](https://github.com/ReVanced/revanced-integrations/commit/6f79746d788f196f3aa63b8e7c24b7f15ecd3f50)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e93805773..3c60861d5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.119.3-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.3-dev.1...v0.119.3-dev.2) (2023-10-13) + + +### Bug Fixes + +* **YouTube - Hide Layout components:** Exempt expandable chips from exceptions ([#498](https://github.com/ReVanced/revanced-integrations/issues/498)) ([6f79746](https://github.com/ReVanced/revanced-integrations/commit/6f79746d788f196f3aa63b8e7c24b7f15ecd3f50)) + ## [0.119.3-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.2...v0.119.3-dev.1) (2023-10-13) diff --git a/gradle.properties b/gradle.properties index 8f0a1db4bb..d1b854e574 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.3-dev.1 +version = 0.119.3-dev.2 From fd09e46d01c820632cfe440dac34f5cd957e793d Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 14 Oct 2023 01:00:25 +0200 Subject: [PATCH 50/53] feat(YouTube - Theme): Disable gradient loading screen --- .../{ThemeLithoComponentsPatch.java => ThemePatch.java} | 7 ++++++- .../app/revanced/integrations/settings/SettingsEnum.java | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) rename app/src/main/java/app/revanced/integrations/patches/theme/{ThemeLithoComponentsPatch.java => ThemePatch.java} (90%) diff --git a/app/src/main/java/app/revanced/integrations/patches/theme/ThemeLithoComponentsPatch.java b/app/src/main/java/app/revanced/integrations/patches/theme/ThemePatch.java similarity index 90% rename from app/src/main/java/app/revanced/integrations/patches/theme/ThemeLithoComponentsPatch.java rename to app/src/main/java/app/revanced/integrations/patches/theme/ThemePatch.java index da9f3963c4..e9796db250 100644 --- a/app/src/main/java/app/revanced/integrations/patches/theme/ThemeLithoComponentsPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/theme/ThemePatch.java @@ -1,9 +1,10 @@ package app.revanced.integrations.patches.theme; +import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.ThemeHelper; -public class ThemeLithoComponentsPatch { +public class ThemePatch { // color constants used in relation with litho components private static final int[] WHITE_VALUES = { -1, // comments chip background @@ -40,6 +41,10 @@ public static int getValue(int originalValue) { return originalValue; } + public static boolean gradientLoadingScreenEnabled() { + return SettingsEnum.GRADIENT_LOADING_SCREEN.getBoolean(); + } + private static int getBlackColor() { if (blackColor == 0) blackColor = ReVancedUtils.getResourceColor("yt_black1"); return blackColor; diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 0d72259bd8..6b8c18a386 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -131,6 +131,7 @@ public enum SettingsEnum { USE_TABLET_MINIPLAYER("revanced_tablet_miniplayer", BOOLEAN, FALSE, true), TABLET_LAYOUT("revanced_tablet_layout", BOOLEAN, FALSE, true, "revanced_tablet_layout_user_dialog_message"), WIDE_SEARCHBAR("revanced_wide_searchbar", BOOLEAN, FALSE, true), + GRADIENT_LOADING_SCREEN("revanced_gradient_loading_screen", BOOLEAN, FALSE), SEEKBAR_CUSTOM_COLOR("revanced_seekbar_custom_color", BOOLEAN, TRUE, true), SEEKBAR_CUSTOM_COLOR_VALUE("revanced_seekbar_custom_color_value", STRING, "#FF0000", true, parents(SEEKBAR_CUSTOM_COLOR)), HIDE_FILTER_BAR_FEED_IN_FEED("revanced_hide_filter_bar_feed_in_feed", BOOLEAN, FALSE, true), From cc3c9e78b2eec6999da394f9cac217a78fd0fad5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 13 Oct 2023 23:04:08 +0000 Subject: [PATCH 51/53] chore(release): 0.120.0-dev.1 [skip ci] # [0.120.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.3-dev.2...v0.120.0-dev.1) (2023-10-13) ### Features * **YouTube - Theme:** Disable gradient loading screen ([fd09e46](https://github.com/ReVanced/revanced-integrations/commit/fd09e46d01c820632cfe440dac34f5cd957e793d)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c60861d5d..e2aa025841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.120.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.3-dev.2...v0.120.0-dev.1) (2023-10-13) + + +### Features + +* **YouTube - Theme:** Disable gradient loading screen ([fd09e46](https://github.com/ReVanced/revanced-integrations/commit/fd09e46d01c820632cfe440dac34f5cd957e793d)) + ## [0.119.3-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.119.3-dev.1...v0.119.3-dev.2) (2023-10-13) diff --git a/gradle.properties b/gradle.properties index d1b854e574..a5f158fe48 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.119.3-dev.2 +version = 0.120.0-dev.1 From 7d02774ea192510e692e90ae55a86e25ee321926 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 14 Oct 2023 11:16:41 +0300 Subject: [PATCH 52/53] fix(YouTube - Minimized playback): Fix pip incorrectly showing if app is minimized immediately after opening a Short --- .../revanced/integrations/patches/MinimizedPlaybackPatch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/MinimizedPlaybackPatch.java b/app/src/main/java/app/revanced/integrations/patches/MinimizedPlaybackPatch.java index e7f8af3608..6fcae6bfc5 100644 --- a/app/src/main/java/app/revanced/integrations/patches/MinimizedPlaybackPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/MinimizedPlaybackPatch.java @@ -5,7 +5,7 @@ public class MinimizedPlaybackPatch { public static boolean isPlaybackNotShort() { - return !PlayerType.getCurrent().isNoneOrHidden(); + return !PlayerType.getCurrent().isNoneHiddenOrSlidingMinimized(); } public static boolean overrideMinimizedPlaybackAvailable() { From 12e663c548c17a3b338227809b7a88ddb3c30c44 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 14 Oct 2023 08:20:25 +0000 Subject: [PATCH 53/53] chore(release): 0.120.0-dev.2 [skip ci] # [0.120.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.120.0-dev.1...v0.120.0-dev.2) (2023-10-14) ### Bug Fixes * **YouTube - Minimized playback:** Fix pip incorrectly showing if app is minimized immediately after opening a Short ([7d02774](https://github.com/ReVanced/revanced-integrations/commit/7d02774ea192510e692e90ae55a86e25ee321926)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2aa025841..3efb9c6e0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.120.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.120.0-dev.1...v0.120.0-dev.2) (2023-10-14) + + +### Bug Fixes + +* **YouTube - Minimized playback:** Fix pip incorrectly showing if app is minimized immediately after opening a Short ([7d02774](https://github.com/ReVanced/revanced-integrations/commit/7d02774ea192510e692e90ae55a86e25ee321926)) + # [0.120.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.119.3-dev.2...v0.120.0-dev.1) (2023-10-13) diff --git a/gradle.properties b/gradle.properties index a5f158fe48..4b4fb3abb7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.120.0-dev.1 +version = 0.120.0-dev.2