Skip to content

Commit

Permalink
feat(YouTube - Return YouTube Dislike): Support version 18.37.36 (#490
Browse files Browse the repository at this point in the history
)

Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
  • Loading branch information
oSumAtrIX and LisoUseInAIKyrios committed Oct 7, 2023
1 parent d4b859d commit 245c3b3
Show file tree
Hide file tree
Showing 9 changed files with 661 additions and 429 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.*;

Expand All @@ -13,12 +14,24 @@

abstract class FilterGroup<T> {
final static class FilterGroupResult {
SettingsEnum setting;
boolean filtered;
private SettingsEnum setting;
private int matchedIndex;
private int matchedLength;
// In the future it might be useful to include which pattern matched,
// but for now that is not needed.

FilterGroupResult() {
this(null, -1, 0);
}

FilterGroupResult(SettingsEnum setting, boolean filtered) {
FilterGroupResult(SettingsEnum setting, int matchedIndex, int matchedLength) {
setValues(setting, matchedIndex, matchedLength);
}

public void setValues(SettingsEnum setting, int matchedIndex, int matchedLength) {
this.setting = setting;
this.filtered = filtered;
this.matchedIndex = matchedIndex;
this.matchedLength = matchedLength;
}

/**
Expand All @@ -30,7 +43,21 @@ public SettingsEnum getSetting() {
}

public boolean isFiltered() {
return filtered;
return matchedIndex >= 0;
}

/**
* Matched index of first pattern that matched, or -1 if nothing matched.
*/
public int getMatchedIndex() {
return matchedIndex;
}

/**
* Length of the matched filter pattern.
*/
public int getMatchedLength() {
return matchedLength;
}
}

Expand Down Expand Up @@ -81,7 +108,21 @@ public StringFilterGroup(final SettingsEnum setting, final String... filters) {

@Override
public FilterGroupResult check(final String string) {
return new FilterGroupResult(setting, isEnabled() && ReVancedUtils.containsAny(string, filters));
int matchedIndex = -1;
int matchedLength = 0;
if (isEnabled()) {
for (String pattern : filters) {
if (!string.isEmpty()) {
final int indexOf = pattern.indexOf(string);
if (indexOf >= 0) {
matchedIndex = indexOf;
matchedLength = pattern.length();
break;
}
}
}
}
return new FilterGroupResult(setting, matchedIndex, matchedLength);
}
}

Expand Down Expand Up @@ -155,19 +196,22 @@ private synchronized void buildFailurePatterns() {

@Override
public FilterGroupResult check(final byte[] bytes) {
var matched = false;
int matchedLength = 0;
int matchedIndex = -1;
if (isEnabled()) {
if (failurePatterns == null) {
buildFailurePatterns(); // Lazy load.
}
for (int i = 0, length = filters.length; i < length; i++) {
if (indexOf(bytes, filters[i], failurePatterns[i]) >= 0) {
matched = true;
byte[] filter = filters[i];
matchedIndex = indexOf(bytes, filter, failurePatterns[i]);
if (matchedIndex >= 0) {
matchedLength = filter.length;
break;
}
}
}
return new FilterGroupResult(setting, matched);
return new FilterGroupResult(setting, matchedIndex, matchedLength);
}
}

Expand Down Expand Up @@ -204,11 +248,10 @@ protected final synchronized void buildSearch() {
continue;
}
for (V pattern : group.filters) {
search.addPattern(pattern, (textSearched, matchedStartIndex, callbackParameter) -> {
search.addPattern(pattern, (textSearched, matchedStartIndex, matchedLength, callbackParameter) -> {
if (group.isEnabled()) {
FilterGroup.FilterGroupResult result = (FilterGroup.FilterGroupResult) callbackParameter;
result.setting = group.setting;
result.filtered = true;
result.setValues(group.setting, matchedStartIndex, matchedLength);
return true;
}
return false;
Expand Down Expand Up @@ -241,9 +284,10 @@ protected FilterGroup.FilterGroupResult check(V stack) {
if (search == null) {
buildSearch(); // Lazy load.
}
FilterGroup.FilterGroupResult result = new FilterGroup.FilterGroupResult(null, false);
FilterGroup.FilterGroupResult result = new FilterGroup.FilterGroupResult();
search.matches(stack, result);
return result;

}

protected abstract TrieSearch<V> createSearchGraph();
Expand Down Expand Up @@ -399,7 +443,7 @@ private static <T> void filterGroupLists(TrieSearch<T> pathSearchTree,
continue;
}
for (T pattern : group.filters) {
pathSearchTree.addPattern(pattern, (textSearched, matchedStartIndex, callbackParameter) -> {
pathSearchTree.addPattern(pattern, (textSearched, matchedStartIndex, matchedLength, callbackParameter) -> {
if (!group.isEnabled()) return false;
LithoFilterParameters parameters = (LithoFilterParameters) callbackParameter;
return filter.isFiltered(parameters.identifier, parameters.path, parameters.protoBuffer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package app.revanced.integrations.patches.components;

import android.os.Build;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.nio.charset.StandardCharsets;

import app.revanced.integrations.patches.ReturnYouTubeDislikePatch;
import app.revanced.integrations.settings.SettingsEnum;

@RequiresApi(api = Build.VERSION_CODES.N)
public final class ReturnYouTubeDislikeFilterPatch extends Filter {

private final ByteArrayFilterGroupList videoIdFilterGroup = new ByteArrayFilterGroupList();

public ReturnYouTubeDislikeFilterPatch() {
pathFilterGroupList.addAll(
new StringFilterGroup(SettingsEnum.RYD_SHORTS, "|shorts_dislike_button.eml|")
);
// After the dislikes 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 ByteArrayAsStringFilterGroup(null, "ic_right_dislike_on_shadowed"),
// Video was not already disliked.
new ByteArrayAsStringFilterGroup(null, "ic_right_dislike_off_shadowed")
);
}

@Override
public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
FilterGroup.FilterGroupResult result = videoIdFilterGroup.check(protobufBufferArray);
if (result.isFiltered()) {
// The video length must be hard coded to 11, as there is additional ASCII text that
// appears immediately after the id if the dislike button is already selected.
final int videoIdLength = 11;
final int subStringSearchStartIndex = result.getMatchedIndex() + result.getMatchedLength();
String videoId = findSubString(protobufBufferArray, subStringSearchStartIndex, videoIdLength);
if (videoId != null) {
ReturnYouTubeDislikePatch.newVideoLoaded(videoId, true);
}
}

return false;
}

/**
* Find an exact length ASCII substring starting from a given index.
*
* Similar to the String finding code in {@link LithoFilterPatch},
* but refactoring it to also handle this use case became messy and overly complicated.
*/
@Nullable
private static String findSubString(byte[] buffer, int bufferStartIndex, int subStringLength) {
// Valid ASCII values (ignore control characters).
final int minimumAscii = 32; // 32 = space character
final int maximumAscii = 126; // 127 = delete character

final int bufferLength = buffer.length;
int start = bufferStartIndex;
int end = bufferStartIndex;
do {
final int value = buffer[end];
if (value < minimumAscii || value > maximumAscii) {
start = end + 1;
} else if (end - start == subStringLength) {
return new String(buffer, start, subStringLength, StandardCharsets.US_ASCII);
}
end++;
} while (end < bufferLength);

return null;
}
}
Loading

0 comments on commit 245c3b3

Please sign in to comment.