From 2d513b5100101cc3cd0393ed72bd7e09b9e11409 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Sat, 16 Jul 2022 16:50:16 +0200 Subject: [PATCH] feat: `return-youtube-dislikes` patch (#81) * feat: update dislike button text * refactor(ryd): remove unused code * refactor: create patch class for ryd * refactor: move VideoInformation --- .../patches/ReturnYouTubeDislikesPatch.java | 33 +++ .../ryd/ReturnYouTubeDislikes.java | 196 +++--------------- .../ryd/requests/RYDRequester.java | 13 +- .../sponsorblock/PlayerController.java | 2 +- .../sponsorblock/player/VideoHelpers.java | 1 + .../sponsorblock/player/ui/AdButton.java | 4 +- .../player/ui/SBBrowserButton.java | 3 +- .../player/ui/SBWhitelistButton.java | 4 +- .../VideoInformation.java | 2 +- .../integrations/whitelist/Whitelist.java | 4 +- .../requests/WhitelistRequester.java | 2 +- 11 files changed, 76 insertions(+), 188 deletions(-) create mode 100644 app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikesPatch.java rename app/src/main/java/app/revanced/integrations/{sponsorblock/player => videoplayer}/VideoInformation.java (97%) diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikesPatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikesPatch.java new file mode 100644 index 0000000000..cfdfd71bf8 --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikesPatch.java @@ -0,0 +1,33 @@ +package app.revanced.integrations.patches; + +import java.util.concurrent.atomic.AtomicReference; + +import app.revanced.integrations.ryd.ReturnYouTubeDislikes; + +/** + * Used by app.revanced.patches.youtube.layout.returnyoutubedislikes.patch.RYDPatch + */ +public class ReturnYouTubeDislikesPatch { + + /** + * Called when the video id changes + */ + public static void newVideoLoaded(String videoId) { + ReturnYouTubeDislikes.newVideoLoaded(videoId); + } + + /** + * Called when a litho text component is created + */ + public static void onComponentCreated(Object conversionContext, AtomicReference textRef) { + ReturnYouTubeDislikes.onComponentCreated(conversionContext, textRef); + } + + /** + * Called when the like/dislike button is clicked + * @param vote -1 (dislike), 0 (none) or 1 (like) + */ + public static void sendVote(int vote) { + ReturnYouTubeDislikes.sendVote(vote); + } +} diff --git a/app/src/main/java/app/revanced/integrations/ryd/ReturnYouTubeDislikes.java b/app/src/main/java/app/revanced/integrations/ryd/ReturnYouTubeDislikes.java index f51e0b4334..0c6e6c9e23 100644 --- a/app/src/main/java/app/revanced/integrations/ryd/ReturnYouTubeDislikes.java +++ b/app/src/main/java/app/revanced/integrations/ryd/ReturnYouTubeDislikes.java @@ -1,35 +1,29 @@ package app.revanced.integrations.ryd; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.currentVideoId; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.dislikeCount; -import static app.revanced.integrations.utils.ReVancedUtils.getIdentifier; +import static app.revanced.integrations.videoplayer.VideoInformation.currentVideoId; +import static app.revanced.integrations.videoplayer.VideoInformation.dislikeCount; import android.content.Context; import android.icu.text.CompactDecimalFormat; import android.os.Build; - -import android.view.View; -import android.widget.TextView; +import android.text.SpannableString; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import app.revanced.integrations.ryd.requests.RYDRequester; import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.ryd.requests.RYDRequester; import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.SharedPrefHelper; public class ReturnYouTubeDislikes { - public static boolean isEnabled; - private static View _dislikeView = null; + private static boolean isEnabled; private static Thread _dislikeFetchThread = null; private static Thread _votingThread = null; private static Registration registration; private static Voting voting; - private static boolean likeActive; - private static boolean dislikeActive; - private static int votingValue = 0; // 1 = like, -1 = dislike, 0 = no vote private static CompactDecimalFormat compactNumberFormatter; static { @@ -60,7 +54,6 @@ public static void onEnabledChange(boolean enabled) { } } - //Was called in SB->player->VideoInformation->setCurrentVideoId(final String videoId) before, has to be called on its own at the same place now. public static void newVideoLoaded(String videoId) { LogHelper.debug(ReturnYouTubeDislikes.class, "newVideoLoaded - " + videoId); @@ -80,162 +73,34 @@ public static void newVideoLoaded(String videoId) { _dislikeFetchThread.start(); } - // Call to this needs to be injected in YT code - public static void setLikeTag(View view) { - if (!isEnabled) return; - - setTag(view, "like"); - } - - public static void setLikeTag(View view, boolean active) { + public static void onComponentCreated(Object conversionContext, AtomicReference textRef) { if (!isEnabled) return; - likeActive = active; - if (likeActive) { - votingValue = 1; - } - - LogHelper.debug(ReturnYouTubeDislikes.class, "Like tag active " + likeActive); - setTag(view, "like"); - } - - // Call to this needs to be injected in YT code - public static void setDislikeTag(View view) { - if (!isEnabled) return; - - _dislikeView = view; - setTag(view, "dislike"); - } - - public static void setDislikeTag(View view, boolean active) { - if (!isEnabled) return; - - dislikeActive = active; - if (dislikeActive) { - votingValue = -1; - } - _dislikeView = view; - LogHelper.debug(ReturnYouTubeDislikes.class, "Dislike tag active " + dislikeActive); - setTag(view, "dislike"); - } - - // Call to this needs to be injected in YT code - public static CharSequence onSetText(View view, CharSequence originalText) { - if (!isEnabled) return originalText; - return handleOnSetText(view, originalText); - } - - // Call to this needs to be injected in YT code - public static void onClick(View view, boolean inactive) { - if (!isEnabled) return; - - handleOnClick(view, inactive); - } - - private static CharSequence handleOnSetText(View view, CharSequence originalText) { - if (!isEnabled) return originalText; - try { - CharSequence tag = (CharSequence) view.getTag(); - LogHelper.debug(ReturnYouTubeDislikes.class, "handleOnSetText - " + tag + " - original text - " + originalText); - if (tag == null) return originalText; + // Contains a pathBuilder string, used to distinguish from other litho components + if (!conversionContext.toString().contains("dislike_button")) return; - if (tag == "like") { - return originalText; - } else if (tag == "dislike") { - return dislikeCount != null ? formatDislikes(dislikeCount) : originalText; - } - } catch (Exception ex) { - LogHelper.printException(ReturnYouTubeDislikes.class, "Error while handling the setText", ex); - } - - return originalText; - } + LogHelper.debug(ReturnYouTubeDislikes.class, "dislike button was created"); - public static void trySetDislikes(String dislikeCount) { - if (!isEnabled) return; - - try { - // Try to set normal video dislike count - if (_dislikeView == null) { - LogHelper.debug(ReturnYouTubeDislikes.class, "_dislikeView was null"); - return; - } + // Have to block the current thread until fetching is done + // There's no known way to edit the text after creation yet + if (_dislikeFetchThread != null) _dislikeFetchThread.join(); - View buttonView = _dislikeView.findViewById(getIdentifier("button_text", "id")); - if (buttonView == null) { - LogHelper.debug(ReturnYouTubeDislikes.class, "buttonView was null"); - return; + if (dislikeCount != null) { + updateDislikeText(textRef, formatDislikes(dislikeCount)); } - TextView button = (TextView) buttonView; - button.setText(dislikeCount); - LogHelper.debug(ReturnYouTubeDislikes.class, "trySetDislikes - " + dislikeCount); } catch (Exception ex) { LogHelper.printException(ReturnYouTubeDislikes.class, "Error while trying to set dislikes text", ex); } } - private static void handleOnClick(View view, boolean previousState) { + public static void sendVote(int vote) { + if (!isEnabled) return; + Context context = ReVancedUtils.getContext(); - if (!isEnabled || SharedPrefHelper.getBoolean(Objects.requireNonNull(context), SharedPrefHelper.SharedPrefNames.YOUTUBE, "user_signed_out", true)) + if (SharedPrefHelper.getBoolean(Objects.requireNonNull(context), SharedPrefHelper.SharedPrefNames.YOUTUBE, "user_signed_out", true)) return; - try { - String tag = (String) view.getTag(); - LogHelper.debug(ReturnYouTubeDislikes.class, "handleOnClick - " + tag + " - previousState - " + previousState); - if (tag == null) return; - - // If active status was removed, vote should be none - if (previousState) { - votingValue = 0; - } - if (tag.equals("like")) { - - // Like was activated - if (!previousState) { - votingValue = 1; - likeActive = true; - } else { - likeActive = false; - } - - // Like was activated and dislike was previously activated - if (!previousState && dislikeActive) { - dislikeCount--; - trySetDislikes(formatDislikes(dislikeCount)); - } - dislikeActive = false; - } else if (tag.equals("dislike")) { - likeActive = false; - - // Dislike was activated - if (!previousState) { - votingValue = -1; - dislikeActive = true; - dislikeCount++; - } - // Dislike was removed - else { - dislikeActive = false; - dislikeCount--; - } - trySetDislikes(formatDislikes(dislikeCount)); - } else { - // Unknown tag - return; - } - - LogHelper.debug(ReturnYouTubeDislikes.class, "New vote status - " + votingValue); - LogHelper.debug(ReturnYouTubeDislikes.class, "Like button " + likeActive + " | Dislike button " + dislikeActive); - sendVote(votingValue); - } catch (Exception ex) { - LogHelper.printException(ReturnYouTubeDislikes.class, "Error while handling the onClick", ex); - } - } - - private static void sendVote(int vote) { - if (!isEnabled) return; - LogHelper.debug(ReturnYouTubeDislikes.class, "sending vote - " + vote + " for video " + currentVideoId); try { if (_votingThread != null && _votingThread.getState() != Thread.State.TERMINATED) { @@ -257,22 +122,21 @@ private static void sendVote(int vote) { _votingThread.start(); } - private static void setTag(View view, String tag) { - if (!isEnabled) return; + private static void updateDislikeText(AtomicReference textRef, String text) { + SpannableString oldString = (SpannableString) textRef.get(); + SpannableString newString = new SpannableString(text); - try { - if (view == null) { - LogHelper.debug(ReturnYouTubeDislikes.class, "View was empty"); - return; - } - LogHelper.debug(ReturnYouTubeDislikes.class, "setTag - " + tag); - view.setTag(tag); - } catch (Exception ex) { - LogHelper.printException(ReturnYouTubeDislikes.class, "Error while trying to set tag to view", ex); + // Copy style (foreground color, etc) to new string + Object[] spans = oldString.getSpans(0, oldString.length(), Object.class); + for (Object span : spans) { + int flags = oldString.getSpanFlags(span); + newString.setSpan(span, 0, newString.length(), flags); } + + textRef.set(newString); } - public static String formatDislikes(int dislikes) { + private static String formatDislikes(int dislikes) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && compactNumberFormatter != null) { final String formatted = compactNumberFormatter.format(dislikes); LogHelper.debug(ReturnYouTubeDislikes.class, "Formatting dislikes - " + dislikes + " - " + formatted); diff --git a/app/src/main/java/app/revanced/integrations/ryd/requests/RYDRequester.java b/app/src/main/java/app/revanced/integrations/ryd/requests/RYDRequester.java index 520b847384..24eade335e 100644 --- a/app/src/main/java/app/revanced/integrations/ryd/requests/RYDRequester.java +++ b/app/src/main/java/app/revanced/integrations/ryd/requests/RYDRequester.java @@ -1,11 +1,8 @@ package app.revanced.integrations.ryd.requests; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.dislikeCount; +import static app.revanced.integrations.videoplayer.VideoInformation.dislikeCount; import static app.revanced.integrations.whitelist.requests.Requester.parseJson; -import android.os.Handler; -import android.os.Looper; - import org.json.JSONObject; @@ -16,7 +13,6 @@ import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.ryd.Registration; -import app.revanced.integrations.ryd.ReturnYouTubeDislikes; import app.revanced.integrations.whitelist.requests.Requester; import app.revanced.integrations.whitelist.requests.Route; @@ -33,13 +29,8 @@ public static void fetchDislikes(String videoId) { connection.setConnectTimeout(5 * 1000); if (connection.getResponseCode() == 200) { JSONObject json = getJSONObject(connection); - int dislikes = json.getInt("dislikes"); - dislikeCount = dislikes; + dislikeCount = json.getInt("dislikes"); LogHelper.debug(RYDRequester.class, "dislikes fetched - " + dislikeCount); - - - // Set the dislikes - new Handler(Looper.getMainLooper()).post(() -> ReturnYouTubeDislikes.trySetDislikes(ReturnYouTubeDislikes.formatDislikes(dislikes))); } else { LogHelper.debug(RYDRequester.class, "dislikes fetch response was " + connection.getResponseCode()); } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java b/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java index bca2fc9305..d1540cf1f9 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java @@ -23,7 +23,7 @@ import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.sponsorblock.player.VideoInformation; +import app.revanced.integrations.videoplayer.VideoInformation; import app.revanced.integrations.whitelist.Whitelist; import app.revanced.integrations.sponsorblock.objects.SponsorSegment; import app.revanced.integrations.sponsorblock.requests.SBRequester; diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoHelpers.java b/app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoHelpers.java index 057ef1a160..b3901700ac 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoHelpers.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoHelpers.java @@ -7,6 +7,7 @@ import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; +import app.revanced.integrations.videoplayer.VideoInformation; public class VideoHelpers { diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/AdButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/AdButton.java index f4177358d8..3461988cf5 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/AdButton.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/AdButton.java @@ -1,6 +1,6 @@ package app.revanced.integrations.sponsorblock.player.ui; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.currentVideoId; +import static app.revanced.integrations.videoplayer.VideoInformation.currentVideoId; import static app.revanced.integrations.sponsorblock.StringRef.str; import android.content.Context; @@ -10,7 +10,7 @@ import android.widget.ImageView; import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.sponsorblock.player.VideoInformation; +import app.revanced.integrations.videoplayer.VideoInformation; import app.revanced.integrations.whitelist.Whitelist; import app.revanced.integrations.whitelist.WhitelistType; import app.revanced.integrations.whitelist.requests.WhitelistRequester; diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBBrowserButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBBrowserButton.java index 438d51066e..f6df7068b6 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBBrowserButton.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBBrowserButton.java @@ -9,9 +9,8 @@ import android.view.ViewGroup; import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.sponsorblock.player.VideoInformation; +import app.revanced.integrations.videoplayer.VideoInformation; import app.revanced.integrations.utils.ReVancedUtils; -import app.revanced.integrations.sponsorblock.SponsorBlockSettings; import app.revanced.integrations.sponsorblock.SponsorBlockUtils; public class SBBrowserButton extends SlimButton { diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBWhitelistButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBWhitelistButton.java index f19df811e2..5604d87f9f 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBWhitelistButton.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SBWhitelistButton.java @@ -1,6 +1,6 @@ package app.revanced.integrations.sponsorblock.player.ui; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.currentVideoId; +import static app.revanced.integrations.videoplayer.VideoInformation.currentVideoId; import static app.revanced.integrations.sponsorblock.StringRef.str; import android.content.Context; @@ -10,7 +10,7 @@ import android.widget.ImageView; import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.sponsorblock.player.VideoInformation; +import app.revanced.integrations.videoplayer.VideoInformation; import app.revanced.integrations.whitelist.Whitelist; import app.revanced.integrations.whitelist.WhitelistType; import app.revanced.integrations.whitelist.requests.WhitelistRequester; diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoInformation.java b/app/src/main/java/app/revanced/integrations/videoplayer/VideoInformation.java similarity index 97% rename from app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoInformation.java rename to app/src/main/java/app/revanced/integrations/videoplayer/VideoInformation.java index 1e3815f980..4d2e947561 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/VideoInformation.java +++ b/app/src/main/java/app/revanced/integrations/videoplayer/VideoInformation.java @@ -1,4 +1,4 @@ -package app.revanced.integrations.sponsorblock.player; +package app.revanced.integrations.videoplayer; import app.revanced.integrations.utils.LogHelper; diff --git a/app/src/main/java/app/revanced/integrations/whitelist/Whitelist.java b/app/src/main/java/app/revanced/integrations/whitelist/Whitelist.java index 80f950e3c8..7d5b139269 100644 --- a/app/src/main/java/app/revanced/integrations/whitelist/Whitelist.java +++ b/app/src/main/java/app/revanced/integrations/whitelist/Whitelist.java @@ -1,6 +1,6 @@ package app.revanced.integrations.whitelist; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.channelName; +import static app.revanced.integrations.videoplayer.VideoInformation.channelName; import static app.revanced.integrations.sponsorblock.player.ui.SlimButtonContainer.adBlockButton; import static app.revanced.integrations.sponsorblock.player.ui.SlimButtonContainer.sbWhitelistButton; import static app.revanced.integrations.sponsorblock.StringRef.str; @@ -21,7 +21,7 @@ import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.sponsorblock.player.ChannelModel; -import app.revanced.integrations.sponsorblock.player.VideoInformation; +import app.revanced.integrations.videoplayer.VideoInformation; import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.SharedPrefHelper; diff --git a/app/src/main/java/app/revanced/integrations/whitelist/requests/WhitelistRequester.java b/app/src/main/java/app/revanced/integrations/whitelist/requests/WhitelistRequester.java index 19a90eeea5..2f8b30b3d8 100644 --- a/app/src/main/java/app/revanced/integrations/whitelist/requests/WhitelistRequester.java +++ b/app/src/main/java/app/revanced/integrations/whitelist/requests/WhitelistRequester.java @@ -1,6 +1,6 @@ package app.revanced.integrations.whitelist.requests; -import static app.revanced.integrations.sponsorblock.player.VideoInformation.currentVideoId; +import static app.revanced.integrations.videoplayer.VideoInformation.currentVideoId; import static app.revanced.integrations.utils.ReVancedUtils.runOnMainThread; import static app.revanced.integrations.sponsorblock.StringRef.str;