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] 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 1dd5fb53..89ad8a66 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 @@ import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislik /** * 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 class ReturnYouTubeDislikePatch { 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 d68d0c1e..e4829964 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 class ReturnYouTubeDislike { * 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 class ReturnYouTubeDislike { } 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 @@ public class ReturnYouTubeDislike { } 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 class ReturnYouTubeDislike { 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 @@ public class ReturnYouTubeDislike { 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 a7e82576..f10ed821 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.