diff --git a/CHANGELOG.md b/CHANGELOG.md index c5828c5e..98d4d76c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## [0.111.1-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.111.1-dev.2...v0.111.1-dev.3) (2023-06-27) + + +### Performance Improvements + +* return earlier when possible ([#427](https://github.com/revanced/revanced-integrations/issues/427)) ([12f3f97](https://github.com/revanced/revanced-integrations/commit/12f3f975525863e593216ecf36ca817d162474e1)) + +## [0.111.1-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.111.1-dev.1...v0.111.1-dev.2) (2023-06-25) + + +### Bug Fixes + +* **youtube/disable-fullscreen-panels:** prompt to restart after turning on/off ([#426](https://github.com/revanced/revanced-integrations/issues/426)) ([328ecff](https://github.com/revanced/revanced-integrations/commit/328ecff18bf301ec8993bba49356f9813de1d901)) + +## [0.111.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.111.0...v0.111.1-dev.1) (2023-06-23) + + +### Bug Fixes + +* **youtube/client-spoof:** update settings text for known side effects of spoof signature ([#424](https://github.com/revanced/revanced-integrations/issues/424)) ([d7a3973](https://github.com/revanced/revanced-integrations/commit/d7a3973ef1e6c4443fc4d89f063bc6bf3446bec3)) + # [0.111.0](https://github.com/revanced/revanced-integrations/compare/v0.110.0...v0.111.0) (2023-06-21) diff --git a/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java b/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java index 9edd455f..38bab199 100644 --- a/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java @@ -1,14 +1,12 @@ package app.revanced.integrations.patches; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +import static app.revanced.integrations.utils.ReVancedUtils.containsAny; + import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.shared.PlayerType; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; -import static app.revanced.integrations.utils.ReVancedUtils.containsAny; - public class SpoofSignatureVerificationPatch { /** * Enable/disable all workarounds that are required due to signature spoofing. @@ -37,28 +35,6 @@ public class SpoofSignatureVerificationPatch { "SAFg" // Autoplay in scrim }; - /** - * On app first start, the first video played usually contains a single non-default window setting value - * and all other subtitle settings for the video are (incorrect) default shorts window settings. - * For this situation, the shorts settings must be replaced. - * - * But some videos use multiple text positions on screen (such as https://youtu.be/3hW1rMNC89o), - * and by chance many of the subtitles uses window positions that match a default shorts position. - * To handle these videos, selectively allowing the shorts specific window settings to 'pass thru' unchanged, - * but only if the video contains multiple non-default subtitle window positions. - * - * Do not enable 'pass thru mode' until this many non default subtitle settings are observed for a single video. - */ - private static final int NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU = 2; - - /** - * The number of non default subtitle settings encountered for the current video. - */ - private static int numberOfNonDefaultSettingsObserved; - - @Nullable - private static String currentVideoId; - /** * Injection point. * @@ -121,115 +97,4 @@ public class SpoofSignatureVerificationPatch { } } - /** - * Last WindowsSetting constructor values. Values are checked for changes to reduce log spam. - */ - private static int lastAp, lastAh, lastAv; - private static boolean lastVs, lastSd; - - /** - * Injection point. Overrides values passed into SubtitleWindowSettings constructor. - * - * @param ap anchor position. A bitmask with 6 bit fields, that appears to indicate the layout position on screen - * @param ah anchor horizontal. A percentage [0, 100], that appears to be a horizontal text anchor point - * @param av anchor vertical. A percentage [0, 100], that appears to be a vertical text anchor point - * @param vs appears to indicate if subtitles exist, and the value is always true. - * @param sd function is not entirely clear - */ - public static int[] getSubtitleWindowSettingsOverride(int ap, int ah, int av, boolean vs, boolean sd) { - final boolean signatureSpoofing = SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean(); - if (SettingsEnum.DEBUG.getBoolean()) { - if (ap != lastAp || ah != lastAh || av != lastAv || vs != lastVs || sd != lastSd) { - LogHelper.printDebug(() -> "video: " + VideoInformation.getVideoId() + " spoof: " + signatureSpoofing - + " ap:" + ap + " ah:" + ah + " av:" + av + " vs:" + vs + " sd:" + sd); - lastAp = ap; - lastAh = ah; - lastAv = av; - lastVs = vs; - lastSd = sd; - } - } - - if (!WORKAROUND) { - return new int[]{ap, ah, av}; - } - - // Videos with custom captions that specify screen positions appear to always have correct screen positions (even with spoofing). - // But for auto generated and most other captions, the spoof incorrectly gives various default Shorts caption settings. - // Check for these known default shorts captions parameters, and replace with the known correct values. - // - // If a regular video uses a custom subtitle setting that match a default short setting, - // then this will incorrectly replace the setting. - // But, if the video uses multiple subtitles in different screen locations, then detect the non-default values - // and do not replace any window settings for the video (regardless if they match a shorts default). - if (signatureSpoofing && !PlayerType.getCurrent().isNoneOrHidden() - && numberOfNonDefaultSettingsObserved < NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU) { - for (SubtitleWindowReplacementSettings setting : SubtitleWindowReplacementSettings.values()) { - if (setting.match(ap, ah, av, vs, sd)) { - return setting.replacementSetting(); - } - } - - numberOfNonDefaultSettingsObserved++; - LogHelper.printDebug(() -> - numberOfNonDefaultSettingsObserved < NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU - ? "Non default subtitle found." - : "Multiple non default subtitles found. Allowing all subtitles for this video to pass thru unchanged."); - } - - return new int[]{ap, ah, av}; - } - - /** - * Injection point. - */ - public static void setCurrentVideoId(@NonNull String videoId) { - try { - if (videoId.equals(currentVideoId)) { - return; - } - currentVideoId = videoId; - numberOfNonDefaultSettingsObserved = 0; - } catch (Exception ex) { - LogHelper.printException(() -> "setCurrentVideoId failure", ex); - } - } - - - /** - * Known incorrect default Shorts subtitle parameters, and the corresponding correct (non-Shorts) values. - */ - private enum SubtitleWindowReplacementSettings { - DEFAULT_SHORTS_PARAMETERS_1(10, 50, 0, true, false, - 34, 50, 95), - DEFAULT_SHORTS_PARAMETERS_2(9, 20, 0, true, false, - 34, 50, 90), - DEFAULT_SHORTS_PARAMETERS_3(9, 20, 0, true, true, - 33, 20, 100); - - // original values - final int ap, ah, av; - final boolean vs, sd; - - // replacement int values - final int[] replacement; - - SubtitleWindowReplacementSettings(int ap, int ah, int av, boolean vs, boolean sd, - int replacementAp, int replacementAh, int replacementAv) { - this.ap = ap; - this.ah = ah; - this.av = av; - this.vs = vs; - this.sd = sd; - this.replacement = new int[]{replacementAp, replacementAh, replacementAv}; - } - - boolean match(int ap, int ah, int av, boolean vs, boolean sd) { - return this.ap == ap && this.ah == ah && this.av == av && this.vs == vs && this.sd == sd; - } - - int[] replacementSetting() { - return replacement; - } - } } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index 314dabcb..95c68b41 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -83,9 +83,10 @@ final class CustomFilterGroup extends StringFilterGroup { class ByteArrayFilterGroup extends FilterGroup { // Modified implementation from https://stackoverflow.com/a/1507813 private int indexOf(final byte[] data, final byte[] pattern) { + if (data.length == 0) + return -1; // Computes the failure function using a boot-strapping process, // where the pattern is matched against itself. - final int[] failure = new int[pattern.length]; int j = 0; @@ -103,7 +104,6 @@ class ByteArrayFilterGroup extends FilterGroup { // KMP matching algorithm. j = 0; - if (data.length == 0) return -1; for (int i = 0; i < data.length; i++) { while (j > 0 && pattern[j] != data[i]) { @@ -130,7 +130,8 @@ class ByteArrayFilterGroup extends FilterGroup { public FilterGroupResult check(final byte[] bytes) { var matched = false; for (byte[] filter : filters) { - if (indexOf(bytes, filter) == -1) continue; + if (indexOf(bytes, filter) == -1) + continue; matched = true; break; @@ -181,7 +182,8 @@ abstract class FilterGroupList> implements Iterable< protected boolean contains(final V stack) { for (T filterGroup : this) { - if (!filterGroup.isEnabled()) continue; + if (!filterGroup.isEnabled()) + continue; var result = filterGroup.check(stack); if (result.isFiltered()) { @@ -205,7 +207,8 @@ abstract class Filter { final protected ByteArrayFilterGroupList protobufBufferFilterGroups = new ByteArrayFilterGroupList(); /** - * Check if the given path, identifier or protobuf buffer is filtered by any {@link FilterGroup}. + * Check if the given path, identifier or protobuf buffer is filtered by any + * {@link FilterGroup}. * * @return True if filtered, false otherwise. */ @@ -232,34 +235,36 @@ abstract class Filter { @RequiresApi(api = Build.VERSION_CODES.N) @SuppressWarnings("unused") public final class LithoFilterPatch { - private static final Filter[] filters = new Filter[]{ - new DummyFilter() // Replaced by patch. + private static final Filter[] filters = new Filter[] { + new DummyFilter() // Replaced by patch. }; @SuppressWarnings("unused") - public static boolean filter(final StringBuilder pathBuilder, final String identifier, final ByteBuffer protobufBuffer) { - // TODO: Maybe this can be moved to the Filter class, to prevent unnecessary string creation - // because some filters might not need the path. + public static boolean filter(final StringBuilder pathBuilder, final String identifier, + final ByteBuffer protobufBuffer) { + // TODO: Maybe this can be moved to the Filter class, to prevent unnecessary + // string creation + // because some filters might not need the path. var path = pathBuilder.toString(); // It is assumed that protobufBuffer is empty as well in this case. - if (path.isEmpty()) return false; + if (path.isEmpty()) + return false; LogHelper.printDebug(() -> String.format( "Searching (ID: %s, Buffer-size: %s): %s", - identifier, protobufBuffer.remaining(), path - )); + identifier, protobufBuffer.remaining(), path)); var protobufBufferArray = protobufBuffer.array(); for (var filter : filters) { var filtered = filter.isFiltered(path, identifier, protobufBufferArray); - LogHelper.printDebug(() -> - String.format("%s (ID: %s): %s", filtered ? "Filtered" : "Unfiltered", identifier, path) - ); + LogHelper.printDebug( + () -> String.format("%s (ID: %s): %s", filtered ? "Filtered" : "Unfiltered", identifier, path)); - if (filtered) return true; + if (filtered) + return true; } return false; diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 9dc49b4b..471a70a6 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -110,7 +110,7 @@ public enum SettingsEnum { HIDE_EMAIL_ADDRESS("revanced_hide_email_address", BOOLEAN, FALSE), HIDE_ENDSCREEN_CARDS("revanced_hide_endscreen_cards", BOOLEAN, TRUE), HIDE_FLOATING_MICROPHONE_BUTTON("revanced_hide_floating_microphone_button", BOOLEAN, TRUE, true), - HIDE_FULLSCREEN_PANELS("revanced_hide_fullscreen_panels", BOOLEAN, TRUE), + HIDE_FULLSCREEN_PANELS("revanced_hide_fullscreen_panels", BOOLEAN, TRUE, true), HIDE_GET_PREMIUM("revanced_hide_get_premium", BOOLEAN, TRUE), HIDE_INFO_CARDS("revanced_hide_info_cards", BOOLEAN, TRUE), HIDE_LOAD_MORE_BUTTON("revanced_hide_load_more_button", BOOLEAN, TRUE, true), diff --git a/gradle.properties b/gradle.properties index 8e72cfe1..5a68b9ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.jvmargs = -Xmx2048m android.useAndroidX = true -version = 0.111.0 +version = 0.111.1-dev.3