mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-26 03:42:13 +02:00
fix(YouTube - Return YouTube Dislike): Match with ReVanced (Close https://github.com/inotia00/ReVanced_Extended/issues/2611)
This commit is contained in:
parent
b171281ec5
commit
6f0958b328
@ -111,22 +111,21 @@ public final class RYDVoteData {
|
|||||||
public void updateUsingVote(Vote vote) {
|
public void updateUsingVote(Vote vote) {
|
||||||
final int likesToAdd, dislikesToAdd;
|
final int likesToAdd, dislikesToAdd;
|
||||||
|
|
||||||
switch (vote) {
|
dislikesToAdd = switch (vote) {
|
||||||
case LIKE:
|
case LIKE -> {
|
||||||
likesToAdd = 1;
|
likesToAdd = 1;
|
||||||
dislikesToAdd = 0;
|
yield 0;
|
||||||
break;
|
}
|
||||||
case DISLIKE:
|
case DISLIKE -> {
|
||||||
likesToAdd = 0;
|
likesToAdd = 0;
|
||||||
dislikesToAdd = 1;
|
yield 1;
|
||||||
break;
|
}
|
||||||
case LIKE_REMOVE:
|
case LIKE_REMOVE -> {
|
||||||
likesToAdd = 0;
|
likesToAdd = 0;
|
||||||
dislikesToAdd = 0;
|
yield 0;
|
||||||
break;
|
}
|
||||||
default:
|
default -> throw new IllegalStateException();
|
||||||
throw new IllegalStateException();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// If a video has no public likes but RYD has raw like data,
|
// If a video has no public likes but RYD has raw like data,
|
||||||
// then use the raw data instead.
|
// then use the raw data instead.
|
||||||
|
@ -27,6 +27,7 @@ import app.revanced.extension.shared.returnyoutubedislike.ReturnYouTubeDislike;
|
|||||||
import app.revanced.extension.shared.utils.Logger;
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
import app.revanced.extension.shared.utils.Utils;
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
|
||||||
|
@SuppressWarnings("All")
|
||||||
public class ReturnYouTubeDislikeApi {
|
public class ReturnYouTubeDislikeApi {
|
||||||
/**
|
/**
|
||||||
* {@link #fetchVotes(String)} TCP connection timeout
|
* {@link #fetchVotes(String)} TCP connection timeout
|
||||||
@ -81,9 +82,81 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
|
|
||||||
public static boolean toastOnConnectionError = false;
|
public static boolean toastOnConnectionError = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of network calls made in {@link #fetchVotes(String)}
|
||||||
|
*/
|
||||||
|
private static volatile int fetchCallCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of times {@link #fetchVotes(String)} failed due to timeout or any other error.
|
||||||
|
* This does not include when rate limit requests are encountered.
|
||||||
|
*/
|
||||||
|
private static volatile int fetchCallNumberOfFailures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total time spent waiting for {@link #fetchVotes(String)} network call to complete.
|
||||||
|
* Value does does not persist on app shut down.
|
||||||
|
*/
|
||||||
|
private static volatile long fetchCallResponseTimeTotal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Round trip network time for the most recent call to {@link #fetchVotes(String)}
|
||||||
|
*/
|
||||||
|
private static volatile long fetchCallResponseTimeLast;
|
||||||
|
private static volatile long fetchCallResponseTimeMin;
|
||||||
|
private static volatile long fetchCallResponseTimeMax;
|
||||||
|
|
||||||
|
public static final int FETCH_CALL_RESPONSE_TIME_VALUE_RATE_LIMIT = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If rate limit was hit, this returns {@link #FETCH_CALL_RESPONSE_TIME_VALUE_RATE_LIMIT}
|
||||||
|
*/
|
||||||
|
public static long getFetchCallResponseTimeLast() {
|
||||||
|
return fetchCallResponseTimeLast;
|
||||||
|
}
|
||||||
|
public static long getFetchCallResponseTimeMin() {
|
||||||
|
return fetchCallResponseTimeMin;
|
||||||
|
}
|
||||||
|
public static long getFetchCallResponseTimeMax() {
|
||||||
|
return fetchCallResponseTimeMax;
|
||||||
|
}
|
||||||
|
public static long getFetchCallResponseTimeAverage() {
|
||||||
|
return fetchCallCount == 0 ? 0 : (fetchCallResponseTimeTotal / fetchCallCount);
|
||||||
|
}
|
||||||
|
public static int getFetchCallCount() {
|
||||||
|
return fetchCallCount;
|
||||||
|
}
|
||||||
|
public static int getFetchCallNumberOfFailures() {
|
||||||
|
return fetchCallNumberOfFailures;
|
||||||
|
}
|
||||||
|
public static int getNumberOfRateLimitRequestsEncountered() {
|
||||||
|
return numberOfRateLimitRequestsEncountered;
|
||||||
|
}
|
||||||
|
|
||||||
private ReturnYouTubeDislikeApi() {
|
private ReturnYouTubeDislikeApi() {
|
||||||
} // utility class
|
} // utility class
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates a slow response by doing meaningless calculations.
|
||||||
|
* Used to debug the app UI and verify UI timeout logic works
|
||||||
|
*/
|
||||||
|
private static void randomlyWaitIfLocallyDebugging() {
|
||||||
|
final boolean DEBUG_RANDOMLY_DELAY_NETWORK_CALLS = false; // set true to debug UI
|
||||||
|
|
||||||
|
if (DEBUG_RANDOMLY_DELAY_NETWORK_CALLS) {
|
||||||
|
final long amountOfTimeToWaste = (long) (Math.random()
|
||||||
|
* (API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS + API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS));
|
||||||
|
Utils.doNothingForDuration(amountOfTimeToWaste);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears any backoff rate limits in effect.
|
* Clears any backoff rate limits in effect.
|
||||||
* Should be called if RYD is turned on/off.
|
* Should be called if RYD is turned on/off.
|
||||||
@ -116,41 +189,64 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
* @return True, if a client rate limit was requested
|
* @return True, if a client rate limit was requested
|
||||||
*/
|
*/
|
||||||
private static boolean checkIfRateLimitWasHit(int httpResponseCode) {
|
private static boolean checkIfRateLimitWasHit(int httpResponseCode) {
|
||||||
|
final boolean DEBUG_RATE_LIMIT = false; // set to true, to verify rate limit works
|
||||||
|
|
||||||
|
if (DEBUG_RATE_LIMIT) {
|
||||||
|
final double RANDOM_RATE_LIMIT_PERCENTAGE = 0.2; // 20% chance of a triggering a rate limit
|
||||||
|
if (Math.random() < RANDOM_RATE_LIMIT_PERCENTAGE) {
|
||||||
|
Logger.printDebug(() -> "Artificially triggering rate limit for debug purposes");
|
||||||
|
httpResponseCode = HTTP_STATUS_CODE_RATE_LIMIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
return httpResponseCode == HTTP_STATUS_CODE_RATE_LIMIT;
|
return httpResponseCode == HTTP_STATUS_CODE_RATE_LIMIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateRateLimitAndStats(boolean connectionError, boolean rateLimitHit) {
|
@SuppressWarnings("NonAtomicOperationOnVolatileField") // Don't care, fields are only estimates.
|
||||||
|
private static void updateRateLimitAndStats(long timeNetworkCallStarted, boolean connectionError, boolean rateLimitHit) {
|
||||||
if (connectionError && rateLimitHit) {
|
if (connectionError && rateLimitHit) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
final long responseTimeOfFetchCall = System.currentTimeMillis() - timeNetworkCallStarted;
|
||||||
|
fetchCallResponseTimeTotal += responseTimeOfFetchCall;
|
||||||
|
fetchCallResponseTimeMin = (fetchCallResponseTimeMin == 0) ? responseTimeOfFetchCall : Math.min(responseTimeOfFetchCall, fetchCallResponseTimeMin);
|
||||||
|
fetchCallResponseTimeMax = Math.max(responseTimeOfFetchCall, fetchCallResponseTimeMax);
|
||||||
|
fetchCallCount++;
|
||||||
if (connectionError) {
|
if (connectionError) {
|
||||||
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_CONNECTION_ERROR_MILLISECONDS;
|
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_CONNECTION_ERROR_MILLISECONDS;
|
||||||
|
fetchCallResponseTimeLast = responseTimeOfFetchCall;
|
||||||
|
fetchCallNumberOfFailures++;
|
||||||
lastApiCallFailed = true;
|
lastApiCallFailed = true;
|
||||||
} else if (rateLimitHit) {
|
} else if (rateLimitHit) {
|
||||||
Logger.printDebug(() -> "API rate limit was hit. Stopping API calls for the next "
|
Logger.printDebug(() -> "API rate limit was hit. Stopping API calls for the next "
|
||||||
+ BACKOFF_RATE_LIMIT_MILLISECONDS + " seconds");
|
+ BACKOFF_RATE_LIMIT_MILLISECONDS + " seconds");
|
||||||
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_RATE_LIMIT_MILLISECONDS;
|
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_RATE_LIMIT_MILLISECONDS;
|
||||||
|
numberOfRateLimitRequestsEncountered++;
|
||||||
|
fetchCallResponseTimeLast = FETCH_CALL_RESPONSE_TIME_VALUE_RATE_LIMIT;
|
||||||
if (!lastApiCallFailed && toastOnConnectionError) {
|
if (!lastApiCallFailed && toastOnConnectionError) {
|
||||||
Utils.showToastLong(str("revanced_ryd_failure_client_rate_limit_requested"));
|
Utils.showToastLong(str("revanced_ryd_failure_client_rate_limit_requested"));
|
||||||
}
|
}
|
||||||
lastApiCallFailed = true;
|
lastApiCallFailed = true;
|
||||||
} else {
|
} else {
|
||||||
|
fetchCallResponseTimeLast = responseTimeOfFetchCall;
|
||||||
lastApiCallFailed = false;
|
lastApiCallFailed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleConnectionError(@NonNull String toastMessage, @Nullable Exception ex) {
|
private static void handleConnectionError(@NonNull String toastMessage,
|
||||||
|
@Nullable Exception ex,
|
||||||
|
boolean showLongToast) {
|
||||||
if (!lastApiCallFailed && toastOnConnectionError) {
|
if (!lastApiCallFailed && toastOnConnectionError) {
|
||||||
Utils.showToastShort(toastMessage);
|
if (showLongToast) {
|
||||||
}
|
Utils.showToastLong(toastMessage);
|
||||||
if (ex != null) {
|
} else {
|
||||||
Logger.printInfo(() -> toastMessage, ex);
|
Utils.showToastShort(toastMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
lastApiCallFailed = true;
|
||||||
|
|
||||||
|
Logger.printInfo(() -> toastMessage, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return NULL if fetch failed, or if a rate limit is in effect.
|
|
||||||
*/
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static RYDVoteData fetchVotes(String videoId) {
|
public static RYDVoteData fetchVotes(String videoId) {
|
||||||
Utils.verifyOffMainThread();
|
Utils.verifyOffMainThread();
|
||||||
@ -160,6 +256,7 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Logger.printDebug(() -> "Fetching votes for: " + videoId);
|
Logger.printDebug(() -> "Fetching votes for: " + videoId);
|
||||||
|
final long timeNetworkCallStarted = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_DISLIKES, videoId);
|
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_DISLIKES, videoId);
|
||||||
@ -173,10 +270,12 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
connection.setConnectTimeout(API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS); // timeout for TCP connection to server
|
connection.setConnectTimeout(API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS); // timeout for TCP connection to server
|
||||||
connection.setReadTimeout(API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS); // timeout for server response
|
connection.setReadTimeout(API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS); // timeout for server response
|
||||||
|
|
||||||
|
randomlyWaitIfLocallyDebugging();
|
||||||
|
|
||||||
final int responseCode = connection.getResponseCode();
|
final int responseCode = connection.getResponseCode();
|
||||||
if (checkIfRateLimitWasHit(responseCode)) {
|
if (checkIfRateLimitWasHit(responseCode)) {
|
||||||
connection.disconnect(); // rate limit hit, should disconnect
|
connection.disconnect(); // rate limit hit, should disconnect
|
||||||
updateRateLimitAndStats(false, true);
|
updateRateLimitAndStats(timeNetworkCallStarted, false, true);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +284,7 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
JSONObject json = Requester.parseJSONObject(connection);
|
JSONObject json = Requester.parseJSONObject(connection);
|
||||||
try {
|
try {
|
||||||
RYDVoteData votingData = new RYDVoteData(json);
|
RYDVoteData votingData = new RYDVoteData(json);
|
||||||
updateRateLimitAndStats(false, false);
|
updateRateLimitAndStats(timeNetworkCallStarted, false, false);
|
||||||
Logger.printDebug(() -> "Voting data fetched: " + votingData);
|
Logger.printDebug(() -> "Voting data fetched: " + votingData);
|
||||||
return votingData;
|
return votingData;
|
||||||
} catch (JSONException ex) {
|
} catch (JSONException ex) {
|
||||||
@ -193,20 +292,21 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
// fall thru to update statistics
|
// fall thru to update statistics
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
// Unexpected response code. Most likely RYD is temporarily broken.
|
||||||
|
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode),
|
||||||
|
null, true);
|
||||||
}
|
}
|
||||||
connection.disconnect(); // something went wrong, might as well disconnect
|
connection.disconnect(); // Something went wrong, might as well disconnect.
|
||||||
} catch (
|
} catch (SocketTimeoutException ex) {
|
||||||
SocketTimeoutException ex) { // connection timed out, response timeout, or some other network error
|
handleConnectionError((str("revanced_ryd_failure_connection_timeout")), ex, false);
|
||||||
handleConnectionError((str("revanced_ryd_failure_connection_timeout")), ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
handleConnectionError((str("revanced_ryd_failure_generic", ex.getMessage())), ex);
|
handleConnectionError((str("revanced_ryd_failure_generic", ex.getMessage())), ex, true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// should never happen
|
// should never happen
|
||||||
Logger.printException(() -> "fetchVotes failure", ex);
|
Logger.printException(() -> "fetchVotes failure", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRateLimitAndStats(true, false);
|
updateRateLimitAndStats(timeNetworkCallStarted, true, false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +320,7 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
if (checkIfRateLimitInEffect("registerAsNewUser")) {
|
if (checkIfRateLimitInEffect("registerAsNewUser")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String userId = randomString();
|
String userId = randomString(36);
|
||||||
Logger.printDebug(() -> "Trying to register new user");
|
Logger.printDebug(() -> "Trying to register new user");
|
||||||
|
|
||||||
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_REGISTRATION, userId);
|
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_REGISTRATION, userId);
|
||||||
@ -241,12 +341,13 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
String solution = solvePuzzle(challenge, difficulty);
|
String solution = solvePuzzle(challenge, difficulty);
|
||||||
return confirmRegistration(userId, solution);
|
return confirmRegistration(userId, solution);
|
||||||
}
|
}
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode),
|
||||||
|
null, true);
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
} catch (SocketTimeoutException ex) {
|
} catch (SocketTimeoutException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex);
|
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex, false);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_generic", "registration failed"), ex);
|
handleConnectionError(str("revanced_ryd_failure_generic", "registration failed"), ex, true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "Failed to register user", ex); // should never happen
|
Logger.printException(() -> "Failed to register user", ex); // should never happen
|
||||||
}
|
}
|
||||||
@ -283,15 +384,18 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
Logger.printDebug(() -> "Registration confirmation successful");
|
Logger.printDebug(() -> "Registration confirmation successful");
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something went wrong, might as well disconnect.
|
// Something went wrong, might as well disconnect.
|
||||||
String response = Requester.parseStringAndDisconnect(connection);
|
String response = Requester.parseStringAndDisconnect(connection);
|
||||||
Logger.printInfo(() -> "Failed to confirm registration for user: " + userId
|
Logger.printInfo(() -> "Failed to confirm registration for user: " + userId
|
||||||
+ " solution: " + solution + " responseCode: " + responseCode + " response: '" + response + "''");
|
+ " solution: " + solution + " responseCode: " + responseCode + " response: '" + response + "''");
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode),
|
||||||
|
null, true);
|
||||||
} catch (SocketTimeoutException ex) {
|
} catch (SocketTimeoutException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex);
|
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex, false);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_generic", "confirm registration failed"), ex);
|
handleConnectionError(str("revanced_ryd_failure_generic", "confirm registration failed"),
|
||||||
|
ex, true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "Failed to confirm registration for user: " + userId
|
Logger.printException(() -> "Failed to confirm registration for user: " + userId
|
||||||
+ "solution: " + solution, ex);
|
+ "solution: " + solution, ex);
|
||||||
@ -299,16 +403,16 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendVote(String userId, String videoId, ReturnYouTubeDislike.Vote vote) {
|
public static boolean sendVote(String userId, String videoId, ReturnYouTubeDislike.Vote vote) {
|
||||||
Utils.verifyOffMainThread();
|
Utils.verifyOffMainThread();
|
||||||
Objects.requireNonNull(videoId);
|
Objects.requireNonNull(videoId);
|
||||||
Objects.requireNonNull(vote);
|
Objects.requireNonNull(vote);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userId == null) return;
|
if (userId == null) return false;
|
||||||
|
|
||||||
if (checkIfRateLimitInEffect("sendVote")) {
|
if (checkIfRateLimitInEffect("sendVote")) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
Logger.printDebug(() -> "Trying to vote for video: " + videoId + " with vote: " + vote);
|
Logger.printDebug(() -> "Trying to vote for video: " + videoId + " with vote: " + vote);
|
||||||
|
|
||||||
@ -325,7 +429,7 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
final int responseCode = connection.getResponseCode();
|
final int responseCode = connection.getResponseCode();
|
||||||
if (checkIfRateLimitWasHit(responseCode)) {
|
if (checkIfRateLimitWasHit(responseCode)) {
|
||||||
connection.disconnect(); // disconnect, as no more connections will be made for a little while
|
connection.disconnect(); // disconnect, as no more connections will be made for a little while
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
|
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
|
||||||
JSONObject json = Requester.parseJSONObject(connection);
|
JSONObject json = Requester.parseJSONObject(connection);
|
||||||
@ -333,25 +437,26 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
int difficulty = json.getInt("difficulty");
|
int difficulty = json.getInt("difficulty");
|
||||||
|
|
||||||
String solution = solvePuzzle(challenge, difficulty);
|
String solution = solvePuzzle(challenge, difficulty);
|
||||||
confirmVote(videoId, userId, solution);
|
return confirmVote(videoId, userId, solution);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.printInfo(() -> "Failed to send vote for video: " + videoId + " vote: " + vote
|
Logger.printInfo(() -> "Failed to send vote for video: " + videoId + " vote: " + vote
|
||||||
+ " response code was: " + responseCode);
|
+ " response code was: " + responseCode);
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode),
|
||||||
|
null, true);
|
||||||
connection.disconnect(); // something went wrong, might as well disconnect
|
connection.disconnect(); // something went wrong, might as well disconnect
|
||||||
} catch (SocketTimeoutException ex) {
|
} catch (SocketTimeoutException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex);
|
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex, false);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_generic", "send vote failed"), ex);
|
handleConnectionError(str("revanced_ryd_failure_generic", "send vote failed"), ex, true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// should never happen
|
// should never happen
|
||||||
Logger.printException(() -> "Failed to send vote for video: " + videoId + " vote: " + vote, ex);
|
Logger.printException(() -> "Failed to send vote for video: " + videoId + " vote: " + vote, ex);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void confirmVote(String videoId, String userId, String solution) {
|
private static boolean confirmVote(String videoId, String userId, String solution) {
|
||||||
Utils.verifyOffMainThread();
|
Utils.verifyOffMainThread();
|
||||||
Objects.requireNonNull(videoId);
|
Objects.requireNonNull(videoId);
|
||||||
Objects.requireNonNull(userId);
|
Objects.requireNonNull(userId);
|
||||||
@ -359,7 +464,7 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (checkIfRateLimitInEffect("confirmVote")) {
|
if (checkIfRateLimitInEffect("confirmVote")) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
Logger.printDebug(() -> "Trying to confirm vote for video: " + videoId + " solution: " + solution);
|
Logger.printDebug(() -> "Trying to confirm vote for video: " + videoId + " solution: " + solution);
|
||||||
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.CONFIRM_VOTE);
|
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.CONFIRM_VOTE);
|
||||||
@ -375,25 +480,29 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
final int responseCode = connection.getResponseCode();
|
final int responseCode = connection.getResponseCode();
|
||||||
if (checkIfRateLimitWasHit(responseCode)) {
|
if (checkIfRateLimitWasHit(responseCode)) {
|
||||||
connection.disconnect(); // disconnect, as no more connections will be made for a little while
|
connection.disconnect(); // disconnect, as no more connections will be made for a little while
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
|
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
|
||||||
Logger.printDebug(() -> "Vote confirm successful for video: " + videoId);
|
Logger.printDebug(() -> "Vote confirm successful for video: " + videoId);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something went wrong, might as well disconnect.
|
// Something went wrong, might as well disconnect.
|
||||||
String response = Requester.parseStringAndDisconnect(connection);
|
String response = Requester.parseStringAndDisconnect(connection);
|
||||||
Logger.printInfo(() -> "Failed to confirm vote for video: " + videoId
|
Logger.printInfo(() -> "Failed to confirm vote for video: " + videoId
|
||||||
+ " solution: " + solution + " responseCode: " + responseCode + " response: '" + response + "'");
|
+ " solution: " + solution + " responseCode: " + responseCode + " response: '" + response + "'");
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode),
|
||||||
|
null, true);
|
||||||
} catch (SocketTimeoutException ex) {
|
} catch (SocketTimeoutException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex);
|
handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex, false);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
handleConnectionError(str("revanced_ryd_failure_generic", "confirm vote failed"), ex);
|
handleConnectionError(str("revanced_ryd_failure_generic", "confirm vote failed"),
|
||||||
|
ex, true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "Failed to confirm vote for video: " + videoId
|
Logger.printException(() -> "Failed to confirm vote for video: " + videoId
|
||||||
+ " solution: " + solution, ex); // should never happen
|
+ " solution: " + solution, ex); // should never happen
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyCommonPostRequestSettings(HttpURLConnection connection) throws ProtocolException {
|
private static void applyCommonPostRequestSettings(HttpURLConnection connection) throws ProtocolException {
|
||||||
@ -440,12 +549,12 @@ public class ReturnYouTubeDislikeApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/a/157202
|
// https://stackoverflow.com/a/157202
|
||||||
private static String randomString() {
|
private static String randomString(int len) {
|
||||||
String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
SecureRandom rnd = new SecureRandom();
|
SecureRandom rnd = new SecureRandom();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(36);
|
StringBuilder sb = new StringBuilder(len);
|
||||||
for (int i = 0; i < 36; i++)
|
for (int i = 0; i < len; i++)
|
||||||
sb.append(AB.charAt(rnd.nextInt(AB.length())));
|
sb.append(AB.charAt(rnd.nextInt(AB.length())));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,24 @@ public class Utils {
|
|||||||
return backgroundThreadPool.submit(call);
|
return backgroundThreadPool.submit(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates a delay by doing meaningless calculations.
|
||||||
|
* Used for debugging to verify UI timeout logic.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
|
public static long doNothingForDuration(long amountOfTimeToWaste) {
|
||||||
|
final long timeCalculationStarted = System.currentTimeMillis();
|
||||||
|
Logger.printDebug(() -> "Artificially creating delay of: " + amountOfTimeToWaste + "ms");
|
||||||
|
|
||||||
|
long meaninglessValue = 0;
|
||||||
|
while (System.currentTimeMillis() - timeCalculationStarted < amountOfTimeToWaste) {
|
||||||
|
// could do a thread sleep, but that will trigger an exception if the thread is interrupted
|
||||||
|
meaninglessValue += Long.numberOfLeadingZeros((long) Math.exp(Math.random()));
|
||||||
|
}
|
||||||
|
// return the value, otherwise the compiler or VM might optimize and remove the meaningless time wasting work,
|
||||||
|
// leaving an empty loop that hammers on the System.currentTimeMillis native call
|
||||||
|
return meaninglessValue;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean containsAny(@NonNull String value, @NonNull String... targets) {
|
public static boolean containsAny(@NonNull String value, @NonNull String... targets) {
|
||||||
return indexOfFirstFound(value, targets) >= 0;
|
return indexOfFirstFound(value, targets) >= 0;
|
||||||
|
@ -360,8 +360,8 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
removeRollingNumberPatchChanges(view);
|
removeRollingNumberPatchChanges(view);
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
final boolean isDescriptionPanel = view.getParent() instanceof ViewGroup viewGroupParent
|
final boolean isDescriptionPanel = view.getParent() instanceof ViewGroup viewGroupParent &&
|
||||||
&& viewGroupParent.getChildCount() < 2;
|
viewGroupParent.getChildCount() < 2;
|
||||||
// Called for all instances of RollingNumber, so must check if text is for a dislikes.
|
// Called for all instances of RollingNumber, so must check if text is for a dislikes.
|
||||||
// Text will already have the correct content but it's missing the drawable separators.
|
// Text will already have the correct content but it's missing the drawable separators.
|
||||||
if (!ReturnYouTubeDislike.isPreviouslyCreatedSegmentedSpan(original.toString()) || isDescriptionPanel) {
|
if (!ReturnYouTubeDislike.isPreviouslyCreatedSegmentedSpan(original.toString()) || isDescriptionPanel) {
|
||||||
|
@ -118,7 +118,6 @@ public class ReturnYouTubeDislike {
|
|||||||
*/
|
*/
|
||||||
public static final int leftSeparatorShapePaddingPixels;
|
public static final int leftSeparatorShapePaddingPixels;
|
||||||
private static final ShapeDrawable leftSeparatorShape;
|
private static final ShapeDrawable leftSeparatorShape;
|
||||||
public static final Locale locale;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final Resources resources = Utils.getResources();
|
final Resources resources = Utils.getResources();
|
||||||
@ -135,7 +134,6 @@ public class ReturnYouTubeDislike {
|
|||||||
|
|
||||||
leftSeparatorShape = new ShapeDrawable(new RectShape());
|
leftSeparatorShape = new ShapeDrawable(new RectShape());
|
||||||
leftSeparatorShape.setBounds(leftSeparatorBounds);
|
leftSeparatorShape.setBounds(leftSeparatorBounds);
|
||||||
locale = resources.getConfiguration().getLocales().get(0);
|
|
||||||
|
|
||||||
ReturnYouTubeDislikeApi.toastOnConnectionError = Settings.RYD_TOAST_ON_CONNECTION_ERROR.get();
|
ReturnYouTubeDislikeApi.toastOnConnectionError = Settings.RYD_TOAST_ON_CONNECTION_ERROR.get();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user