mirror of
https://github.com/revanced/revanced-patches
synced 2025-02-14 14:16:50 +01:00
chore: Merge branch dev
to main
(#505)
This commit is contained in:
commit
3f4ee6685d
@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
/** @noinspection unused*/
|
||||
public final class DisableFullscreenAmbientModePatch {
|
||||
public static boolean enableFullScreenAmbientMode() {
|
||||
return !SettingsEnum.DISABLE_FULLSCREEN_AMBIENT_MODE.getBoolean();
|
||||
}
|
||||
}
|
@ -4,14 +4,14 @@ import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public final class DisableFineScrubbingGesturePatch {
|
||||
public final class DisablePreciseSeekingGesturePatch {
|
||||
/**
|
||||
* Disables the fine scrubbing gesture.
|
||||
* Disables the gesture that is used to seek precisely.
|
||||
* @param tracker The velocity tracker that is used to determine the gesture.
|
||||
* @param event The motion event that is used to determine the gesture.
|
||||
*/
|
||||
public static void disableGesture(VelocityTracker tracker, MotionEvent event) {
|
||||
if (SettingsEnum.DISABLE_FINE_SCRUBBING_GESTURE.getBoolean()) return;
|
||||
if (SettingsEnum.DISABLE_PRECISE_SEEKING_GESTURE.getBoolean()) return;
|
||||
|
||||
tracker.addMovement(event);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
/** @noinspection unused*/
|
||||
public final class DisableSuggestedVideoEndScreenPatch {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static View lastView;
|
||||
|
||||
public static void closeEndScreen(final ImageView imageView) {
|
||||
if (!SettingsEnum.DISABLE_SUGGESTED_VIDEO_END_SCREEN.getBoolean()) return;
|
||||
|
||||
// Get the view which can be listened to for layout changes.
|
||||
final var parent = imageView.getParent().getParent();
|
||||
|
||||
// Prevent adding the listener multiple times.
|
||||
if (lastView == parent) return;
|
||||
|
||||
lastView = (ViewGroup)parent;
|
||||
lastView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) -> imageView.performClick());
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public final class EnableOldSeekbarThumbnailsPatch {
|
||||
public static boolean enableOldSeekbarThumbnails() {
|
||||
return !SettingsEnum.ENABLE_OLD_SEEKBAR_THUMBNAILS.getBoolean();
|
||||
}
|
||||
}
|
@ -404,11 +404,14 @@ public class ReturnYouTubeDislikePatch {
|
||||
/**
|
||||
* Injection point. Uses 'playback response' video id hook to preload RYD.
|
||||
*/
|
||||
public static void preloadVideoId(@NonNull String videoId) {
|
||||
if (!SettingsEnum.RYD_ENABLED.getBoolean()) {
|
||||
public static void preloadVideoId(@NonNull String videoId, boolean videoIsOpeningOrPlaying) {
|
||||
// Shorts shelf in home and subscription feed causes player response hook to be called,
|
||||
// and the 'is opening/playing' parameter will be false.
|
||||
// This hook will be called again when the Short is actually opened.
|
||||
if (!videoIsOpeningOrPlaying || !SettingsEnum.RYD_ENABLED.getBoolean()) {
|
||||
return;
|
||||
}
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneOrHidden()) {
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean() && PlayerType.getCurrent().isNoneHiddenOrSlidingMinimized()) {
|
||||
return;
|
||||
}
|
||||
if (videoId.equals(lastPrefetchedVideoId)) {
|
||||
@ -471,12 +474,13 @@ public class ReturnYouTubeDislikePatch {
|
||||
if (videoIdIsSame(currentVideoData, videoId)) {
|
||||
return;
|
||||
}
|
||||
currentVideoData = ReturnYouTubeDislike.getFetchForVideoId(videoId);
|
||||
ReturnYouTubeDislike data = ReturnYouTubeDislike.getFetchForVideoId(videoId);
|
||||
// Pre-emptively set the data to short status.
|
||||
// Required to prevent Shorts data from being used on a minimized video in incognito mode.
|
||||
if (isNoneHiddenOrSlidingMinimized) {
|
||||
currentVideoData.setVideoIdIsShort(true);
|
||||
data.setVideoIdIsShort(true);
|
||||
}
|
||||
currentVideoData = data;
|
||||
}
|
||||
|
||||
LogHelper.printDebug(() -> "New video id: " + videoId + " playerType: " + currentPlayerType
|
||||
|
@ -69,7 +69,7 @@ public final class VideoInformation {
|
||||
*
|
||||
* @param videoId The id of the last video loaded.
|
||||
*/
|
||||
public static void setPlayerResponseVideoId(@NonNull String videoId) {
|
||||
public static void setPlayerResponseVideoId(@NonNull String videoId, boolean videoIsOpeningOrPlaying) {
|
||||
if (!playerResponseVideoId.equals(videoId)) {
|
||||
LogHelper.printDebug(() -> "New player response video id: " + videoId);
|
||||
playerResponseVideoId = videoId;
|
||||
|
@ -120,6 +120,11 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
"inline_expander"
|
||||
);
|
||||
|
||||
final var videoQualityMenuFooter = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_VIDEO_QUALITY_MENU_FOOTER,
|
||||
"quality_sheet_footer"
|
||||
);
|
||||
|
||||
final var chapters = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_CHAPTERS,
|
||||
"macro_markers_carousel"
|
||||
@ -196,6 +201,7 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
joinMembership,
|
||||
medicalPanel,
|
||||
notifyMe,
|
||||
videoQualityMenuFooter,
|
||||
infoPanel,
|
||||
subscribersCommunityGuidelines,
|
||||
channelGuidelines,
|
||||
|
@ -128,8 +128,20 @@ class StringFilterGroup extends FilterGroup<String> {
|
||||
|
||||
final class CustomFilterGroup extends StringFilterGroup {
|
||||
|
||||
public CustomFilterGroup(final SettingsEnum setting, final SettingsEnum filter) {
|
||||
super(setting, filter.getString().split("\\s+"));
|
||||
private static String[] getFilterPatterns(SettingsEnum setting) {
|
||||
String[] patterns = setting.getString().split("\\s+");
|
||||
for (String pattern : patterns) {
|
||||
if (!StringTrieSearch.isValidPattern(pattern)) {
|
||||
ReVancedUtils.showToastLong("Invalid custom filter, resetting to default");
|
||||
setting.saveValue(setting.defaultValue);
|
||||
return getFilterPatterns(setting);
|
||||
}
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
|
||||
public CustomFilterGroup(SettingsEnum setting, SettingsEnum filter) {
|
||||
super(setting, getFilterPatterns(filter));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,26 +6,38 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.shared.PlayerType;
|
||||
|
||||
public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||
|
||||
// Search the buffer only if the flyout menu identifier is found.
|
||||
// Search the buffer only if the flyout menu path is found.
|
||||
// Handle the searching in this class instead of adding to the global filter group (which searches all the time)
|
||||
private final ByteArrayFilterGroupList flyoutFilterGroupList = new ByteArrayFilterGroupList();
|
||||
|
||||
private final ByteArrayFilterGroup exception;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public PlayerFlyoutMenuItemsFilter() {
|
||||
identifierFilterGroupList.addAll(new StringFilterGroup(null, "overflow_menu_item.eml|"));
|
||||
exception = new ByteArrayAsStringFilterGroup(
|
||||
// Whitelist Quality menu item when "Hide Additional settings menu" is enabled
|
||||
SettingsEnum.HIDE_ADDITIONAL_SETTINGS_MENU,
|
||||
"quality_sheet"
|
||||
);
|
||||
|
||||
// Using pathFilterGroupList due to new flyout panel(A/B)
|
||||
pathFilterGroupList.addAll(
|
||||
new StringFilterGroup(null, "overflow_menu_item.eml|")
|
||||
);
|
||||
|
||||
flyoutFilterGroupList.addAll(
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_QUALITY_MENU,
|
||||
"yt_outline_gear"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_CAPTIONS_MENU,
|
||||
"closed_caption"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_ADDITIONAL_SETTINGS_MENU,
|
||||
"yt_outline_gear"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_LOOP_VIDEO_MENU,
|
||||
"yt_outline_arrow_repeat_1_"
|
||||
@ -64,6 +76,10 @@ public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||
@Override
|
||||
boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
// Shorts also use this player flyout panel
|
||||
if (PlayerType.getCurrent().isNoneOrHidden() || exception.check(protobufBufferArray).isFiltered())
|
||||
return false;
|
||||
|
||||
// Only 1 group is added to the parent class, so the matched group must be the overflow menu.
|
||||
if (matchedIndex == 0 && flyoutFilterGroupList.check(protobufBufferArray).isFiltered()) {
|
||||
// Super class handles logging.
|
||||
|
@ -53,9 +53,9 @@ public final class ReturnYouTubeDislikeFilterPatch extends Filter {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void newPlayerResponseVideoId(String videoId) {
|
||||
public static void newPlayerResponseVideoId(String videoId, boolean videoIsOpeningOrPlaying) {
|
||||
try {
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
if (!videoIsOpeningOrPlaying || !SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
return;
|
||||
}
|
||||
synchronized (lastVideoIds) {
|
||||
|
@ -31,7 +31,7 @@ final class PlayerRoutes {
|
||||
|
||||
JSONObject client = new JSONObject();
|
||||
client.put("clientName", "ANDROID");
|
||||
client.put("clientVersion", "18.37.36");
|
||||
client.put("clientVersion", ReVancedUtils.getVersionName());
|
||||
client.put("androidSdkVersion", 34);
|
||||
|
||||
context.put("client", client);
|
||||
|
@ -80,7 +80,7 @@ public class ReturnYouTubeDislike {
|
||||
* How long to retain unsuccessful RYD fetches,
|
||||
* and also the minimum time before retrying again.
|
||||
*/
|
||||
private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 2 * 60 * 1000; // 2 Minutes
|
||||
private static final long CACHE_TIMEOUT_FAILURE_MILLISECONDS = 3 * 60 * 1000; // 3 Minutes
|
||||
|
||||
/**
|
||||
* Unique placeholder character, used to detect if a segmented span already has dislikes added to it.
|
||||
|
@ -32,13 +32,13 @@ public class ReturnYouTubeDislikeApi {
|
||||
/**
|
||||
* {@link #fetchVotes(String)} TCP connection timeout
|
||||
*/
|
||||
private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2000;
|
||||
private static final int API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS = 2 * 1000; // 2 Seconds.
|
||||
|
||||
/**
|
||||
* {@link #fetchVotes(String)} HTTP read timeout.
|
||||
* To locally debug and force timeouts, change this to a very small number (ie: 100)
|
||||
*/
|
||||
private static final int API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS = 5000;
|
||||
private static final int API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS = 5 * 1000; // 5 Seconds.
|
||||
|
||||
/**
|
||||
* Default connection and response timeout for voting and registration.
|
||||
@ -46,7 +46,7 @@ public class ReturnYouTubeDislikeApi {
|
||||
* Voting and user registration runs in the background and has has no urgency
|
||||
* so this can be a larger value.
|
||||
*/
|
||||
private static final int API_REGISTER_VOTE_TIMEOUT_MILLISECONDS = 90000;
|
||||
private static final int API_REGISTER_VOTE_TIMEOUT_MILLISECONDS = 60 * 1000; // 60 Seconds.
|
||||
|
||||
/**
|
||||
* Response code of a successful API call
|
||||
@ -54,31 +54,30 @@ public class ReturnYouTubeDislikeApi {
|
||||
private static final int HTTP_STATUS_CODE_SUCCESS = 200;
|
||||
|
||||
/**
|
||||
* Response code indicating the video id is not for a video that can be voted for.
|
||||
* (it's not a Short or a regular video, and it's likely a YouTube Story)
|
||||
* Indicates a client rate limit has been reached and the client must back off.
|
||||
*/
|
||||
private static final int HTTP_STATUS_CODE_NOT_FOUND = 404;
|
||||
private static final int HTTP_STATUS_CODE_RATE_LIMIT = 429;
|
||||
|
||||
/**
|
||||
* Indicates a client rate limit has been reached
|
||||
* How long to wait until API calls are resumed, if the API requested a back off.
|
||||
* No clear guideline of how long to wait until resuming.
|
||||
*/
|
||||
private static final int RATE_LIMIT_HTTP_STATUS_CODE = 429;
|
||||
private static final int BACKOFF_RATE_LIMIT_MILLISECONDS = 4 * 60 * 1000; // 4 Minutes.
|
||||
|
||||
/**
|
||||
* How long to wait until API calls are resumed, if a rate limit is hit.
|
||||
* No clear guideline of how long to backoff. Using 2 minutes for now.
|
||||
* How long to wait until API calls are resumed, if any connection error occurs.
|
||||
*/
|
||||
private static final int RATE_LIMIT_BACKOFF_SECONDS = 120;
|
||||
private static final int BACKOFF_CONNECTION_ERROR_MILLISECONDS = 60 * 1000; // 60 Seconds.
|
||||
|
||||
/**
|
||||
* Last time a {@link #RATE_LIMIT_HTTP_STATUS_CODE} was reached.
|
||||
* zero if has not been reached.
|
||||
* If non zero, then the system time of when API calls can resume.
|
||||
*/
|
||||
private static volatile long lastTimeRateLimitWasHit; // must be volatile, since different threads read/write to this
|
||||
private static volatile long timeToResumeAPICalls; // must be volatile, since different threads read/write to this
|
||||
|
||||
/**
|
||||
* Number of times {@link #RATE_LIMIT_HTTP_STATUS_CODE} was requested by RYD api.
|
||||
* Does not include network calls attempted while rate limit is in effect
|
||||
* 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;
|
||||
|
||||
@ -165,16 +164,16 @@ public class ReturnYouTubeDislikeApi {
|
||||
* @return True, if api rate limit is in effect.
|
||||
*/
|
||||
private static boolean checkIfRateLimitInEffect(String apiEndPointName) {
|
||||
if (lastTimeRateLimitWasHit == 0) {
|
||||
if (timeToResumeAPICalls == 0) {
|
||||
return false;
|
||||
}
|
||||
final long numberOfSecondsSinceLastRateLimit = (System.currentTimeMillis() - lastTimeRateLimitWasHit) / 1000;
|
||||
if (numberOfSecondsSinceLastRateLimit < RATE_LIMIT_BACKOFF_SECONDS) {
|
||||
LogHelper.printDebug(() -> "Ignoring api call " + apiEndPointName + " as only "
|
||||
+ numberOfSecondsSinceLastRateLimit + " seconds has passed since last rate limit.");
|
||||
return true;
|
||||
final long now = System.currentTimeMillis();
|
||||
if (now > timeToResumeAPICalls) {
|
||||
timeToResumeAPICalls = 0;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
LogHelper.printDebug(() -> "Ignoring api call " + apiEndPointName + " as rate limit is in effect");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,37 +185,33 @@ public class ReturnYouTubeDislikeApi {
|
||||
final double RANDOM_RATE_LIMIT_PERCENTAGE = 0.2; // 20% chance of a triggering a rate limit
|
||||
if (Math.random() < RANDOM_RATE_LIMIT_PERCENTAGE) {
|
||||
LogHelper.printDebug(() -> "Artificially triggering rate limit for debug purposes");
|
||||
httpResponseCode = RATE_LIMIT_HTTP_STATUS_CODE;
|
||||
httpResponseCode = HTTP_STATUS_CODE_RATE_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (httpResponseCode == RATE_LIMIT_HTTP_STATUS_CODE) {
|
||||
lastTimeRateLimitWasHit = System.currentTimeMillis();
|
||||
//noinspection NonAtomicOperationOnVolatileField // don't care, field is used only as an estimate
|
||||
numberOfRateLimitRequestsEncountered++;
|
||||
LogHelper.printDebug(() -> "API rate limit was hit. Stopping API calls for the next "
|
||||
+ RATE_LIMIT_BACKOFF_SECONDS + " seconds");
|
||||
ReVancedUtils.showToastLong(str("revanced_ryd_failure_client_rate_limit_requested"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return httpResponseCode == HTTP_STATUS_CODE_RATE_LIMIT;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NonAtomicOperationOnVolatileField") // do not want to pay performance cost of full synchronization for debug fields that are only estimates anyways
|
||||
private static void updateStatistics(long timeNetworkCallStarted, long timeNetworkCallEnded, boolean connectionError, boolean rateLimitHit) {
|
||||
@SuppressWarnings("NonAtomicOperationOnVolatileField") // Don't care, fields are estimates.
|
||||
private static void updateRateLimitAndStats(long timeNetworkCallStarted, boolean connectionError, boolean rateLimitHit) {
|
||||
if (connectionError && rateLimitHit) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
final long responseTimeOfFetchCall = timeNetworkCallEnded - timeNetworkCallStarted;
|
||||
final long responseTimeOfFetchCall = System.currentTimeMillis() - timeNetworkCallStarted;
|
||||
fetchCallResponseTimeTotal += responseTimeOfFetchCall;
|
||||
fetchCallResponseTimeMin = (fetchCallResponseTimeMin == 0) ? responseTimeOfFetchCall : Math.min(responseTimeOfFetchCall, fetchCallResponseTimeMin);
|
||||
fetchCallResponseTimeMax = Math.max(responseTimeOfFetchCall, fetchCallResponseTimeMax);
|
||||
fetchCallCount++;
|
||||
if (connectionError) {
|
||||
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_CONNECTION_ERROR_MILLISECONDS;
|
||||
fetchCallResponseTimeLast = responseTimeOfFetchCall;
|
||||
fetchCallNumberOfFailures++;
|
||||
} else if (rateLimitHit) {
|
||||
LogHelper.printDebug(() -> "API rate limit was hit. Stopping API calls for the next "
|
||||
+ BACKOFF_RATE_LIMIT_MILLISECONDS + " seconds");
|
||||
timeToResumeAPICalls = System.currentTimeMillis() + BACKOFF_RATE_LIMIT_MILLISECONDS;
|
||||
numberOfRateLimitRequestsEncountered++;
|
||||
fetchCallResponseTimeLast = FETCH_CALL_RESPONSE_TIME_VALUE_RATE_LIMIT;
|
||||
ReVancedUtils.showToastLong(str("revanced_ryd_failure_client_rate_limit_requested"));
|
||||
} else {
|
||||
fetchCallResponseTimeLast = responseTimeOfFetchCall;
|
||||
}
|
||||
@ -262,27 +257,22 @@ public class ReturnYouTubeDislikeApi {
|
||||
final int responseCode = connection.getResponseCode();
|
||||
if (checkIfRateLimitWasHit(responseCode)) {
|
||||
connection.disconnect(); // rate limit hit, should disconnect
|
||||
updateStatistics(timeNetworkCallStarted, System.currentTimeMillis(),false, true);
|
||||
updateRateLimitAndStats(timeNetworkCallStarted, false, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
|
||||
final long timeNetworkCallEnded = System.currentTimeMillis(); // record end time before parsing
|
||||
// do not disconnect, the same server connection will likely be used again soon
|
||||
JSONObject json = Requester.parseJSONObject(connection);
|
||||
try {
|
||||
RYDVoteData votingData = new RYDVoteData(json);
|
||||
updateStatistics(timeNetworkCallStarted, timeNetworkCallEnded, false, false);
|
||||
updateRateLimitAndStats(timeNetworkCallStarted, false, false);
|
||||
LogHelper.printDebug(() -> "Voting data fetched: " + votingData);
|
||||
return votingData;
|
||||
} catch (JSONException ex) {
|
||||
LogHelper.printException(() -> "Failed to parse video: " + videoId + " json: " + json, ex);
|
||||
// fall thru to update statistics
|
||||
}
|
||||
} else if (responseCode == HTTP_STATUS_CODE_NOT_FOUND) {
|
||||
// normal response when viewing YouTube Stories (cannot vote for these)
|
||||
LogHelper.printDebug(() -> "Video has no like/dislikes (video is a YouTube Story?): " + videoId);
|
||||
return null; // do not updated connection statistics
|
||||
} else {
|
||||
handleConnectionError(str("revanced_ryd_failure_connection_status_code", responseCode), null);
|
||||
}
|
||||
@ -296,7 +286,7 @@ public class ReturnYouTubeDislikeApi {
|
||||
LogHelper.printException(() -> "Failed to fetch votes", ex, str("revanced_ryd_failure_generic", ex.getMessage()));
|
||||
}
|
||||
|
||||
updateStatistics(timeNetworkCallStarted, System.currentTimeMillis(), true, false);
|
||||
updateRateLimitAndStats(timeNetworkCallStarted, true, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -311,7 +301,7 @@ public class ReturnYouTubeDislikeApi {
|
||||
return null;
|
||||
}
|
||||
String userId = randomString(36);
|
||||
LogHelper.printDebug(() -> "Trying to register new user: " + userId);
|
||||
LogHelper.printDebug(() -> "Trying to register new user");
|
||||
|
||||
HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_REGISTRATION, userId);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
@ -55,6 +55,7 @@ public enum SettingsEnum {
|
||||
HIDE_CHANNEL_BAR("revanced_hide_channel_bar", BOOLEAN, FALSE),
|
||||
HIDE_CHANNEL_MEMBER_SHELF("revanced_hide_channel_member_shelf", BOOLEAN, TRUE),
|
||||
HIDE_EXPANDABLE_CHIP("revanced_hide_expandable_chip", BOOLEAN, TRUE),
|
||||
HIDE_VIDEO_QUALITY_MENU_FOOTER("revanced_hide_video_quality_menu_footer", BOOLEAN, TRUE),
|
||||
HIDE_CHAPTERS("revanced_hide_chapters", BOOLEAN, TRUE),
|
||||
HIDE_COMMUNITY_GUIDELINES("revanced_hide_community_guidelines", BOOLEAN, TRUE),
|
||||
HIDE_COMMUNITY_POSTS("revanced_hide_community_posts", BOOLEAN, FALSE),
|
||||
@ -146,14 +147,16 @@ public enum SettingsEnum {
|
||||
HIDE_SHORTS_CHANNEL_BAR("revanced_hide_shorts_channel_bar", BOOLEAN, FALSE),
|
||||
HIDE_SHORTS_NAVIGATION_BAR("revanced_hide_shorts_navigation_bar", BOOLEAN, TRUE, true),
|
||||
HIDE_SHORTS("revanced_hide_shorts", BOOLEAN, FALSE, true),
|
||||
|
||||
DISABLE_SUGGESTED_VIDEO_END_SCREEN("revanced_disable_suggested_video_end_screen", BOOLEAN, TRUE),
|
||||
ENABLE_OLD_SEEKBAR_THUMBNAILS("revanced_enable_old_seekbar_thumbnails", BOOLEAN, TRUE),
|
||||
DISABLE_FULLSCREEN_AMBIENT_MODE("revanced_disable_fullscreen_ambient_mode", BOOLEAN, TRUE, true),
|
||||
ALT_THUMBNAIL("revanced_alt_thumbnail", BOOLEAN, FALSE),
|
||||
ALT_THUMBNAIL_TYPE("revanced_alt_thumbnail_type", INTEGER, 2, parents(ALT_THUMBNAIL)),
|
||||
ALT_THUMBNAIL_FAST_QUALITY("revanced_alt_thumbnail_fast_quality", BOOLEAN, FALSE, parents(ALT_THUMBNAIL)),
|
||||
|
||||
//Player flyout menu items
|
||||
HIDE_QUALITY_MENU("revanced_hide_player_flyout_quality", BOOLEAN, FALSE),
|
||||
HIDE_CAPTIONS_MENU("revanced_hide_player_flyout_captions", BOOLEAN, FALSE),
|
||||
HIDE_ADDITIONAL_SETTINGS_MENU("revanced_hide_player_flyout_additional_settings", BOOLEAN, FALSE),
|
||||
HIDE_LOOP_VIDEO_MENU("revanced_hide_player_flyout_loop_video", BOOLEAN, FALSE),
|
||||
HIDE_AMBIENT_MODE_MENU("revanced_hide_player_flyout_ambient_mode", BOOLEAN, FALSE),
|
||||
HIDE_REPORT_MENU("revanced_hide_player_flyout_report", BOOLEAN, TRUE),
|
||||
@ -169,6 +172,7 @@ public enum SettingsEnum {
|
||||
EXTERNAL_BROWSER("revanced_external_browser", BOOLEAN, TRUE, true),
|
||||
AUTO_REPEAT("revanced_auto_repeat", BOOLEAN, FALSE),
|
||||
SEEKBAR_TAPPING("revanced_seekbar_tapping", BOOLEAN, TRUE),
|
||||
DISABLE_PRECISE_SEEKING_GESTURE("revanced_disable_precise_seeking_gesture", BOOLEAN, TRUE),
|
||||
DISABLE_FINE_SCRUBBING_GESTURE("revanced_disable_fine_scrubbing_gesture", BOOLEAN, TRUE),
|
||||
SPOOF_SIGNATURE("revanced_spoof_signature_verification_enabled", BOOLEAN, TRUE, true,
|
||||
"revanced_spoof_signature_verification_enabled_user_dialog_message"),
|
||||
@ -378,6 +382,7 @@ public enum SettingsEnum {
|
||||
// region Migration
|
||||
|
||||
migrateOldSettingToNew(HIDE_VIDEO_WATERMARK, HIDE_VIDEO_CHANNEL_WATERMARK);
|
||||
migrateOldSettingToNew(DISABLE_FINE_SCRUBBING_GESTURE, DISABLE_PRECISE_SEEKING_GESTURE);
|
||||
|
||||
// Do _not_ delete this SB private user id migration property until sometime in 2024.
|
||||
// This is the only setting that cannot be reconfigured if lost,
|
||||
|
@ -1,10 +1,5 @@
|
||||
package app.revanced.integrations.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class ByteTrieSearch extends TrieSearch<byte[]> {
|
||||
|
||||
private static final class ByteTrieNode extends TrieNode<byte[]> {
|
||||
@ -22,35 +17,25 @@ public final class ByteTrieSearch extends TrieSearch<byte[]> {
|
||||
char getCharValue(byte[] text, int index) {
|
||||
return (char) text[index];
|
||||
}
|
||||
@Override
|
||||
int getTextLength(byte[] text) {
|
||||
return text.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the pattern is valid to add to this instance.
|
||||
*/
|
||||
public static boolean isValidPattern(byte[] pattern) {
|
||||
for (byte b : pattern) {
|
||||
if (TrieNode.isInvalidRange((char) b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public ByteTrieSearch() {
|
||||
super(new ByteTrieNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull byte[] pattern) {
|
||||
super.addPattern(pattern, pattern.length, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull byte[] pattern, @NonNull TriePatternMatchedCallback<byte[]> callback) {
|
||||
super.addPattern(pattern, pattern.length, Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull byte[] textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) {
|
||||
return super.matches(textToSearch, textToSearch.length, startIndex, endIndex, callbackParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull byte[] textToSearch, int startIndex) {
|
||||
return matches(textToSearch, startIndex, textToSearch.length, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull byte[] textToSearch, @Nullable Object callbackParameter) {
|
||||
return matches(textToSearch,0, textToSearch.length, callbackParameter);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,5 @@
|
||||
package app.revanced.integrations.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Text pattern searching using a prefix tree (trie).
|
||||
*/
|
||||
@ -25,34 +20,25 @@ public final class StringTrieSearch extends TrieSearch<String> {
|
||||
char getCharValue(String text, int index) {
|
||||
return text.charAt(index);
|
||||
}
|
||||
@Override
|
||||
int getTextLength(String text) {
|
||||
return text.length();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the pattern is valid to add to this instance.
|
||||
*/
|
||||
public static boolean isValidPattern(String pattern) {
|
||||
for (int i = 0, length = pattern.length(); i < length; i++) {
|
||||
if (TrieNode.isInvalidRange(pattern.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public StringTrieSearch() {
|
||||
super(new StringTrieNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull String pattern) {
|
||||
super.addPattern(pattern, pattern.length(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull String pattern, @NonNull TriePatternMatchedCallback<String> callback) {
|
||||
super.addPattern(pattern, pattern.length(), Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull String textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) {
|
||||
return super.matches(textToSearch, textToSearch.length(), startIndex, endIndex, callbackParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull String textToSearch, @Nullable Object callbackParameter) {
|
||||
return matches(textToSearch, 0, textToSearch.length(), callbackParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull String textToSearch, int startIndex) {
|
||||
return matches(textToSearch, startIndex, textToSearch.length(), null);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public abstract class TrieSearch<T> {
|
||||
private static final int CHILDREN_ARRAY_INCREASE_SIZE_INCREMENT = 2;
|
||||
private static final int CHILDREN_ARRAY_MAX_SIZE = MAX_VALID_CHAR - MIN_VALID_CHAR + 1;
|
||||
|
||||
private static boolean isInvalidRange(char character) {
|
||||
static boolean isInvalidRange(char character) {
|
||||
return character < MIN_VALID_CHAR || character > MAX_VALID_CHAR;
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ public abstract class TrieSearch<T> {
|
||||
}
|
||||
|
||||
private static int hashIndexForTableSize(int arraySize, char nodeValue) {
|
||||
return (nodeValue - MIN_VALID_CHAR) % arraySize;
|
||||
return nodeValue % arraySize;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -300,6 +300,7 @@ public abstract class TrieSearch<T> {
|
||||
|
||||
abstract TrieNode<T> createNode(char nodeValue);
|
||||
abstract char getCharValue(T text, int index);
|
||||
abstract int getTextLength(T text);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,6 +324,23 @@ public abstract class TrieSearch<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pattern that will always return a positive match if found.
|
||||
*
|
||||
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
|
||||
*/
|
||||
public void addPattern(@NonNull T pattern) {
|
||||
addPattern(pattern, root.getTextLength(pattern), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
|
||||
* @param callback Callback to determine if searching should halt when a match is found.
|
||||
*/
|
||||
public void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback<T> callback) {
|
||||
addPattern(pattern, root.getTextLength(pattern), Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
void addPattern(@NonNull T pattern, int patternLength, @Nullable TriePatternMatchedCallback<T> callback) {
|
||||
if (patternLength == 0) return; // Nothing to match
|
||||
|
||||
@ -330,8 +348,38 @@ public abstract class TrieSearch<T> {
|
||||
root.addPattern(pattern, patternLength, 0, callback);
|
||||
}
|
||||
|
||||
final boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex,
|
||||
@Nullable Object callbackParameter) {
|
||||
public final boolean matches(@NonNull T textToSearch) {
|
||||
return matches(textToSearch, 0);
|
||||
}
|
||||
|
||||
public boolean matches(@NonNull T textToSearch, @NonNull Object callbackParameter) {
|
||||
return matches(textToSearch, 0, root.getTextLength(textToSearch),
|
||||
Objects.requireNonNull(callbackParameter));
|
||||
}
|
||||
|
||||
public boolean matches(@NonNull T textToSearch, int startIndex) {
|
||||
return matches(textToSearch, startIndex, root.getTextLength(textToSearch));
|
||||
}
|
||||
|
||||
public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) {
|
||||
return matches(textToSearch, startIndex, endIndex, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches through text, looking for any substring that matches any pattern in this tree.
|
||||
*
|
||||
* @param textToSearch Text to search through.
|
||||
* @param startIndex Index to start searching, inclusive value.
|
||||
* @param endIndex Index to stop matching, exclusive value.
|
||||
* @param callbackParameter Optional parameter passed to the callbacks.
|
||||
* @return If any pattern matched, and it's callback halted searching.
|
||||
*/
|
||||
public boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) {
|
||||
return matches(textToSearch, root.getTextLength(textToSearch), startIndex, endIndex, callbackParameter);
|
||||
}
|
||||
|
||||
private boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex,
|
||||
@Nullable Object callbackParameter) {
|
||||
if (endIndex > textToSearchLength) {
|
||||
throw new IllegalArgumentException("endIndex: " + endIndex
|
||||
+ " is greater than texToSearchLength: " + textToSearchLength);
|
||||
@ -365,41 +413,4 @@ public abstract class TrieSearch<T> {
|
||||
public List<T> getPatterns() {
|
||||
return Collections.unmodifiableList(patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pattern that will always return a positive match if found.
|
||||
*
|
||||
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
|
||||
*/
|
||||
public abstract void addPattern(@NonNull T pattern);
|
||||
|
||||
/**
|
||||
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
|
||||
* @param callback Callback to determine if searching should halt when a match is found.
|
||||
*/
|
||||
public abstract void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback<T> callback);
|
||||
|
||||
|
||||
/**
|
||||
* Searches through text, looking for any substring that matches any pattern in this tree.
|
||||
*
|
||||
* @param textToSearch Text to search through.
|
||||
* @param startIndex Index to start searching, inclusive value.
|
||||
* @param endIndex Index to stop matching, exclusive value.
|
||||
* @param callbackParameter Optional parameter passed to the callbacks.
|
||||
* @return If any pattern matched, and it's callback halted searching.
|
||||
*/
|
||||
public abstract boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter);
|
||||
|
||||
public abstract boolean matches(@NonNull T textToSearch, int startIndex);
|
||||
|
||||
public abstract boolean matches(@NonNull T textToSearch, @Nullable Object callbackParameter);
|
||||
|
||||
public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) {
|
||||
return matches(textToSearch, startIndex, endIndex, null);
|
||||
}
|
||||
|
||||
public final boolean matches(@NonNull T textToSearch) {
|
||||
return matches(textToSearch, 0);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user