diff --git a/CHANGELOG.md b/CHANGELOG.md index 73686be7..8ef79f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +# [0.113.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.4...v0.113.0-dev.5) (2023-07-19) + + +### Bug Fixes + +* **YouTube - Spoof client:** show video time and chapters while using seekbar ([#435](https://github.com/ReVanced/revanced-integrations/issues/435)) ([a0f831a](https://github.com/ReVanced/revanced-integrations/commit/a0f831ac3f3773a0b47a0fb532d0bf58f6aa96d7)) + +# [0.113.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.3...v0.113.0-dev.4) (2023-07-19) + + +### Bug Fixes + +* **Tiktok - Settings:** bump compatibility ([#440](https://github.com/ReVanced/revanced-integrations/issues/440)) ([821a32e](https://github.com/ReVanced/revanced-integrations/commit/821a32ee40d7795cabedc40f24356c1c1069ddec)) + +# [0.113.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.2...v0.113.0-dev.3) (2023-07-16) + + +### Bug Fixes + +* **youtube/return-youtube-dislike:** fix dislikes not showing in some situations ([#439](https://github.com/ReVanced/revanced-integrations/issues/439)) ([7a28c2f](https://github.com/ReVanced/revanced-integrations/commit/7a28c2fa13438947931b8c41ef73b128a32530eb)) + +# [0.113.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.1...v0.113.0-dev.2) (2023-07-16) + + +### Features + +* **YouTube - Hide ads:** hide new type of buttoned ad ([9f21c72](https://github.com/ReVanced/revanced-integrations/commit/9f21c7268e5a08f542f5b090316486aadf4a5acd)) + +# [0.113.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.112.1-dev.2...v0.113.0-dev.1) (2023-07-15) + + +### Features + +* **youtube:** rename `video-speed` to `playback-speed` ([#438](https://github.com/revanced/revanced-integrations/issues/438)) ([630776f](https://github.com/revanced/revanced-integrations/commit/630776fd3514435dd83ef1c765a4f5b007e8e2f2)) + +## [0.112.1-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.112.1-dev.1...v0.112.1-dev.2) (2023-07-15) + + +### Bug Fixes + +* **YouTube - Hide Shorts Components:** hide sound button ([a2b1630](https://github.com/revanced/revanced-integrations/commit/a2b1630df8d330f3c0cbf77e9ea46b9d1c51adde)) + +## [0.112.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.112.0...v0.112.1-dev.1) (2023-07-14) + + +### Bug Fixes + +* **youtube/sponsorblock:** fix some segments skipping slightly too late ([#436](https://github.com/revanced/revanced-integrations/issues/436)) ([f694928](https://github.com/revanced/revanced-integrations/commit/f69492819e52e0fd99c4e10390fd39f26c3a9c48)) + # [0.112.0](https://github.com/revanced/revanced-integrations/compare/v0.111.2...v0.112.0) (2023-07-08) diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 21014e7f..a3d2fc33 100644 --- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -202,7 +202,13 @@ public class ReturnYouTubeDislikePatch { */ public static boolean setShortsDislikes(@NonNull View likeDislikeView) { try { - if (!SettingsEnum.RYD_ENABLED.getBoolean() || !SettingsEnum.RYD_SHORTS.getBoolean()) { + if (!SettingsEnum.RYD_ENABLED.getBoolean()) { + return false; + } + if (!SettingsEnum.RYD_SHORTS.getBoolean()) { + // Must clear the data here, in case a new video was loaded while PlayerType + // suggested the video was not a short (can happen when spoofing to an old app version). + ReturnYouTubeDislike.setCurrentVideoId(null); return false; } LogHelper.printDebug(() -> "setShortsDislikes"); @@ -302,7 +308,7 @@ public class ReturnYouTubeDislikePatch { if (!videoId.equals(currentVideoId)) { currentVideoId = videoId; - final boolean noneHiddenOrMinimized = PlayerType.getCurrent().isNoneHiddenOrMinimized(); + final boolean noneHiddenOrMinimized = PlayerType.getCurrent().isNoneOrHidden(); if (noneHiddenOrMinimized && !SettingsEnum.RYD_SHORTS.getBoolean()) { ReturnYouTubeDislike.setCurrentVideoId(null); return; 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 899d7b6d..37c7a51d 100644 --- a/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java @@ -2,6 +2,10 @@ package app.revanced.integrations.patches; import static app.revanced.integrations.utils.ReVancedUtils.containsAny; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.shared.PlayerType; import app.revanced.integrations.utils.LogHelper; @@ -67,4 +71,25 @@ public class SpoofSignatureVerificationPatch { return originalValue; } + /** + * Injection point. + */ + public static boolean getSeekbarThumbnailOverrideValue() { + return SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean(); + } + + /** + * Injection point. + * + * @param view seekbar thumbnail view. Includes both shorts and regular videos. + */ + public static void seekbarImageViewCreated(ImageView view) { + if (SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean()) { + view.setVisibility(View.GONE); + // Also hide the border around the thumbnail (otherwise a 1 pixel wide bordered frame is visible). + ViewGroup parentLayout = (ViewGroup) view.getParent(); + parentLayout.setPadding(0, 0, 0, 0); + } + } + } diff --git a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java index 2a321953..ad5bcd16 100644 --- a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java +++ b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java @@ -24,7 +24,7 @@ public final class VideoInformation { @NonNull private static String videoId = ""; private static long videoLength = 0; - private static volatile long videoTime = -1; // must be volatile. Value is set off main thread from high precision patch hook + private static long videoTime = -1; /** * The current playback speed */ @@ -98,17 +98,17 @@ public final class VideoInformation { /** * Injection point. - * Called off the main thread approximately every 50ms to 100ms + * Called on the main thread every 1000ms. * * @param currentPlaybackTime The current playback time of the video in milliseconds. */ - public static void setVideoTimeHighPrecision(final long currentPlaybackTime) { + public static void setVideoTime(final long currentPlaybackTime) { videoTime = currentPlaybackTime; } /** * Seek on the current video. - * Does not function for playback of Shorts or Stories. + * Does not function for playback of Shorts. * * Caution: If called from a videoTimeHook() callback, * this will cause a recursive call into the same videoTimeHook() callback. @@ -118,11 +118,6 @@ public final class VideoInformation { */ public static boolean seekTo(final long millisecond) { ReVancedUtils.verifyOnMainThread(); - if (seekMethod == null) { - LogHelper.printException(() -> "seekMethod was null"); - return false; - } - try { LogHelper.printDebug(() -> "Seeking to " + millisecond); return (Boolean) seekMethod.invoke(playerControllerRef.get(), millisecond); @@ -137,7 +132,7 @@ public final class VideoInformation { } /** - * Id of the current video playing. Includes Shorts and YouTube Stories. + * Id of the current video playing. Includes Shorts. * * @return The id of the video. Empty string if not set yet. */ @@ -154,7 +149,7 @@ public final class VideoInformation { } /** - * Length of the current video playing. Includes Shorts and YouTube Stories. + * Length of the current video playing. Includes Shorts. * * @return The length of the video in milliseconds. * If the video is not yet loaded, or if the video is playing in the background with no video visible, @@ -165,14 +160,14 @@ public final class VideoInformation { } /** - * Playback time of the current video playing. - * Value can lag up to approximately 100ms behind the actual current video playback time. + * Playback time of the current video playing. Includes Shorts. * - * Note: Code inside a videoTimeHook patch callback - * should use the callback video time and avoid using this method - * (in situations of recursive hook callbacks, the value returned here may be outdated). + * Value will lag behind the actual playback time by a variable amount based on the playback speed. * - * Includes Shorts and YouTube Stories. + * If playback speed is 2.0x, this value may be up to 2000ms behind the actual playback time. + * If playback speed is 1.0x, this value may be up to 1000ms behind the actual playback time. + * If playback speed is 0.5x, this value may be up to 500ms behind the actual playback time. + * Etc. * * @return The time of the video in milliseconds. -1 if not set yet. */ @@ -192,7 +187,7 @@ public final class VideoInformation { * @see VideoState */ public static boolean isAtEndOfVideo() { - return videoTime > 0 && videoLength > 0 && videoTime >= videoLength; + return videoTime >= videoLength && videoLength > 0; } } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java index a16ea57f..4e1bdfd8 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java @@ -23,6 +23,7 @@ public final class AdsFilter extends Filter { "_buttoned_layout", "full_width_square_image_layout", "_ad_with", + "text_image_button_group_layout", "video_display_button_group_layout", "landscape_image_wide_button_layout" ); diff --git a/app/src/main/java/app/revanced/integrations/patches/components/VideoSpeedMenuFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java similarity index 60% rename from app/src/main/java/app/revanced/integrations/patches/components/VideoSpeedMenuFilterPatch.java rename to app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java index f01d30d1..66b229f4 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/VideoSpeedMenuFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java @@ -1,11 +1,11 @@ package app.revanced.integrations.patches.components; -// Abuse LithoFilter for CustomVideoSpeedPatch. -public final class VideoSpeedMenuFilterPatch extends Filter { +// Abuse LithoFilter for CustomPlaybackSpeedPatch. +public final class PlaybackSpeedMenuFilterPatch extends Filter { // Must be volatile or synchronized, as litho filtering runs off main thread and this field is then access from the main thread. - public static volatile boolean isVideoSpeedMenuVisible; + public static volatile boolean isPlaybackSpeedMenuVisible; - public VideoSpeedMenuFilterPatch() { + public PlaybackSpeedMenuFilterPatch() { pathFilterGroups.addAll(new StringFilterGroup( null, "playback_speed_sheet_content.eml-js" @@ -14,7 +14,7 @@ public final class VideoSpeedMenuFilterPatch extends Filter { @Override boolean isFiltered(final String path, final String identifier, final byte[] protobufBufferArray) { - isVideoSpeedMenuVisible = super.isFiltered(path, identifier, protobufBufferArray); + isPlaybackSpeedMenuVisible = super.isFiltered(path, identifier, protobufBufferArray); return false; } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index 18fc6f36..ec1ffe46 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -1,33 +1,22 @@ package app.revanced.integrations.patches.components; +import android.view.View; +import app.revanced.integrations.settings.SettingsEnum; +import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar; + import static app.revanced.integrations.utils.ReVancedUtils.hideViewBy1dpUnderCondition; import static app.revanced.integrations.utils.ReVancedUtils.hideViewUnderCondition; -import android.annotation.SuppressLint; -import android.os.Build; -import android.view.View; - -import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar; - -import app.revanced.integrations.settings.SettingsEnum; - public final class ShortsFilter extends Filter { + // Set by patch. public static PivotBar pivotBar; - @SuppressLint("StaticFieldLeak") - + final StringFilterGroupList shortsFilterGroup = new StringFilterGroupList(); private final StringFilterGroup reelChannelBar = new StringFilterGroup( null, "reel_channel_bar" ); - private final StringFilterGroup infoPanel = new StringFilterGroup( - SettingsEnum.HIDE_SHORTS_INFO_PANEL, - "shorts_info_panel_overview" - ); - public ShortsFilter() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return; - final var thanksButton = new StringFilterGroup( SettingsEnum.HIDE_SHORTS_THANKS_BUTTON, "suggested_action" @@ -48,6 +37,11 @@ public final class ShortsFilter extends Filter { "reel_pivot_button" ); + final var infoPanel = new StringFilterGroup( + SettingsEnum.HIDE_SHORTS_INFO_PANEL, + "shorts_info_panel_overview" + ); + final var channelBar = new StringFilterGroup( SettingsEnum.HIDE_SHORTS_CHANNEL_BAR, "reel_channel_bar" @@ -61,19 +55,20 @@ public final class ShortsFilter extends Filter { "shorts_video_cell" ); - this.pathFilterGroups.addAll(joinButton, subscribeButton, soundButton, channelBar); - this.identifierFilterGroups.addAll(shorts, thanksButton); + shortsFilterGroup.addAll(soundButton, infoPanel); + pathFilterGroups.addAll(joinButton, subscribeButton, channelBar); + identifierFilterGroups.addAll(shorts, thanksButton); } @Override boolean isFiltered(final String path, final String identifier, final byte[] protobufBufferArray) { + // Filter the path only when reelChannelBar is visible. if (reelChannelBar.check(path).isFiltered()) if (this.pathFilterGroups.contains(path)) return true; - // Shorts info panel path appears outside of reelChannelBar path. - if (infoPanel.isEnabled() && infoPanel.check(path).isFiltered()) return true; + if (shortsFilterGroup.contains(path)) return true; return this.identifierFilterGroups.contains(identifier); } diff --git a/app/src/main/java/app/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch.java b/app/src/main/java/app/revanced/integrations/patches/playback/speed/CustomPlaybackSpeedPatch.java similarity index 76% rename from app/src/main/java/app/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch.java rename to app/src/main/java/app/revanced/integrations/patches/playback/speed/CustomPlaybackSpeedPatch.java index a8e2e603..631ad943 100644 --- a/app/src/main/java/app/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/playback/speed/CustomPlaybackSpeedPatch.java @@ -13,12 +13,12 @@ import com.facebook.litho.ComponentHost; import java.util.Arrays; -import app.revanced.integrations.patches.components.VideoSpeedMenuFilterPatch; +import app.revanced.integrations.patches.components.PlaybackSpeedMenuFilterPatch; import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; -public class CustomVideoSpeedPatch { +public class CustomPlaybackSpeedPatch { /** * Maximum playback speed, exclusive value. Custom speeds must be less than this value. */ @@ -27,17 +27,17 @@ public class CustomVideoSpeedPatch { /** * Custom playback speeds. */ - public static float[] customVideoSpeeds; + public static float[] customPlaybackSpeeds; /** - * Minimum value of {@link #customVideoSpeeds} + * Minimum value of {@link #customPlaybackSpeeds} */ - public static float minVideoSpeed; + public static float minPlaybackSpeed; /** - * Maxium value of {@link #customVideoSpeeds} + * Maxium value of {@link #customPlaybackSpeeds} */ - public static float maxVideoSpeed; + public static float maxPlaybackSpeed; /** * PreferenceList entries and values, of all available playback speeds. @@ -60,10 +60,10 @@ public class CustomVideoSpeedPatch { if (speedStrings.length == 0) { throw new IllegalArgumentException(); } - customVideoSpeeds = new float[speedStrings.length]; + customPlaybackSpeeds = new float[speedStrings.length]; for (int i = 0, length = speedStrings.length; i < length; i++) { final float speed = Float.parseFloat(speedStrings[i]); - if (speed <= 0 || arrayContains(customVideoSpeeds, speed)) { + if (speed <= 0 || arrayContains(customPlaybackSpeeds, speed)) { throw new IllegalArgumentException(); } if (speed >= MAXIMUM_PLAYBACK_SPEED) { @@ -72,13 +72,13 @@ public class CustomVideoSpeedPatch { loadCustomSpeeds(); return; } - minVideoSpeed = Math.min(minVideoSpeed, speed); - maxVideoSpeed = Math.max(maxVideoSpeed, speed); - customVideoSpeeds[i] = speed; + minPlaybackSpeed = Math.min(minPlaybackSpeed, speed); + maxPlaybackSpeed = Math.max(maxPlaybackSpeed, speed); + customPlaybackSpeeds[i] = speed; } } catch (Exception ex) { LogHelper.printInfo(() -> "parse error", ex); - resetCustomSpeeds("Invalid custom video speeds. Using default values."); + resetCustomSpeeds("Invalid custom playback speeds. Using default values."); loadCustomSpeeds(); } } @@ -95,10 +95,10 @@ public class CustomVideoSpeedPatch { */ public static void initializeListPreference(ListPreference preference) { if (preferenceListEntries == null) { - preferenceListEntries = new String[customVideoSpeeds.length]; - preferenceListEntryValues = new String[customVideoSpeeds.length]; + preferenceListEntries = new String[customPlaybackSpeeds.length]; + preferenceListEntryValues = new String[customPlaybackSpeeds.length]; int i = 0; - for (float speed : customVideoSpeeds) { + for (float speed : customPlaybackSpeeds) { String speedString = String.valueOf(speed); preferenceListEntries[i] = speedString + "x"; preferenceListEntryValues[i] = speedString; @@ -115,14 +115,14 @@ public class CustomVideoSpeedPatch { public static void onFlyoutMenuCreate(final LinearLayout linearLayout) { // The playback rate menu is a RecyclerView with 2 children. The third child is the "Advanced" quality menu. addRecyclerListener(linearLayout, 2, 1, recyclerView -> { - if (VideoSpeedMenuFilterPatch.isVideoSpeedMenuVisible && + if (PlaybackSpeedMenuFilterPatch.isPlaybackSpeedMenuVisible && recyclerView.getChildCount() == 1 && recyclerView.getChildAt(0) instanceof ComponentHost ) { linearLayout.setVisibility(View.GONE); - // Close the new video speed menu and instead show the old one. - showOldVideoSpeedMenu(); + // Close the new Playback speed menu and instead show the old one. + showOldPlaybackSpeedMenu(); // DismissView [R.id.touch_outside] is the 1st ChildView of the 3rd ParentView. ((ViewGroup) linearLayout.getParent().getParent().getParent()) @@ -131,7 +131,7 @@ public class CustomVideoSpeedPatch { }); } - public static void showOldVideoSpeedMenu() { + public static void showOldPlaybackSpeedMenu() { LogHelper.printDebug(() -> "Old video quality menu shown"); // Rest of the implementation added by patch. diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java index fc577f53..7fcd9d0f 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java @@ -255,7 +255,7 @@ public class ReturnYouTubeDislike { // If a Short is opened while a regular video is on screen, this will incorrectly set this as false. // But this check is needed to fix unusual situations of opening/closing the app // while both a regular video and a short are on screen. - dislikeDataIsShort = currentPlayerType.isNoneHiddenOrMinimized(); + dislikeDataIsShort = currentPlayerType.isNoneOrHidden(); RYDCachedFetch entry = futureCache.get(videoId); if (entry != null && entry.futureInProgressOrFinishedSuccessfully()) { @@ -371,7 +371,7 @@ public class ReturnYouTubeDislike { // Must make a local copy of videoId, since it may change between now and when the vote thread runs. String videoIdToVoteFor = getCurrentVideoId(); if (videoIdToVoteFor == null || - (SettingsEnum.RYD_SHORTS.getBoolean() && dislikeDataIsShort != PlayerType.getCurrent().isNoneHiddenOrMinimized())) { + (SettingsEnum.RYD_SHORTS.getBoolean() && dislikeDataIsShort != PlayerType.getCurrent().isNoneOrHidden())) { // User enabled RYD after starting playback of a video. // Or shorts was loaded with regular video present, then shorts was closed, // and then user voted on the now visible original video. 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 10fb1ea5..3e7097d9 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -152,7 +152,8 @@ 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), - SPOOF_SIGNATURE_VERIFICATION("revanced_spoof_signature_verification", BOOLEAN, TRUE, "revanced_spoof_signature_verification_user_dialog_message"), + SPOOF_SIGNATURE_VERIFICATION("revanced_spoof_signature_verification", BOOLEAN, TRUE, true, + "revanced_spoof_signature_verification_user_dialog_message"), // Swipe controls SWIPE_BRIGHTNESS("revanced_swipe_brightness", BOOLEAN, TRUE), diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java b/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java index 50d4a725..f90f98da 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java @@ -24,7 +24,7 @@ import androidx.annotation.Nullable; import com.google.android.apps.youtube.app.application.Shell_HomeActivity; -import app.revanced.integrations.patches.playback.speed.CustomVideoSpeedPatch; +import app.revanced.integrations.patches.playback.speed.CustomPlaybackSpeedPatch; import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.settings.SharedPrefCategory; import app.revanced.integrations.utils.LogHelper; @@ -135,7 +135,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment { // if the preference was included, then initialize it based on the available playback speed Preference defaultSpeedPreference = findPreference(SettingsEnum.PLAYBACK_SPEED_DEFAULT.path); if (defaultSpeedPreference instanceof ListPreference) { - CustomVideoSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference); + CustomPlaybackSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference); } // Set current value from SettingsEnum diff --git a/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt b/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt index 0fd89bfc..a8dec9cc 100644 --- a/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt +++ b/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt @@ -18,7 +18,7 @@ enum class PlayerType { HIDDEN, /** * When spoofing to 16.x YouTube and watching a short with a regular video in the background, - * the type will be this (and not [HIDDEN]). + * the type can be this (and not [HIDDEN]). */ WATCH_WHILE_MINIMIZED, WATCH_WHILE_MAXIMIZED, diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java b/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java index e6bb328d..be42a498 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java @@ -58,6 +58,7 @@ public class SegmentPlaybackController { /** * Because loading can take time, show the skip to highlight for a few seconds after the segments load. * This is the system time (in milliseconds) to no longer show the initial display skip to highlight. + * Value will be zero if no highlight segment exists, or if the system time to show the highlight has passed. */ private static long highlightSegmentInitialShowEndTime; @@ -198,7 +199,7 @@ public class SegmentPlaybackController { return; } if (PlayerType.getCurrent().isNoneOrHidden()) { - LogHelper.printDebug(() -> "ignoring short or story"); + LogHelper.printDebug(() -> "ignoring Short"); return; } if (!ReVancedUtils.isNetworkConnected()) { @@ -238,14 +239,20 @@ public class SegmentPlaybackController { setSegments(segments); final long videoTime = VideoInformation.getVideoTime(); - // if the current video time is before the highlight - if (highlightSegment != null && videoTime < highlightSegment.end) { - if (highlightSegment.shouldAutoSkip()) { - skipSegment(highlightSegment, false); - return; + if (highlightSegment != null) { + // If the current video time is before the highlight. + final long timeUntilHighlight = highlightSegment.start - videoTime; + if (timeUntilHighlight > 0) { + if (highlightSegment.shouldAutoSkip()) { + skipSegment(highlightSegment, false); + return; + } + highlightSegmentInitialShowEndTime = System.currentTimeMillis() + Math.min( + (long) (timeUntilHighlight / VideoInformation.getPlaybackSpeed()), + DURATION_TO_SHOW_SKIP_BUTTON); } - highlightSegmentInitialShowEndTime = System.currentTimeMillis() + DURATION_TO_SHOW_SKIP_BUTTON; } + // check for any skips now, instead of waiting for the next update to setVideoTime() setVideoTime(videoTime); }); @@ -262,7 +269,7 @@ public class SegmentPlaybackController { public static void setVideoTime(long millis) { try { if (!SettingsEnum.SB_ENABLED.getBoolean() - || PlayerType.getCurrent().isNoneOrHidden() // shorts playback + || PlayerType.getCurrent().isNoneOrHidden() // Shorts playback. || segments == null || segments.length == 0) { return; } @@ -270,11 +277,17 @@ public class SegmentPlaybackController { updateHiddenSegments(millis); - // to debug the timing logic, set this to a very large value (5000 or more) - // then try manually seeking just playback reaches a skip/hide of different segments - final long lookAheadMilliseconds = 1500; // must be larger than the average time between calls to this method final float playbackSpeed = VideoInformation.getPlaybackSpeed(); - final long startTimerLookAheadThreshold = millis + (long)(playbackSpeed * lookAheadMilliseconds); + // Amount of time to look ahead for the next segment, + // and the threshold to determine if a scheduled show/hide is at the correct video time when it's run. + // + // This value must be greater than largest time between calls to this method (1000ms), + // and must be adjusted for the video speed. + // + // To debug the stale skip logic, set this to a very large value (5000 or more) + // then try manually seeking just before playback reaches a segment skip. + final long speedAdjustedTimeThreshold = (long)(playbackSpeed * 1200); + final long startTimerLookAheadThreshold = millis + speedAdjustedTimeThreshold; SponsorSegment foundSegmentCurrentlyPlaying = null; SponsorSegment foundUpcomingSegment = null; @@ -344,9 +357,11 @@ public class SegmentPlaybackController { } if (highlightSegment != null) { - if (millis < DURATION_TO_SHOW_SKIP_BUTTON || System.currentTimeMillis() < highlightSegmentInitialShowEndTime) { + if (millis < DURATION_TO_SHOW_SKIP_BUTTON || (highlightSegmentInitialShowEndTime != 0 + && System.currentTimeMillis() < highlightSegmentInitialShowEndTime)) { SponsorBlockViewController.showSkipHighlightButton(highlightSegment); } else { + highlightSegmentInitialShowEndTime = 0; SponsorBlockViewController.hideSkipHighlightButton(); } } @@ -361,12 +376,9 @@ public class SegmentPlaybackController { SponsorBlockViewController.hideSkipSegmentButton(); } - // must be greater than the average time between updates to VideoInformation time - final long videoInformationTimeUpdateThresholdMilliseconds = 250; - // schedule a hide, only if the segment end is near final SponsorSegment segmentToHide = - (foundSegmentCurrentlyPlaying != null && foundSegmentCurrentlyPlaying.endIsNear(millis, lookAheadMilliseconds)) + (foundSegmentCurrentlyPlaying != null && foundSegmentCurrentlyPlaying.endIsNear(millis, speedAdjustedTimeThreshold)) ? foundSegmentCurrentlyPlaying : null; @@ -384,9 +396,13 @@ public class SegmentPlaybackController { return; } scheduledHideSegment = null; + if (VideoState.getCurrent() != VideoState.PLAYING) { + LogHelper.printDebug(() -> "Ignoring scheduled hide segment as video is paused: " + segmentToHide); + return; + } final long videoTime = VideoInformation.getVideoTime(); - if (!segmentToHide.endIsNear(videoTime, videoInformationTimeUpdateThresholdMilliseconds)) { + if (!segmentToHide.endIsNear(videoTime, speedAdjustedTimeThreshold)) { // current video time is not what's expected. User paused playback LogHelper.printDebug(() -> "Ignoring outdated scheduled hide: " + segmentToHide + " videoInformation time: " + videoTime); @@ -419,10 +435,13 @@ public class SegmentPlaybackController { return; } scheduledUpcomingSegment = null; + if (VideoState.getCurrent() != VideoState.PLAYING) { + LogHelper.printDebug(() -> "Ignoring scheduled hide segment as video is paused: " + segmentToSkip); + return; + } final long videoTime = VideoInformation.getVideoTime(); - if (!segmentToSkip.startIsNear(videoTime, - videoInformationTimeUpdateThresholdMilliseconds)) { + if (!segmentToSkip.startIsNear(videoTime, speedAdjustedTimeThreshold)) { // current video time is not what's expected. User paused playback LogHelper.printDebug(() -> "Ignoring outdated scheduled segment: " + segmentToSkip + " videoInformation time: " + videoTime); @@ -488,10 +507,10 @@ public class SegmentPlaybackController { SponsorBlockViewController.hideSkipHighlightButton(); SponsorBlockViewController.hideSkipSegmentButton(); - // If trying to seek to end of the video, YouTube can seek just short of the actual end. + // If trying to seek to end of the video, YouTube can seek just before of the actual end. // (especially if the video does not end on a whole second boundary). // This causes additional segment skip attempts, even though it cannot seek any closer to the desired time. - // Check for and ignore repeated skip attempts of the same segment over a short time period. + // Check for and ignore repeated skip attempts of the same segment over a small time period. final long now = System.currentTimeMillis(); final long minimumMillisecondsBetweenSkippingSameSegment = 500; if ((lastSegmentSkipped == segmentToSkip) && (now - lastSegmentSkippedTime < minimumMillisecondsBetweenSkippingSameSegment)) { diff --git a/app/src/main/java/app/revanced/tiktok/settingsmenu/SettingsMenu.java b/app/src/main/java/app/revanced/tiktok/settingsmenu/SettingsMenu.java index 7449ed8a..f79d16b7 100644 --- a/app/src/main/java/app/revanced/tiktok/settingsmenu/SettingsMenu.java +++ b/app/src/main/java/app/revanced/tiktok/settingsmenu/SettingsMenu.java @@ -6,36 +6,65 @@ import android.preference.PreferenceFragment; import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; - -import com.bytedance.ies.ugc.aweme.commercialize.compliance.personalization.AdPersonalizationActivity; - import app.revanced.tiktok.utils.LogHelper; import app.revanced.tiktok.utils.ReVancedUtils; +import com.bytedance.ies.ugc.aweme.commercialize.compliance.personalization.AdPersonalizationActivity; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; public class SettingsMenu { - public static void initializeSettings(AdPersonalizationActivity base) { + public static Object createSettingsEntry(String entryClazzName, String entryInfoClazzName) { + try { + Class entryClazz = Class.forName(entryClazzName); + Class entryInfoClazz = Class.forName(entryInfoClazzName); + Constructor entryConstructor = entryClazz.getConstructor(entryInfoClazz); + Constructor entryInfoConstructor = entryInfoClazz.getDeclaredConstructors()[0]; + Object buttonInfo = entryInfoConstructor.newInstance("Revanced settings", null, (View.OnClickListener) view -> startSettingsActivity()); + return entryConstructor.newInstance(buttonInfo); + } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | + InstantiationException e) { + throw new RuntimeException(e); + } + } + + /*** + * Initialize the settings menu. + * @param base The activity to initialize the settings menu on. + * @return Whether the settings menu should be initialized. + */ + public static boolean initializeSettings(AdPersonalizationActivity base) { + if (!base.getIntent().getExtras().getBoolean("revanced", false)) return false; + SettingsStatus.load(); + LinearLayout linearLayout = new LinearLayout(base); linearLayout.setLayoutParams(new LinearLayout.LayoutParams(-1, -1)); linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.setFitsSystemWindows(true); linearLayout.setTransitionGroup(true); + FrameLayout fragment = new FrameLayout(base); fragment.setLayoutParams(new FrameLayout.LayoutParams(-1, -1)); int fragmentId = View.generateViewId(); fragment.setId(fragmentId); + linearLayout.addView(fragment); base.setContentView(linearLayout); + PreferenceFragment preferenceFragment = new ReVancedSettingsFragment(); base.getFragmentManager().beginTransaction().replace(fragmentId, preferenceFragment).commit(); + + return true; } - public static void startSettingsActivity() { + private static void startSettingsActivity() { Context appContext = ReVancedUtils.getAppContext(); if (appContext != null) { Intent intent = new Intent(appContext, AdPersonalizationActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra("revanced", true); appContext.startActivity(intent); } else { LogHelper.debug(SettingsMenu.class, "ReVancedUtils.getAppContext() return null"); diff --git a/gradle.properties b/gradle.properties index 0beafaec..1de8668a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true android.useAndroidX = true -version = 0.112.0 +version = 0.113.0-dev.5