You've already forked revanced-integrations
mirror of
https://github.com/revanced/revanced-integrations
synced 2025-11-21 18:35:37 +01:00
Compare commits
7 Commits
v0.121.0-d
...
v0.121.0-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21bccf6a99 | ||
|
|
40cfa1e9af | ||
|
|
0fbf7a3434 | ||
|
|
6bd5aae977 | ||
|
|
bf5071107b | ||
|
|
8cbb50b8ed | ||
|
|
98c91af130 |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,3 +1,25 @@
|
||||
# [0.121.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.3...v0.121.0-dev.4) (2023-10-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - ReturnYouTubeDislike:** Use API back off if client connection fails for any reason ([#509](https://github.com/ReVanced/revanced-integrations/issues/509)) ([40cfa1e](https://github.com/ReVanced/revanced-integrations/commit/40cfa1e9af2b064b464c4d03d5c28b5932621d62))
|
||||
|
||||
# [0.121.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.2...v0.121.0-dev.3) (2023-10-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Add `Disable fullscreen ambient mode` patch ([bf50711](https://github.com/ReVanced/revanced-integrations/commit/bf5071107b8bc88ac6562d45bfa28bdab8e566c7))
|
||||
* **YouTube:** Add `Disable suggested video end screen` patch ([6bd5aae](https://github.com/ReVanced/revanced-integrations/commit/6bd5aae9772e80809dbee9f8fffc1247364a9a13))
|
||||
|
||||
# [0.121.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.1...v0.121.0-dev.2) (2023-10-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - ReturnYouTubeDislike:** Fix RYD prefetching home feed Shorts ([#508](https://github.com/ReVanced/revanced-integrations/issues/508)) ([98c91af](https://github.com/ReVanced/revanced-integrations/commit/98c91af130b57322aa98a3e66ec0acad26bfc7d6))
|
||||
|
||||
# [0.121.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.120.1-dev.3...v0.121.0-dev.1) (2023-10-23)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
/** @noinspection unused*/
|
||||
public final class DisableFullscreenAmbientModePatch {
|
||||
public static boolean enableFullScreenAmbientMode() {
|
||||
return !SettingsEnum.DISABLE_FULLSCREEN_AMBIENT_MODE.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.widget.ImageView;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
/** @noinspection unused*/
|
||||
public final class DisableSuggestedVideoEndScreenPatch {
|
||||
public static void closeEndScreen(ImageView imageView) {
|
||||
if (!SettingsEnum.DISABLE_SUGGESTED_VIDEO_END_SCREEN.getBoolean()) return;
|
||||
|
||||
imageView.performClick();
|
||||
}
|
||||
}
|
||||
@@ -404,11 +404,14 @@ public class ReturnYouTubeDislikePatch {
|
||||
/**
|
||||
* Injection point. Uses 'playback response' video id hook to preload RYD.
|
||||
*/
|
||||
public static void preloadVideoId(@NonNull String videoId) {
|
||||
if (!SettingsEnum.RYD_ENABLED.getBoolean()) {
|
||||
public static void preloadVideoId(@NonNull String videoId, boolean videoIsOpeningOrPlaying) {
|
||||
// Shorts shelf in home and subscription feed causes player response hook to be called,
|
||||
// and the 'is opening/playing' parameter will be false.
|
||||
// This hook will be called again when the Short is actually opened.
|
||||
if (!videoIsOpeningOrPlaying || !SettingsEnum.RYD_ENABLED.getBoolean()) {
|
||||
return;
|
||||
}
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneOrHidden()) {
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneHiddenOrSlidingMinimized()) {
|
||||
return;
|
||||
}
|
||||
if (videoId.equals(lastPrefetchedVideoId)) {
|
||||
@@ -471,12 +474,13 @@ public class ReturnYouTubeDislikePatch {
|
||||
if (videoIdIsSame(currentVideoData, videoId)) {
|
||||
return;
|
||||
}
|
||||
currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId);
|
||||
ReturnYouTubeDislike data = 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);
|
||||
data.setVideoIdIsShort(true);
|
||||
}
|
||||
currentVideoData = data;
|
||||
}
|
||||
|
||||
LogHelper.printDebug(() -> "New video id: " + videoId + " playerType: " + currentPlayerType
|
||||
|
||||
@@ -69,7 +69,7 @@ public final class VideoInformation {
|
||||
*
|
||||
* @param videoId The id of the last video loaded.
|
||||
*/
|
||||
public static void setPlayerResponseVideoId(@NonNull String videoId) {
|
||||
public static void setPlayerResponseVideoId(@NonNull String videoId, boolean videoIsOpeningOrPlaying) {
|
||||
if (!playerResponseVideoId.equals(videoId)) {
|
||||
LogHelper.printDebug(() -> "New player response video id: " + videoId);
|
||||
playerResponseVideoId = videoId;
|
||||
|
||||
@@ -53,9 +53,9 @@ public final class ReturnYouTubeDislikeFilterPatch extends Filter {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void newPlayerResponseVideoId(String videoId) {
|
||||
public static void newPlayerResponseVideoId(String videoId, boolean videoIsOpeningOrPlaying) {
|
||||
try {
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
if (!videoIsOpeningOrPlaying || !SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
return;
|
||||
}
|
||||
synchronized (lastVideoIds) {
|
||||
|
||||
@@ -80,7 +80,7 @@ public class ReturnYouTubeDislike {
|
||||
* How long to retain unsuccessful RYD fetches,
|
||||
* and also the minimum time before retrying again.
|
||||
*/
|
||||
private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 2 * 60 * 1000; // 2 Minutes
|
||||
private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 3 * 60 * 1000; // 3 Minutes
|
||||
|
||||
/**
|
||||
* Unique placeholder character, used to detect if a segmented span already has dislikes added to it.
|
||||
|
||||
@@ -32,13 +32,13 @@ public class ReturnYouTubeDislikeApi {
|
||||
/**
|
||||
* {@link #fetchVotes(String)} TCP connection timeout
|
||||
*/
|
||||
private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2000;
|
||||
private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2 * 1000; // 2 Seconds.
|
||||
|
||||
/**
|
||||
* {@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 = 5000;
|
||||
private static final int API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS = 5 * 1000; // 5 Seconds.
|
||||
|
||||
/**
|
||||
* Default connection and response timeout for voting and registration.
|
||||
@@ -46,7 +46,7 @@ public class ReturnYouTubeDislikeApi {
|
||||
* Voting and user registration runs in the background and has has no urgency
|
||||
* so this can be a larger value.
|
||||
*/
|
||||
private static final int API_REGISTER_VOTE_TIMEOUT_MILLISECONDS = 90000;
|
||||
private static final int API_REGISTER_VOTE_TIMEOUT_MILLISECONDS = 60 * 1000; // 60 Seconds.
|
||||
|
||||
/**
|
||||
* Response code of a successful API call
|
||||
@@ -54,31 +54,30 @@ public class ReturnYouTubeDislikeApi {
|
||||
private static final int HTTP_STATUS_CODE_SUCCESS = 200;
|
||||
|
||||
/**
|
||||
* Response code indicating the video id is not for a video that can be voted for.
|
||||
* (it's not a Short or a regular video, and it's likely a YouTube Story)
|
||||
* Indicates a client rate limit has been reached and the client must back off.
|
||||
*/
|
||||
private static final int HTTP_STATUS_CODE_NOT_FOUND = 404;
|
||||
private static final int HTTP_STATUS_CODE_RATE_LIMIT = 429;
|
||||
|
||||
/**
|
||||
* Indicates a client rate limit has been reached
|
||||
* How long to wait until API calls are resumed, if the API requested a back off.
|
||||
* No clear guideline of how long to wait until resuming.
|
||||
*/
|
||||
private static final int RATE_LIMIT_HTTP_STATUS_CODE = 429;
|
||||
private static final int BACKOFF_RATE_LIMIT_MILLISECONDS = 4 * 60 * 1000; // 4 Minutes.
|
||||
|
||||
/**
|
||||
* How long to wait until API calls are resumed, if a rate limit is hit.
|
||||
* No clear guideline of how long to backoff. Using 2 minutes for now.
|
||||
* How long to wait until API calls are resumed, if any connection error occurs.
|
||||
*/
|
||||
private static final int RATE_LIMIT_BACKOFF_SECONDS = 120;
|
||||
private static final int BACKOFF_CONNECTION_ERROR_MILLISECONDS = 60 * 1000; // 60 Seconds.
|
||||
|
||||
/**
|
||||
* Last time a {@link #RATE_LIMIT_HTTP_STATUS_CODE} was reached.
|
||||
* zero if has not been reached.
|
||||
* If non zero, then the system time of when API calls can resume.
|
||||
*/
|
||||
private static volatile long lastTimeRateLimitWasHit; // must be volatile, since different threads read/write to this
|
||||
private static volatile long timeToResumeAPICalls; // must be volatile, since different threads read/write to this
|
||||
|
||||
/**
|
||||
* Number of times {@link #RATE_LIMIT_HTTP_STATUS_CODE} was requested by RYD api.
|
||||
* Does not include network calls attempted while rate limit is in effect
|
||||
* Number of times {@link #HTTP_STATUS_CODE_RATE_LIMIT} was requested by RYD api.
|
||||
* Does not include network calls attempted while rate limit is in effect,
|
||||
* and does not include rate limit imposed if a fetch fails.
|
||||
*/
|
||||
private static volatile int numberOfRateLimitRequestsEncountered;
|
||||
|
||||
@@ -165,16 +164,16 @@ public class ReturnYouTubeDislikeApi {
|
||||
* @return True, if api rate limit is in effect.
|
||||
*/
|
||||
private static boolean checkIfRateLimitInEffect(String apiEndPointName) {
|
||||
if (lastTimeRateLimitWasHit == 0) {
|
||||
if (timeToResumeAPICalls == 0) {
|
||||
return false;
|
||||
}
|
||||
final long numberOfSecondsSinceLastRateLimit = (System.currentTimeMillis() - lastTimeRateLimitWasHit) / 1000;
|
||||
if (numberOfSecondsSinceLastRateLimit < RATE_LIMIT_BACKOFF_SECONDS) {
|
||||
LogHelper.printDebug(() -> "Ignoring api call " + apiEndPointName + " as only "
|
||||
+ numberOfSecondsSinceLastRateLimit + " seconds has passed since last rate limit.");
|
||||
return true;
|
||||
final long now = System.currentTimeMillis();
|
||||
if (now > timeToResumeAPICalls) {
|
||||
timeToResumeAPICalls = 0;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
LogHelper.printDebug(() -> "Ignoring api call " + apiEndPointName + " as rate limit is in effect");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,37 +185,33 @@ public class ReturnYouTubeDislikeApi {
|
||||
final double RANDOM_RATE_LIMIT_PERCENTAGE = 0.2; // 20% chance of a triggering a rate limit
|
||||
if (Math.random() < RANDOM_RATE_LIMIT_PERCENTAGE) {
|
||||
LogHelper.printDebug(() -> "Artificially triggering rate limit for debug purposes");
|
||||
httpResponseCode = RATE_LIMIT_HTTP_STATUS_CODE;
|
||||
httpResponseCode = HTTP_STATUS_CODE_RATE_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (httpResponseCode == RATE_LIMIT_HTTP_STATUS_CODE) {
|
||||
lastTimeRateLimitWasHit = System.currentTimeMillis();
|
||||
//noinspection NonAtomicOperationOnVolatileField // don't care, field is used only as an estimate
|
||||
numberOfRateLimitRequestsEncountered++;
|
||||
LogHelper.printDebug(() -> "API rate limit was hit. Stopping API calls for the next "
|
||||
+ RATE_LIMIT_BACKOFF_SECONDS + " seconds");
|
||||
ReVancedUtils.showToastLong(str("revanced_ryd_failure_client_rate_limit_requested"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return httpResponseCode == HTTP_STATUS_CODE_RATE_LIMIT;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NonAtomicOperationOnVolatileField") // do not want to pay performance cost of full synchronization for debug fields that are only estimates anyways
|
||||
private static void updateStatistics(long timeNetworkCallStarted, long timeNetworkCallEnded, boolean connectionError, boolean rateLimitHit) {
|
||||
@SuppressWarnings("NonAtomicOperationOnVolatileField") // Don't care, fields are estimates.
|
||||
private static void updateRateLimitAndStats(long timeNetworkCallStarted, boolean connectionError, boolean rateLimitHit) {
|
||||
if (connectionError && rateLimitHit) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
final long responseTimeOfFetchCall = timeNetworkCallEnded - timeNetworkCallStarted;
|
||||
final long responseTimeOfFetchCall = System.currentTimeMillis() - timeNetworkCallStarted;
|
||||
fetchCallResponseTimeTotal += responseTimeOfFetchCall;
|
||||
fetchCallResponseTimeMin = (fetchCallResponseTimeMin == 0) ? responseTimeOfFetchCall : Math.min(responseTimeOfFetchCall, fetchCallResponseTimeMin);
|
||||
fetchCallResponseTimeMax = Math.max(responseTimeOfFetchCall, fetchCallResponseTimeMax);
|
||||
fetchCallCount++;
|
||||
if (connectionError) {
|
||||
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_CONNECTION_ERROR_MILLISECONDS;
|
||||
fetchCallResponseTimeLast = responseTimeOfFetchCall;
|
||||
fetchCallNumberOfFailures++;
|
||||
} else if (rateLimitHit) {
|
||||
LogHelper.printDebug(() -> "API rate limit was hit. Stopping API calls for the next "
|
||||
+ BACKOFF_RATE_LIMIT_MILLISECONDS + " seconds");
|
||||
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_RATE_LIMIT_MILLISECONDS;
|
||||
numberOfRateLimitRequestsEncountered++;
|
||||
fetchCallResponseTimeLast = FETCH_CALL_RESPONSE_TIME_VALUE_RATE_LIMIT;
|
||||
ReVancedUtils.showToastLong(str("revanced_ryd_failure_client_rate_limit_requested"));
|
||||
} else {
|
||||
fetchCallResponseTimeLast = responseTimeOfFetchCall;
|
||||
}
|
||||
@@ -262,27 +257,22 @@ public class ReturnYouTubeDislikeApi {
|
||||
final int responseCode = connection.getResponseCode();
|
||||
if (checkIfRateLimitWasHit(responseCode)) {
|
||||
connection.disconnect(); // rate limit hit, should disconnect
|
||||
updateStatistics(timeNetworkCallStarted, System.currentTimeMillis(),false, true);
|
||||
updateRateLimitAndStats(timeNetworkCallStarted, false, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
|
||||
final long timeNetworkCallEnded = System.currentTimeMillis(); // record end time before parsing
|
||||
// do not disconnect, the same server connection will likely be used again soon
|
||||
JSONObject json = Requester.parseJSONObject(connection);
|
||||
try {
|
||||
RYDVoteData votingData = new RYDVoteData(json);
|
||||
updateStatistics(timeNetworkCallStarted, timeNetworkCallEnded, false, false);
|
||||
updateRateLimitAndStats(timeNetworkCallStarted, false, false);
|
||||
LogHelper.printDebug(() -> "Voting data fetched: " + votingData);
|
||||
return votingData;
|
||||
} catch (JSONException ex) {
|
||||
LogHelper.printException(() -> "Failed to parse video: " + videoId + " json: " + json, ex);
|
||||
// fall thru to update statistics
|
||||
}
|
||||
} else if (responseCode == HTTP_STATUS_CODE_NOT_FOUND) {
|
||||
// normal response when viewing YouTube Stories (cannot vote for these)
|
||||
LogHelper.printDebug(() -> "Video has no like/dislikes (video is a YouTube Story?): " + videoId);
|
||||
return null; // do not updated connection statistics
|
||||
} else {
|
||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
||||
}
|
||||
@@ -296,7 +286,7 @@ public class ReturnYouTubeDislikeApi {
|
||||
LogHelper.printException(() -> "Failed to fetch votes", ex, str("revanced_ryd_failure_generic", ex.getMessage()));
|
||||
}
|
||||
|
||||
updateStatistics(timeNetworkCallStarted, System.currentTimeMillis(), true, false);
|
||||
updateRateLimitAndStats(timeNetworkCallStarted, true, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -311,7 +301,7 @@ public class ReturnYouTubeDislikeApi {
|
||||
return null;
|
||||
}
|
||||
String userId = randomString(36);
|
||||
LogHelper.printDebug(() -> "Trying to register new user: " + userId);
|
||||
LogHelper.printDebug(() -> "Trying to register new user");
|
||||
|
||||
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_REGISTRATION, userId);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
@@ -147,7 +147,8 @@ public enum SettingsEnum {
|
||||
HIDE_SHORTS_CHANNEL_BAR("revanced_hide_shorts_channel_bar", BOOLEAN, FALSE),
|
||||
HIDE_SHORTS_NAVIGATION_BAR("revanced_hide_shorts_navigation_bar", BOOLEAN, TRUE, true),
|
||||
HIDE_SHORTS("revanced_hide_shorts", BOOLEAN, FALSE, true),
|
||||
|
||||
DISABLE_SUGGESTED_VIDEO_END_SCREEN("revanced_disable_suggested_video_end_screen", BOOLEAN, TRUE),
|
||||
DISABLE_FULLSCREEN_AMBIENT_MODE("revanced_disable_fullscreen_ambient_mode", BOOLEAN, TRUE, true),
|
||||
ALT_THUMBNAIL("revanced_alt_thumbnail", BOOLEAN, FALSE),
|
||||
ALT_THUMBNAIL_TYPE("revanced_alt_thumbnail_type", INTEGER, 2, parents(ALT_THUMBNAIL)),
|
||||
ALT_THUMBNAIL_FAST_QUALITY("revanced_alt_thumbnail_fast_quality", BOOLEAN, FALSE, parents(ALT_THUMBNAIL)),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
android.useAndroidX = true
|
||||
version = 0.121.0-dev.1
|
||||
version = 0.121.0-dev.4
|
||||
|
||||
Reference in New Issue
Block a user