chore: Merge branch dev to main (#505)

This commit is contained in:
oSumAtrIX 2023-11-04 22:11:22 +01:00 committed by GitHub
commit 3344375fb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 304 additions and 173 deletions

View File

@ -1,3 +1,74 @@
# [0.121.0-dev.7](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.6...v0.121.0-dev.7) (2023-11-03)
### Bug Fixes
* **YouTube - Player flyout menu:** Restore functionality ([#502](https://github.com/ReVanced/revanced-integrations/issues/502)) ([c048527](https://github.com/ReVanced/revanced-integrations/commit/c048527dc0bc6b1b3de9c451ca909aab7ad93d0f))
# [0.121.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.5...v0.121.0-dev.6) (2023-10-25)
### Bug Fixes
* **YouTube - Client spoof:** Set the client version correctly ([f203731](https://github.com/ReVanced/revanced-integrations/commit/f2037316d36f99ef79ae5792e34d8616ecd31c80))
# [0.121.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.4...v0.121.0-dev.5) (2023-10-25)
### Bug Fixes
* **YouTube - Disable suggested video end screen:** Hide the view once possible ([df27822](https://github.com/ReVanced/revanced-integrations/commit/df278222e8814612797e55e616d4ebc075cafb92))
### Features
* **YouTube - Disable precise seeking gesture:** Use better patch name ([2453d30](https://github.com/ReVanced/revanced-integrations/commit/2453d30970ac59d78647386f4fe5d904dbc145e4))
* **YouTube:** Add `Enable old seekbar thumbnails` patch ([75297a5](https://github.com/ReVanced/revanced-integrations/commit/75297a52c1c5f7c2b928964d08b055380f4a08fe))
# [0.121.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.3...v0.121.0-dev.4) (2023-10-25)
### Bug Fixes
* **YouTube - ReturnYouTubeDislike:** Use API back off if client connection fails for any reason ([#509](https://github.com/ReVanced/revanced-integrations/issues/509)) ([40cfa1e](https://github.com/ReVanced/revanced-integrations/commit/40cfa1e9af2b064b464c4d03d5c28b5932621d62))
# [0.121.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.2...v0.121.0-dev.3) (2023-10-24)
### Features
* **YouTube:** Add `Disable fullscreen ambient mode` patch ([bf50711](https://github.com/ReVanced/revanced-integrations/commit/bf5071107b8bc88ac6562d45bfa28bdab8e566c7))
* **YouTube:** Add `Disable suggested video end screen` patch ([6bd5aae](https://github.com/ReVanced/revanced-integrations/commit/6bd5aae9772e80809dbee9f8fffc1247364a9a13))
# [0.121.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.121.0-dev.1...v0.121.0-dev.2) (2023-10-24)
### Bug Fixes
* **YouTube - ReturnYouTubeDislike:** Fix RYD prefetching home feed Shorts ([#508](https://github.com/ReVanced/revanced-integrations/issues/508)) ([98c91af](https://github.com/ReVanced/revanced-integrations/commit/98c91af130b57322aa98a3e66ec0acad26bfc7d6))
# [0.121.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.120.1-dev.3...v0.121.0-dev.1) (2023-10-23)
### Features
* **YouTube - Hide layout components:** Hide video quality menu footer ([04608d3](https://github.com/ReVanced/revanced-integrations/commit/04608d32e88d184e4662a71498d7a49c1fbbdb25))
## [0.120.1-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.120.1-dev.2...v0.120.1-dev.3) (2023-10-21)
### Bug Fixes
* **YouTube - Custom filter:** Fix app crash if invalid character is used in custom filter ([#506](https://github.com/ReVanced/revanced-integrations/issues/506)) ([debd0a2](https://github.com/ReVanced/revanced-integrations/commit/debd0a2e1101e543161390fd3ced6bda19030155))
## [0.120.1-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.120.1-dev.1...v0.120.1-dev.2) (2023-10-20)
### Reverts
* Revert "fix(YouTube - Minimized playback): Fix pip incorrectly showing for Short playback (#504)" ([c1c7e3b](https://github.com/ReVanced/revanced-integrations/commit/c1c7e3b5964394de6af39f6fb83d667eba174f0a)), closes [#504](https://github.com/ReVanced/revanced-integrations/issues/504)
* Revert "chore(release): 0.120.1-dev.1 [skip ci]" ([e68f558](https://github.com/ReVanced/revanced-integrations/commit/e68f558e9ccac4c6e0d9113b3f134e89edd2233f))
# [0.120.0](https://github.com/ReVanced/revanced-integrations/compare/v0.119.2...v0.120.0) (2023-10-20)

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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));
}
}

View File

@ -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.

View File

@ -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) {

View File

@ -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);

View File

@ -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.

View File

@ -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");

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
android.useAndroidX = true
version = 0.120.0
version = 0.121.0-dev.7