mirror of
https://github.com/revanced/revanced-integrations.git
synced 2025-01-20 16:57:32 +01:00
fix(youtube/sponsorblock): fix some segments skipping slightly too late (#436)
This commit is contained in:
parent
59850b2c04
commit
f69492819e
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user