From ae18edd047d7979307bc28f28db17bae2c5cc226 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 16 May 2023 10:28:35 +0400 Subject: [PATCH] feat(youtube): add options to disable toasts on connection errors (#402) Co-authored-by: oSumAtrIX --- .../requests/ReturnYouTubeDislikeApi.java | 80 +++++++++++++------ .../integrations/settings/SettingsEnum.java | 2 + .../ReturnYouTubeDislikeSettingsFragment.java | 18 +++++ .../SponsorBlockSettingsFragment.java | 15 ++++ .../sponsorblock/requests/SBRequester.java | 28 +++++-- 5 files changed, 111 insertions(+), 32 deletions(-) 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 dcc5bf9d..0965f493 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 @@ -5,11 +5,13 @@ import static app.revanced.integrations.utils.StringRef.str; import android.util.Base64; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.json.JSONException; import org.json.JSONObject; +import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.ProtocolException; @@ -22,6 +24,7 @@ import java.util.Objects; import app.revanced.integrations.requests.Requester; import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike; +import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; @@ -219,6 +222,15 @@ public class ReturnYouTubeDislikeApi { } } + private static void handleConnectionError(@NonNull String toastMessage, @Nullable Exception ex) { + if (SettingsEnum.RYD_TOAST_ON_CONNECTION_ERROR.getBoolean()) { + ReVancedUtils.showToastShort(toastMessage); + } + if (ex != null) { + LogHelper.printInfo(() -> toastMessage, ex); + } + } + /** * @return NULL if fetch failed, or if a rate limit is in effect. */ @@ -272,12 +284,13 @@ public class ReturnYouTubeDislikeApi { LogHelper.printDebug(() -> "Video has no like/dislikes (video is a YouTube Story?): " + videoId); return null; // do not updated connection statistics } else { - LogHelper.printException(() -> "Failed to fetch votes for video: " + videoId + " response code was: " + responseCode, - null, str("revanced_ryd_failure_connection_status_code", responseCode)); - connection.disconnect(); // something went wrong, might as well disconnect + handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null); } + connection.disconnect(); // something went wrong, might as well disconnect } catch (SocketTimeoutException ex) { // connection timed out, response timeout, or some other network error - LogHelper.printException(() -> "Failed to fetch votes", ex, str("revanced_ryd_failure_connection_timeout")); + handleConnectionError((str("revanced_ryd_failure_connection_timeout")), ex); + } catch (IOException ex) { + handleConnectionError((str("revanced_ryd_failure_generic", ex.getMessage())), ex); } catch (Exception ex) { // should never happen LogHelper.printException(() -> "Failed to fetch votes", ex, str("revanced_ryd_failure_generic", ex.getMessage())); @@ -318,11 +331,14 @@ public class ReturnYouTubeDislikeApi { String solution = solvePuzzle(challenge, difficulty); return confirmRegistration(userId, solution); } - LogHelper.printException(() -> "Failed to register new user: " + userId - + " response code was: " + responseCode); // failed attempt, and ok to log userId + handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null); connection.disconnect(); + } catch (SocketTimeoutException ex) { + handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex); + } catch (IOException ex) { + handleConnectionError(str("revanced_ryd_failure_generic", "registration failed"), ex); } catch (Exception ex) { - LogHelper.printException(() -> "Failed to register user", ex); + LogHelper.printException(() -> "Failed to register user", ex); // should never happen } return null; } @@ -351,19 +367,23 @@ public class ReturnYouTubeDislikeApi { connection.disconnect(); // disconnect, as no more connections will be made for a little while return null; } + String result = null; if (responseCode == HTTP_STATUS_CODE_SUCCESS) { - String result = Requester.parseJson(connection); + result = Requester.parseJson(connection); if (result.equalsIgnoreCase("true")) { LogHelper.printDebug(() -> "Registration confirmation successful"); return userId; } - LogHelper.printException(() -> "Failed to confirm registration for user: " + userId - + " solution: " + solution + " response string was: " + result); - } else { - LogHelper.printException(() -> "Failed to confirm registration for user: " + userId - + " solution: " + solution + " response code was: " + responseCode); } + final String resultLog = result == null ? "(no response)" : result; + LogHelper.printInfo(() -> "Failed to confirm registration for user: " + userId + + " solution: " + solution + " responseCode: " + responseCode + " responseString: " + resultLog); + handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null); connection.disconnect(); // something went wrong, might as well disconnect + } catch (SocketTimeoutException ex) { + handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex); + } catch (IOException ex) { + handleConnectionError(str("revanced_ryd_failure_generic", "confirm registration failed"), ex); } catch (Exception ex) { LogHelper.printException(() -> "Failed to confirm registration for user: " + userId + "solution: " + solution, ex); @@ -405,10 +425,16 @@ public class ReturnYouTubeDislikeApi { String solution = solvePuzzle(challenge, difficulty); return confirmVote(videoId, userId, solution); } - LogHelper.printException(() -> "Failed to send vote for video: " + videoId - + " vote: " + vote + " response code was: " + responseCode); + LogHelper.printInfo(() -> "Failed to send vote for video: " + videoId + " vote: " + vote + + " response code was: " + responseCode); + handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null); connection.disconnect(); // something went wrong, might as well disconnect + } catch (SocketTimeoutException ex) { + handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex); + } catch (IOException ex) { + handleConnectionError(str("revanced_ryd_failure_generic", "send vote failed"), ex); } catch (Exception ex) { + // should never happen LogHelper.printException(() -> "Failed to send vote for video: " + videoId + " vote: " + vote, ex); } return false; @@ -438,23 +464,26 @@ public class ReturnYouTubeDislikeApi { connection.disconnect(); // disconnect, as no more connections will be made for a little while return false; } - + String result = null; if (responseCode == HTTP_STATUS_CODE_SUCCESS) { - String result = Requester.parseJson(connection); + result = Requester.parseJson(connection); if (result.equalsIgnoreCase("true")) { LogHelper.printDebug(() -> "Vote confirm successful for video: " + videoId); return true; } - LogHelper.printException(() -> "Failed to confirm vote for video: " + videoId - + " solution: " + solution + " response string was: " + result); - } else { - LogHelper.printException(() -> "Failed to confirm vote for video: " + videoId - + " solution: " + solution + " response code was: " + responseCode); } + final String resultLog = result == null ? "(no response)" : result; + LogHelper.printInfo(() -> "Failed to confirm vote for video: " + videoId + + " solution: " + solution + " responseCode: " + responseCode + " responseString: " + resultLog); + handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null); connection.disconnect(); // something went wrong, might as well disconnect + } catch (SocketTimeoutException ex) { + handleConnectionError(str("revanced_ryd_failure_connection_timeout"), ex); + } catch (IOException ex) { + handleConnectionError(str("revanced_ryd_failure_generic", "confirm vote failed"), ex); } catch (Exception ex) { LogHelper.printException(() -> "Failed to confirm vote for video: " + videoId - + " solution: " + solution, ex); + + " solution: " + solution, ex); // should never happen } return false; } @@ -503,7 +532,7 @@ public class ReturnYouTubeDislikeApi { } // should never be reached - throw new IllegalStateException("Failed to solve puzzle challenge: " + challenge + " of difficulty: " + difficulty); + throw new IllegalStateException("Failed to solve puzzle challenge: " + challenge + " difficulty: " + difficulty); } // https://stackoverflow.com/a/157202 @@ -519,9 +548,8 @@ public class ReturnYouTubeDislikeApi { private static int countLeadingZeroes(byte[] uInt8View) { int zeroes = 0; - int value; for (byte b : uInt8View) { - value = b & 0xFF; + int value = b & 0xFF; if (value == 0) { zeroes += 8; } else { 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 4b5bc40a..8aa98f11 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -169,6 +169,7 @@ public enum SettingsEnum { RYD_SHORTS("ryd_shorts", BOOLEAN, TRUE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)), RYD_DISLIKE_PERCENTAGE("ryd_dislike_percentage", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)), RYD_COMPACT_LAYOUT("ryd_compact_layout", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)), + RYD_TOAST_ON_CONNECTION_ERROR("ryd_toast_on_connection_error", BOOLEAN, TRUE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)), // SponsorBlock SB_ENABLED("sb_enabled", BOOLEAN, TRUE, SPONSOR_BLOCK), @@ -180,6 +181,7 @@ public enum SettingsEnum { SB_COMPACT_SKIP_BUTTON("sb_compact_skip_button", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)), SB_AUTO_HIDE_SKIP_BUTTON("sb_auto_hide_skip_button", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)), SB_TOAST_ON_SKIP("sb_toast_on_skip", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)), + SB_TOAST_ON_CONNECTION_ERROR("sb_toast_on_connection_error", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)), SB_TRACK_SKIP_COUNT("sb_track_skip_count", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)), SB_SEGMENT_MIN_DURATION("sb_min_segment_duration", FLOAT, 0F, SPONSOR_BLOCK, parents(SB_ENABLED)), SB_VIDEO_LENGTH_WITHOUT_SEGMENTS("sb_video_length_without_segments", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)), 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 4005ad7e..dadc85be 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/ReturnYouTubeDislikeSettingsFragment.java @@ -34,10 +34,16 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment { */ private SwitchPreference compactLayoutPreference; + /** + * If segmented like/dislike button uses smaller compact layout. + */ + private SwitchPreference toastOnRYDNotAvailable; + private void updateUIState() { shortsPreference.setEnabled(SettingsEnum.RYD_SHORTS.isAvailable()); percentagePreference.setEnabled(SettingsEnum.RYD_DISLIKE_PERCENTAGE.isAvailable()); compactLayoutPreference.setEnabled(SettingsEnum.RYD_COMPACT_LAYOUT.isAvailable()); + toastOnRYDNotAvailable.setEnabled(SettingsEnum.RYD_TOAST_ON_CONNECTION_ERROR.isAvailable()); } @Override @@ -102,6 +108,18 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment { }); preferenceScreen.addPreference(compactLayoutPreference); + toastOnRYDNotAvailable = new SwitchPreference(context); + toastOnRYDNotAvailable.setChecked(SettingsEnum.RYD_TOAST_ON_CONNECTION_ERROR.getBoolean()); + toastOnRYDNotAvailable.setTitle(str("ryd_toast_on_connection_error_title")); + toastOnRYDNotAvailable.setSummaryOn(str("ryd_toast_on_connection_error_summary_on")); + toastOnRYDNotAvailable.setSummaryOff(str("ryd_toast_on_connection_error_summary_off")); + toastOnRYDNotAvailable.setOnPreferenceChangeListener((pref, newValue) -> { + SettingsEnum.RYD_TOAST_ON_CONNECTION_ERROR.saveValue(newValue); + updateUIState(); + return true; + }); + preferenceScreen.addPreference(toastOnRYDNotAvailable); + updateUIState(); 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 a46a7254..85bac3ab 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java @@ -52,6 +52,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment { private SwitchPreference showSkipToast; private SwitchPreference trackSkips; private SwitchPreference showTimeWithoutSegments; + private SwitchPreference toastOnConnectionError; private EditTextPreference newSegmentStep; private EditTextPreference minSegmentDuration; @@ -90,6 +91,9 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment { showSkipToast.setChecked(SettingsEnum.SB_TOAST_ON_SKIP.getBoolean()); showSkipToast.setEnabled(enabled); + toastOnConnectionError.setChecked(SettingsEnum.SB_TOAST_ON_CONNECTION_ERROR.getBoolean()); + toastOnConnectionError.setEnabled(enabled); + trackSkips.setChecked(SettingsEnum.SB_TRACK_SKIP_COUNT.getBoolean()); trackSkips.setEnabled(enabled); @@ -283,6 +287,17 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment { screen.addPreference(category); category.setTitle(str("sb_general")); + toastOnConnectionError = new SwitchPreference(context); + toastOnConnectionError.setTitle(str("sb_toast_on_connection_error_title")); + toastOnConnectionError.setSummaryOn(str("sb_toast_on_connection_error_summary_on")); + toastOnConnectionError.setSummaryOff(str("sb_toast_on_connection_error_summary_off")); + toastOnConnectionError.setOnPreferenceChangeListener((preference1, newValue) -> { + SettingsEnum.SB_TOAST_ON_CONNECTION_ERROR.saveValue(newValue); + updateUI(); + return true; + }); + category.addPreference(toastOnConnectionError); + trackSkips = new SwitchPreference(context); trackSkips.setTitle(str("sb_general_skipcount")); trackSkips.setSummaryOn(str("sb_general_skipcount_sum_on")); diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java b/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java index 7c19444e..6bb69917 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java @@ -49,6 +49,15 @@ public class SBRequester { private SBRequester() { } + private static void handleConnectionError(@NonNull String toastMessage, @Nullable Exception ex) { + if (SettingsEnum.SB_TOAST_ON_CONNECTION_ERROR.getBoolean()) { + ReVancedUtils.showToastShort(toastMessage); + } + if (ex != null) { + LogHelper.printInfo(() -> toastMessage, ex); + } + } + @NonNull public static SponsorSegment[] getSegments(@NonNull String videoId) { ReVancedUtils.verifyOffMainThread(); @@ -88,14 +97,16 @@ public class SBRequester { // no segments are found. a normal response LogHelper.printDebug(() -> "No segments found for video: " + videoId); } else { - LogHelper.printException(() -> "getSegments failed with response code: " + responseCode, - null, str("sb_sponsorblock_connection_failure_status", responseCode)); + handleConnectionError(str("sb_sponsorblock_connection_failure_status", responseCode), null); connection.disconnect(); // something went wrong, might as well disconnect } } catch (SocketTimeoutException ex) { - LogHelper.printException(() -> "Failed to get segments", ex, str("sb_sponsorblock_connection_failure_timeout")); + handleConnectionError(str("sb_sponsorblock_connection_failure_timeout"), ex); + } catch (IOException ex) { + handleConnectionError(str("sb_sponsorblock_connection_failure_generic"), ex); } catch (Exception ex) { - LogHelper.printException(() -> "Failed to get segments", ex, str("sb_sponsorblock_connection_failure_generic")); + // Should never happen + LogHelper.printException(() -> "getSegments failure", ex); } // Crude debug tests to verify random features @@ -162,7 +173,10 @@ public class SBRequester { } ReVancedUtils.showToastLong(messageToToast); } catch (SocketTimeoutException ex) { + // Always show, even if show connection toasts is turned off ReVancedUtils.showToastLong(str("sb_submit_failed_timeout")); + } catch (IOException ex) { + ReVancedUtils.showToastLong(str("sb_submit_failed_unknown_error", 0, ex.getMessage())); } catch (Exception ex) { LogHelper.printException(() -> "failed to submit segments", ex); } @@ -217,7 +231,9 @@ public class SBRequester { break; } } catch (SocketTimeoutException ex) { - LogHelper.printException(() -> "failed to vote for segment", ex, str("sb_vote_failed_timeout")); + ReVancedUtils.showToastShort(str("sb_vote_failed_timeout")); + } catch (IOException ex) { + ReVancedUtils.showToastShort(str("sb_vote_failed_unknown_error", 0, ex.getMessage())); } catch (Exception ex) { LogHelper.printException(() -> "failed to vote for segment", ex); // should never happen } @@ -264,7 +280,7 @@ public class SBRequester { public static void runVipCheckInBackgroundIfNeeded() { if (!SponsorBlockSettings.userHasSBPrivateId()) { - return; // User cannot be a VIP. User has never voted, created any segments, and has not import any SB settings. + return; // User cannot be a VIP. User has never voted, created any segments, or has imported a SB user id. } long now = System.currentTimeMillis(); if (now < (SettingsEnum.SB_LAST_VIP_CHECK.getLong() + TimeUnit.DAYS.toMillis(3))) {