Skip to content
This repository has been archived by the owner on Oct 26, 2024. It is now read-only.

Commit

Permalink
fix(YouTube - ReturnYouTubeDislike): Show estimated like count for vi…
Browse files Browse the repository at this point in the history
…deos with hidden likes (#684)
  • Loading branch information
LisoUseInAIKyrios authored Sep 1, 2024
1 parent 55c278d commit 27d2b60
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 134 deletions.
17 changes: 17 additions & 0 deletions app/src/main/java/app/revanced/integrations/shared/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,23 @@ public static boolean isRightToLeftTextLayout() {
return isRightToLeftTextLayout;
}

/**
* @return if the text contains at least 1 number character,
* including any unicode numbers such as Arabic.
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean containsNumber(@NonNull CharSequence text) {
for (int index = 0, length = text.length(); index < length;) {
final int codePoint = Character.codePointAt(text, index);
if (Character.isDigit(codePoint)) {
return true;
}
index += Character.charCount(codePoint);
}

return false;
}

/**
* Safe to call from any thread
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ private static CharSequence onLithoTextLoaded(@NonNull Object conversionContext,
return original;
}

final CharSequence replacement;
if (conversionContextString.contains("segmented_like_dislike_button.eml")) {
// Regular video.
ReturnYouTubeDislike videoData = currentVideoData;
Expand All @@ -235,46 +234,62 @@ private static CharSequence onLithoTextLoaded(@NonNull Object conversionContext,
if (!(original instanceof Spanned)) {
original = new SpannableString(original);
}
replacement = videoData.getDislikesSpanForRegularVideo((Spanned) original,
return videoData.getDislikesSpanForRegularVideo((Spanned) original,
true, isRollingNumber);
} else if (!isRollingNumber && conversionContextString.contains("|shorts_dislike_button.eml|")) {
// Litho Shorts player.
if (!Settings.RYD_SHORTS.get() || Settings.HIDE_SHORTS_DISLIKE_BUTTON.get()) {
// Must clear the current video here, otherwise if the user opens a regular video
// then opens a litho short (while keeping the regular video on screen), then closes the short,
// the original video may show the incorrect dislike value.
clearData();
return original;
}
ReturnYouTubeDislike videoData = lastLithoShortsVideoData;
if (videoData == null) {
// The Shorts litho video id filter did not detect the video id.
// This is normal in incognito mode, but otherwise is abnormal.
Logger.printDebug(() -> "Cannot modify Shorts litho span, data is null");
return original;
}
// Use the correct dislikes data after voting.
if (lithoShortsShouldUseCurrentData) {
lithoShortsShouldUseCurrentData = false;
videoData = currentVideoData;
if (videoData == null) {
Logger.printException(() -> "currentVideoData is null"); // Should never happen
return original;
}
Logger.printDebug(() -> "Using current video data for litho span");
}
replacement = videoData.getDislikeSpanForShort((Spanned) original);
} else {
return original;
}

return replacement;
if (isRollingNumber) {
return original; // No need to check for Shorts in the context.
}

if (conversionContextString.contains("|shorts_dislike_button.eml")) {
return getShortsSpan(original, true);
}

if (conversionContextString.contains("|shorts_like_button.eml")
&& !Utils.containsNumber(original)) {
Logger.printDebug(() -> "Replacing hidden likes count");
return getShortsSpan(original, false);
}
} catch (Exception ex) {
Logger.printException(() -> "onLithoTextLoaded failure", ex);
}
return original;
}

private static CharSequence getShortsSpan(@NonNull CharSequence original, boolean isDislikesSpan) {
// Litho Shorts player.
if (!Settings.RYD_SHORTS.get() || (isDislikesSpan && Settings.HIDE_SHORTS_DISLIKE_BUTTON.get())
|| (!isDislikesSpan && Settings.HIDE_SHORTS_LIKE_BUTTON.get())) {
return original;
}

ReturnYouTubeDislike videoData = lastLithoShortsVideoData;
if (videoData == null) {
// The Shorts litho video id filter did not detect the video id.
// This is normal in incognito mode, but otherwise is abnormal.
Logger.printDebug(() -> "Cannot modify Shorts litho span, data is null");
return original;
}

// Use the correct dislikes data after voting.
if (lithoShortsShouldUseCurrentData) {
if (isDislikesSpan) {
lithoShortsShouldUseCurrentData = false;
}
videoData = currentVideoData;
if (videoData == null) {
Logger.printException(() -> "currentVideoData is null"); // Should never happen
return original;
}
Logger.printDebug(() -> "Using current video data for litho span");
}

return isDislikesSpan
? videoData.getDislikeSpanForShort((Spanned) original)
: videoData.getLikeSpanForShort((Spanned) original);
}

//
// Rolling Number
//
Expand Down Expand Up @@ -597,6 +612,7 @@ public static void preloadVideoId(@NonNull String videoId, boolean isShortAndOpe
Logger.printDebug(() -> "Waiting for prefetch to complete: " + videoId);
fetch.getFetchData(20000); // Any arbitrarily large max wait time.
}

// Set the fields after the fetch completes, so any concurrent calls will also wait.
lastPlayerResponseWasShort = videoIdIsShort;
lastPrefetchedVideoId = videoId;
Expand Down Expand Up @@ -657,6 +673,7 @@ public static void setLastLithoShortsVideoId(@Nullable String videoId) {
clearData();
return;
}

Logger.printDebug(() -> "New litho Shorts video id: " + videoId);
ReturnYouTubeDislike videoData = ReturnYouTubeDislike.getFetchForVideoId(videoId);
videoData.setVideoIdIsShort(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected boolean removeEldestEntry(Entry eldest) {
@SuppressWarnings("unused")
public static void newPlayerResponseVideoId(String videoId, boolean isShortAndOpeningOrPlaying) {
try {
if (!isShortAndOpeningOrPlaying || !Settings.RYD_SHORTS.get()) {
if (!isShortAndOpeningOrPlaying || !Settings.RYD_ENABLED.get() || !Settings.RYD_SHORTS.get()) {
return;
}
synchronized (lastVideoIds) {
Expand All @@ -68,21 +68,28 @@ public static void newPlayerResponseVideoId(String videoId, boolean isShortAndOp
private final ByteArrayFilterGroupList videoIdFilterGroup = new ByteArrayFilterGroupList();

public ReturnYouTubeDislikeFilterPatch() {
// Likes always seems to load before the dislikes, but if this
// ever changes then both likes and dislikes need callbacks.
addPathCallbacks(
new StringFilterGroup(Settings.RYD_SHORTS, "|shorts_dislike_button.eml|")
new StringFilterGroup(null, "|shorts_like_button.eml")
);
// After the dislikes icon name is some binary data and then the video id for that specific short.

// After the likes icon name is some binary data and then the video id for that specific short.
videoIdFilterGroup.addAll(
// Video was previously disliked before video was opened.
new ByteArrayFilterGroup(null, "ic_right_dislike_on_shadowed"),
// Video was not already disliked.
new ByteArrayFilterGroup(null, "ic_right_dislike_off_shadowed")
// Video was previously liked before video was opened.
new ByteArrayFilterGroup(null, "ic_right_like_on_shadowed"),
// Video was not already liked.
new ByteArrayFilterGroup(null, "ic_right_like_off_shadowed")
);
}

@Override
boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
if (!Settings.RYD_ENABLED.get() || !Settings.RYD_SHORTS.get()) {
return false;
}

FilterGroup.FilterGroupResult result = videoIdFilterGroup.check(protobufBufferArray);
if (result.isFiltered()) {
String matchedVideoId = findVideoId(protobufBufferArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public static HttpURLConnection getConnectionFromRoute(String apiUrl, Route rout
public static HttpURLConnection getConnectionFromCompiledRoute(String apiUrl, Route.CompiledRoute route) throws IOException {
String url = apiUrl + route.getCompiledRoute();
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
// Request data is in the URL parameters and no body is sent.
// The calling code must set a length if using a request body.
connection.setFixedLengthStreamingMode(0);
connection.setRequestMethod(route.getMethod().name());
String agentString = System.getProperty("http.agent")
+ "; ReVanced/" + Utils.getAppVersionName()
Expand Down
Loading

0 comments on commit 27d2b60

Please sign in to comment.