mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-04-29 22:24:31 +02:00
feat(YouTube - SponsorBlock): After the skip button is automatically hidden, makes the visibility of the skip button match the player control's (#142)
* ci: workflow to ping Discord users when patches are released (#72) * init: Workflow to notify discord users of releases * Rename workflow * chore (Background playback): Shorten description * Revert "chore (Background playback): Shorten description" This reverts commit 10661b870f0c9c670c5d522f9b2ca7cc82d32772. * Change message contents * feat(YouTube - SponsorBlock): Display skip segment button when player controls are shown Closes https://github.com/anddea/revanced-patches/issues/962 * feat: Apply code review suggestions --------- Co-authored-by: KobeW50 <84587632+KobeW50@users.noreply.github.com> Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com> Co-authored-by: Aaron Veil <70171475+anddea@users.noreply.github.com>
This commit is contained in:
parent
6ee7649581
commit
8659c489a0
@ -68,6 +68,7 @@ public class PlayerControlsPatch {
|
|||||||
|
|
||||||
// CreateSegmentButtonController.changeVisibility(showing, animation);
|
// CreateSegmentButtonController.changeVisibility(showing, animation);
|
||||||
// VotingButtonController.changeVisibility(showing, animation);
|
// VotingButtonController.changeVisibility(showing, animation);
|
||||||
|
// SegmentPlaybackController.changeVisibility(showing, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,6 +119,7 @@ public class PlayerControlsPatch {
|
|||||||
|
|
||||||
// CreateSegmentButtonController.changeVisibilityNegatedImmediate();
|
// CreateSegmentButtonController.changeVisibilityNegatedImmediate();
|
||||||
// VotingButtonController.changeVisibilityNegatedImmediate();
|
// VotingButtonController.changeVisibilityNegatedImmediate();
|
||||||
|
// SegmentPlaybackController.changeVisibilityNegatedImmediate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,6 @@ import androidx.annotation.Nullable;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -48,7 +47,7 @@ public class SegmentPlaybackController {
|
|||||||
*/
|
*/
|
||||||
private static final long DURATION_TO_SHOW_SKIP_BUTTON = 3800;
|
private static final long DURATION_TO_SHOW_SKIP_BUTTON = 3800;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Highlight segments have zero length as they are a point in time.
|
* Highlight segments have zero length as they are a point in time.
|
||||||
* Draw them on screen using a fixed width bar.
|
* Draw them on screen using a fixed width bar.
|
||||||
* Value is independent of device dpi.
|
* Value is independent of device dpi.
|
||||||
@ -511,14 +510,14 @@ public class SegmentPlaybackController {
|
|||||||
* Removes all previously hidden segments that are not longer contained in the given video time.
|
* Removes all previously hidden segments that are not longer contained in the given video time.
|
||||||
*/
|
*/
|
||||||
private static void updateHiddenSegments(long currentVideoTime) {
|
private static void updateHiddenSegments(long currentVideoTime) {
|
||||||
Iterator<SponsorSegment> i = hiddenSkipSegmentsForCurrentVideoTime.iterator();
|
// If you want to maintain compatibility with RVX Android 6, use Iterator.
|
||||||
while (i.hasNext()) {
|
hiddenSkipSegmentsForCurrentVideoTime.removeIf(segment -> {
|
||||||
SponsorSegment hiddenSegment = i.next();
|
if (!segment.containsTime(currentVideoTime)) {
|
||||||
if (!hiddenSegment.containsTime(currentVideoTime)) {
|
Logger.printDebug(() -> "Resetting hide skip button: " + segment);
|
||||||
Logger.printDebug(() -> "Resetting hide skip button: " + hiddenSegment);
|
return true;
|
||||||
i.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setSegmentCurrentlyPlaying(@Nullable SponsorSegment segment) {
|
private static void setSegmentCurrentlyPlaying(@Nullable SponsorSegment segment) {
|
||||||
@ -545,6 +544,72 @@ public class SegmentPlaybackController {
|
|||||||
SponsorBlockViewController.showSkipSegmentButton(segment);
|
SponsorBlockViewController.showSkipSegmentButton(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void changeVisibility(boolean showing, boolean animation) {
|
||||||
|
onPlayerControlsVisibilityChanged(showing, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void changeVisibilityNegatedImmediate() {
|
||||||
|
onPlayerControlsVisibilityChanged(false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles changes in player control visibility and manages the skip segment button accordingly.
|
||||||
|
*
|
||||||
|
* <p>This method is called whenever the visibility state of the player controls changes.
|
||||||
|
* If auto-hide is enabled and there is a currently playing sponsor segment, it will show
|
||||||
|
* the skip segment button when the controls are visible and schedule recursive checks
|
||||||
|
* to hide the button after a defined duration.</p>
|
||||||
|
*
|
||||||
|
* @param visible if true, player controls are visible (The user touched the player when the player controls were invisible)
|
||||||
|
* @param immediate if true, player controls are invisible (The user touched the player when the player controls were visible)
|
||||||
|
*/
|
||||||
|
private static void onPlayerControlsVisibilityChanged(boolean visible, boolean immediate) {
|
||||||
|
if (!Settings.SB_ENABLED.get()
|
||||||
|
|| !Settings.SB_AUTO_HIDE_SKIP_BUTTON.get()
|
||||||
|
|| segmentCurrentlyPlaying == null
|
||||||
|
|| !hiddenSkipSegmentsForCurrentVideoTime.contains(segmentCurrentlyPlaying)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the player button appears after the skip button is hidden
|
||||||
|
if (visible) {
|
||||||
|
SponsorBlockViewController.showSkipSegmentButton(segmentCurrentlyPlaying);
|
||||||
|
skipSegmentButtonEndTime = System.currentTimeMillis() + 2000; // Player buttons are hidden after 2000ms
|
||||||
|
checkPlayerControlsVisibilityRecursive(segmentCurrentlyPlaying);
|
||||||
|
} else if (immediate) {
|
||||||
|
// Hide the skip segment button and reset the end time
|
||||||
|
skipSegmentButtonEndTime = 0;
|
||||||
|
SponsorBlockViewController.hideSkipSegmentButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively checks whether the skip segment button should remain visible or be hidden.
|
||||||
|
*
|
||||||
|
* <p>This method continues checking at a fixed interval (500 milliseconds) if the button
|
||||||
|
* should be hidden. The recursion stops if the current segment changes or the duration
|
||||||
|
* to show the button has expired.</p>
|
||||||
|
*
|
||||||
|
* @param segment the sponsor segment associated with the current check
|
||||||
|
*/
|
||||||
|
private static void checkPlayerControlsVisibilityRecursive(SponsorSegment segment) {
|
||||||
|
if (skipSegmentButtonEndTime == 0
|
||||||
|
// Stop recursion if the current segment has changed
|
||||||
|
|| segment != segmentCurrentlyPlaying) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue recursion if the button's visibility duration has not expired
|
||||||
|
if (skipSegmentButtonEndTime > System.currentTimeMillis()) {
|
||||||
|
Utils.runOnMainThreadDelayed(() -> checkPlayerControlsVisibilityRecursive(segment), 1000);
|
||||||
|
} else {
|
||||||
|
// Hide the skip segment button and reset the end time
|
||||||
|
skipSegmentButtonEndTime = 0;
|
||||||
|
hiddenSkipSegmentsForCurrentVideoTime.add(segment);
|
||||||
|
SponsorBlockViewController.hideSkipSegmentButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void skipSegment(@NonNull SponsorSegment segmentToSkip, boolean userManuallySkipped) {
|
private static void skipSegment(@NonNull SponsorSegment segmentToSkip, boolean userManuallySkipped) {
|
||||||
try {
|
try {
|
||||||
SponsorBlockViewController.hideSkipHighlightButton();
|
SponsorBlockViewController.hideSkipHighlightButton();
|
||||||
@ -793,5 +858,4 @@ public class SegmentPlaybackController {
|
|||||||
Logger.printException(() -> "drawSponsorTimeBars failure", ex);
|
Logger.printException(() -> "drawSponsorTimeBars failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -201,25 +201,25 @@ private fun MutableMethod.initializeHook(classDescriptor: String) =
|
|||||||
"invoke-static {p0}, $classDescriptor->initialize(Landroid/view/View;)V"
|
"invoke-static {p0}, $classDescriptor->initialize(Landroid/view/View;)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun changeVisibilityHook(classDescriptor: String) =
|
internal fun changeVisibilityHook(classDescriptor: String) =
|
||||||
changeVisibilityMethod.addInstruction(
|
changeVisibilityMethod.addInstruction(
|
||||||
0,
|
0,
|
||||||
"invoke-static {p0, p1}, $classDescriptor->changeVisibility(ZZ)V"
|
"invoke-static {p0, p1}, $classDescriptor->changeVisibility(ZZ)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun changeVisibilityNegatedImmediateHook(classDescriptor: String) =
|
internal fun changeVisibilityNegatedImmediateHook(classDescriptor: String) =
|
||||||
changeVisibilityNegatedImmediatelyMethod.addInstruction(
|
changeVisibilityNegatedImmediatelyMethod.addInstruction(
|
||||||
0,
|
0,
|
||||||
"invoke-static {}, $classDescriptor->changeVisibilityNegatedImmediate()V"
|
"invoke-static {}, $classDescriptor->changeVisibilityNegatedImmediate()V"
|
||||||
)
|
)
|
||||||
|
|
||||||
fun hookBottomControlButton(classDescriptor: String) {
|
internal fun hookBottomControlButton(classDescriptor: String) {
|
||||||
initializeBottomControlButtonMethod.initializeHook(classDescriptor)
|
initializeBottomControlButtonMethod.initializeHook(classDescriptor)
|
||||||
changeVisibilityHook(classDescriptor)
|
changeVisibilityHook(classDescriptor)
|
||||||
changeVisibilityNegatedImmediateHook(classDescriptor)
|
changeVisibilityNegatedImmediateHook(classDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hookTopControlButton(classDescriptor: String) {
|
internal fun hookTopControlButton(classDescriptor: String) {
|
||||||
initializeTopControlButtonMethod.initializeHook(classDescriptor)
|
initializeTopControlButtonMethod.initializeHook(classDescriptor)
|
||||||
changeVisibilityHook(classDescriptor)
|
changeVisibilityHook(classDescriptor)
|
||||||
changeVisibilityNegatedImmediateHook(classDescriptor)
|
changeVisibilityNegatedImmediateHook(classDescriptor)
|
||||||
|
@ -12,6 +12,8 @@ import app.revanced.patches.youtube.utils.extension.Constants.EXTENSION_PATH
|
|||||||
import app.revanced.patches.youtube.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR
|
import app.revanced.patches.youtube.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.SPONSORBLOCK
|
import app.revanced.patches.youtube.utils.patch.PatchList.SPONSORBLOCK
|
||||||
import app.revanced.patches.youtube.utils.playercontrols.addTopControl
|
import app.revanced.patches.youtube.utils.playercontrols.addTopControl
|
||||||
|
import app.revanced.patches.youtube.utils.playercontrols.changeVisibilityHook
|
||||||
|
import app.revanced.patches.youtube.utils.playercontrols.changeVisibilityNegatedImmediateHook
|
||||||
import app.revanced.patches.youtube.utils.playercontrols.hookTopControlButton
|
import app.revanced.patches.youtube.utils.playercontrols.hookTopControlButton
|
||||||
import app.revanced.patches.youtube.utils.playercontrols.playerControlsPatch
|
import app.revanced.patches.youtube.utils.playercontrols.playerControlsPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout
|
import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout
|
||||||
@ -111,10 +113,17 @@ val sponsorBlockBytecodePatch = bytecodePatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Voting & Shield button
|
// Voting & Shield button
|
||||||
setOf("CreateSegmentButtonController;", "VotingButtonController;").forEach { className ->
|
setOf(
|
||||||
|
"CreateSegmentButtonController;",
|
||||||
|
"VotingButtonController;"
|
||||||
|
).forEach { className ->
|
||||||
hookTopControlButton("$EXTENSION_SPONSOR_BLOCK_UI_PATH/$className")
|
hookTopControlButton("$EXTENSION_SPONSOR_BLOCK_UI_PATH/$className")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip button
|
||||||
|
changeVisibilityHook(EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR)
|
||||||
|
changeVisibilityNegatedImmediateHook(EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR)
|
||||||
|
|
||||||
// Append timestamp
|
// Append timestamp
|
||||||
totalTimeFingerprint.methodOrThrow().apply {
|
totalTimeFingerprint.methodOrThrow().apply {
|
||||||
val targetIndex = indexOfFirstInstructionOrThrow {
|
val targetIndex = indexOfFirstInstructionOrThrow {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user