fix(YouTube - ReturnYouTubeDislike): Do not retry API call if same fetch recently failed (#493)

This commit is contained in:
LisoUseInAIKyrios 2023-10-07 23:06:10 +04:00 committed by GitHub
parent 78b5fe2128
commit 486c894257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 18 deletions

View File

@ -25,6 +25,17 @@ import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislik
/** /**
* Handles all interaction of UI patch components. * 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 { public class ReturnYouTubeDislikePatch {
@ -435,10 +446,10 @@ public class ReturnYouTubeDislikePatch {
lastLithoShortsVideoData = videoData; lastLithoShortsVideoData = videoData;
lithoShortsShouldUseCurrentData = false; lithoShortsShouldUseCurrentData = false;
} else { } else {
// All other playback (including non-litho Shorts).
if (videoIdIsSame(currentVideoData, videoId)) { if (videoIdIsSame(currentVideoData, videoId)) {
return; return;
} }
// All other playback (including litho Shorts).
currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId); currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId);
} }

View File

@ -69,12 +69,18 @@ public class ReturnYouTubeDislike {
* Must be less than 5 seconds, as per: * Must be less than 5 seconds, as per:
* https://developer.android.com/topic/performance/vitals/anr * 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. * 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); ReturnYouTubeDislike fetch = fetchCache.get(videoId);
if (fetch == null || !fetch.futureInProgressOrFinishedSuccessfully()) { if (fetch == null) {
fetch = new ReturnYouTubeDislike(videoId); fetch = new ReturnYouTubeDislike(videoId);
fetchCache.put(videoId, fetch); fetchCache.put(videoId, fetch);
} }
@ -374,7 +380,15 @@ public class ReturnYouTubeDislike {
} }
private boolean isExpired(long now) { 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 @Nullable
@ -389,8 +403,11 @@ public class ReturnYouTubeDislike {
return null; 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() { private synchronized void clearUICache() {
@ -493,13 +510,6 @@ public class ReturnYouTubeDislike {
return original; return original;
} }
/**
* @return if the RYD fetch call has completed.
*/
public boolean fetchCompleted() {
return future.isDone();
}
public void sendVote(@NonNull Vote vote) { public void sendVote(@NonNull Vote vote) {
ReVancedUtils.verifyOnMainThread(); ReVancedUtils.verifyOnMainThread();
Objects.requireNonNull(vote); Objects.requireNonNull(vote);

View File

@ -35,10 +35,10 @@ public class ReturnYouTubeDislikeApi {
private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2000; private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2000;
/** /**
* {@link #fetchVotes(String)} HTTP read timeout * {@link #fetchVotes(String)} HTTP read timeout.
* To locally debug and force timeouts, change this to a very small number (ie: 100) * 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. * Default connection and response timeout for voting and registration.