mirror of
https://github.com/revanced/revanced-integrations.git
synced 2024-11-27 22:36:51 +01:00
fix(YouTube - SponsorBlock): Improve create segment manual seek accuracy (#671)
This commit is contained in:
parent
d57a64b659
commit
34c02aeb2a
@ -7,7 +7,6 @@ import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -15,17 +14,21 @@ import java.util.Objects;
|
||||
* @noinspection unused
|
||||
*/
|
||||
public final class VideoInformation {
|
||||
|
||||
public interface PlaybackController {
|
||||
// Methods are added to YT classes during patching.
|
||||
boolean seekTo(long videoTime);
|
||||
boolean seekToRelative(long videoTimeOffset);
|
||||
}
|
||||
|
||||
private static final float DEFAULT_YOUTUBE_PLAYBACK_SPEED = 1.0f;
|
||||
private static final String SEEK_METHOD_NAME = "seekTo";
|
||||
/**
|
||||
* Prefix present in all Short player parameters signature.
|
||||
*/
|
||||
private static final String SHORTS_PLAYER_PARAMETERS = "8AEB";
|
||||
|
||||
private static WeakReference<Object> playerControllerRef;
|
||||
private static WeakReference<Object> mdxPlayerDirectorRef;
|
||||
private static Method seekMethod;
|
||||
private static Method mdxSeekMethod;
|
||||
private static WeakReference<PlaybackController> playerControllerRef = new WeakReference<>(null);
|
||||
private static WeakReference<PlaybackController> mdxPlayerDirectorRef = new WeakReference<>(null);
|
||||
|
||||
@NonNull
|
||||
private static String videoId = "";
|
||||
@ -47,15 +50,12 @@ public final class VideoInformation {
|
||||
*
|
||||
* @param playerController player controller object.
|
||||
*/
|
||||
public static void initialize(@NonNull Object playerController) {
|
||||
public static void initialize(@NonNull PlaybackController playerController) {
|
||||
try {
|
||||
playerControllerRef = new WeakReference<>(Objects.requireNonNull(playerController));
|
||||
videoTime = -1;
|
||||
videoLength = 0;
|
||||
playbackSpeed = DEFAULT_YOUTUBE_PLAYBACK_SPEED;
|
||||
|
||||
seekMethod = playerController.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE);
|
||||
seekMethod.setAccessible(true);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "Failed to initialize", ex);
|
||||
}
|
||||
@ -66,12 +66,9 @@ public final class VideoInformation {
|
||||
*
|
||||
* @param mdxPlayerDirector MDX player director object (casting mode).
|
||||
*/
|
||||
public static void initializeMdx(@NonNull Object mdxPlayerDirector) {
|
||||
public static void initializeMdx(@NonNull PlaybackController mdxPlayerDirector) {
|
||||
try {
|
||||
mdxPlayerDirectorRef = new WeakReference<>(Objects.requireNonNull(mdxPlayerDirector));
|
||||
|
||||
mdxSeekMethod = mdxPlayerDirector.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE);
|
||||
mdxSeekMethod.setAccessible(true);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "Failed to initialize MDX", ex);
|
||||
}
|
||||
@ -195,42 +192,80 @@ public final class VideoInformation {
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.printDebug(() -> "Seeking to " + adjustedSeekTime);
|
||||
Logger.printDebug(() -> "Seeking to: " + adjustedSeekTime);
|
||||
|
||||
try {
|
||||
//noinspection DataFlowIssue
|
||||
if ((Boolean) seekMethod.invoke(playerControllerRef.get(), adjustedSeekTime)) {
|
||||
return true;
|
||||
} // Else the video is loading or changing videos, or video is casting to a different device.
|
||||
} catch (Exception ex) {
|
||||
Logger.printInfo(() -> "seekTo method call failed", ex);
|
||||
// Try regular playback controller first, and it will not succeed if casting.
|
||||
PlaybackController controller = playerControllerRef.get();
|
||||
if (controller == null) {
|
||||
Logger.printDebug(() -> "Cannot seekTo because player controller is null");
|
||||
} else {
|
||||
if (controller.seekTo(adjustedSeekTime)) return true;
|
||||
Logger.printDebug(() -> "seekTo did not succeeded. Trying MXD.");
|
||||
// Else the video is loading or changing videos, or video is casting to a different device.
|
||||
}
|
||||
|
||||
// Try calling the seekTo method of the MDX player director (called when casting).
|
||||
// The difference has to be a different second mark in order to avoid infinite skip loops
|
||||
// as the Lounge API only supports seconds.
|
||||
if ((adjustedSeekTime / 1000) == (videoTime / 1000)) {
|
||||
Logger.printDebug(() -> "Skipping seekTo for MDX because seek time is too small ("
|
||||
+ (adjustedSeekTime - videoTime) + "ms)");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
//noinspection DataFlowIssue
|
||||
return (Boolean) mdxSeekMethod.invoke(mdxPlayerDirectorRef.get(), adjustedSeekTime);
|
||||
} catch (Exception ex) {
|
||||
Logger.printInfo(() -> "seekTo (MDX) method call failed", ex);
|
||||
if (adjustedSeekTime / 1000 == videoTime / 1000) {
|
||||
Logger.printDebug(() -> "Skipping seekTo for MDX because seek time is too small "
|
||||
+ "(" + (adjustedSeekTime - videoTime) + "ms)");
|
||||
return false;
|
||||
}
|
||||
|
||||
controller = mdxPlayerDirectorRef.get();
|
||||
if (controller == null) {
|
||||
Logger.printDebug(() -> "Cannot seekTo MXD because player controller is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
return controller.seekTo(adjustedSeekTime);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "Failed to seek", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @noinspection UnusedReturnValue*/
|
||||
public static boolean seekToRelative(long millisecondsRelative) {
|
||||
return seekTo(videoTime + millisecondsRelative);
|
||||
/**
|
||||
* Seeks a relative amount. Should always be used over {@link #seekTo(long)}
|
||||
* when the desired seek time is an offset of the current time.
|
||||
*
|
||||
* @noinspection UnusedReturnValue
|
||||
*/
|
||||
public static boolean seekToRelative(long seekTime) {
|
||||
Utils.verifyOnMainThread();
|
||||
try {
|
||||
Logger.printDebug(() -> "Seeking relative to: " + seekTime);
|
||||
|
||||
// Try regular playback controller first, and it will not succeed if casting.
|
||||
PlaybackController controller = playerControllerRef.get();
|
||||
if (controller == null) {
|
||||
Logger.printDebug(() -> "Cannot seek relative as player controller is null");
|
||||
} else {
|
||||
if (controller.seekToRelative(seekTime)) return true;
|
||||
Logger.printDebug(() -> "seekToRelative did not succeeded. Trying MXD.");
|
||||
}
|
||||
|
||||
// Adjust the fine adjustment function so it's at least 1 second before/after.
|
||||
// Otherwise the fine adjustment will do nothing when casting.
|
||||
final long adjustedSeekTime;
|
||||
if (seekTime < 0) {
|
||||
adjustedSeekTime = Math.min(seekTime, -1000);
|
||||
} else {
|
||||
adjustedSeekTime = Math.max(seekTime, 1000);
|
||||
}
|
||||
|
||||
controller = mdxPlayerDirectorRef.get();
|
||||
if (controller == null) {
|
||||
Logger.printDebug(() -> "Cannot seek relative as MXD player controller is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
return controller.seekToRelative(adjustedSeekTime);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "Failed to seek relative", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,19 +1,20 @@
|
||||
package app.revanced.integrations.youtube.patches.playback.quality;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import static app.revanced.integrations.shared.StringRef.str;
|
||||
import static app.revanced.integrations.shared.Utils.NetworkType;
|
||||
|
||||
import app.revanced.integrations.shared.settings.IntegerSetting;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static app.revanced.integrations.shared.StringRef.str;
|
||||
import static app.revanced.integrations.shared.Utils.NetworkType;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.shared.settings.IntegerSetting;
|
||||
import app.revanced.integrations.youtube.patches.VideoInformation;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class RememberVideoQualityPatch {
|
||||
@ -158,7 +159,7 @@ public class RememberVideoQualityPatch {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void newVideoStarted(Object ignoredPlayerController) {
|
||||
public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) {
|
||||
Logger.printDebug(() -> "newVideoStarted");
|
||||
qualityNeedsUpdating = true;
|
||||
videoQualities = null;
|
||||
|
@ -13,7 +13,7 @@ public final class RememberPlaybackSpeedPatch {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void newVideoStarted(Object ignoredPlayerController) {
|
||||
public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) {
|
||||
Logger.printDebug(() -> "newVideoStarted");
|
||||
VideoInformation.overridePlaybackSpeed(Settings.PLAYBACK_SPEED_DEFAULT.get());
|
||||
}
|
||||
|
@ -11,11 +11,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
@ -182,7 +178,7 @@ public class SegmentPlaybackController {
|
||||
* Injection point.
|
||||
* Initializes SponsorBlock when the video player starts playing a new video.
|
||||
*/
|
||||
public static void initialize(Object ignoredPlayerController) {
|
||||
public static void initialize(VideoInformation.PlaybackController ignoredPlayerController) {
|
||||
try {
|
||||
Utils.verifyOnMainThread();
|
||||
SponsorBlockSettings.initialize();
|
||||
@ -632,6 +628,7 @@ public class SegmentPlaybackController {
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void setSponsorBarRect(final Object self) {
|
||||
try {
|
||||
Field field = self.getClass().getDeclaredField("replaceMeWithsetSponsorBarRect");
|
||||
@ -663,6 +660,7 @@ public class SegmentPlaybackController {
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void setSponsorBarThickness(int thickness) {
|
||||
if (sponsorBarThickness != thickness) {
|
||||
Logger.printDebug(() -> "setSponsorBarThickness: " + thickness);
|
||||
@ -673,6 +671,7 @@ public class SegmentPlaybackController {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static String appendTimeWithoutSegments(String totalTime) {
|
||||
try {
|
||||
if (Settings.SB_ENABLED.get() && Settings.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.get()
|
||||
@ -725,9 +724,9 @@ public class SegmentPlaybackController {
|
||||
final long minutes = (timeWithoutSegmentsValue / 60000) % 60;
|
||||
final long seconds = (timeWithoutSegmentsValue / 1000) % 60;
|
||||
if (hours > 0) {
|
||||
timeWithoutSegments = String.format("\u2009(%d:%02d:%02d)", hours, minutes, seconds);
|
||||
timeWithoutSegments = String.format(Locale.ENGLISH, "\u2009(%d:%02d:%02d)", hours, minutes, seconds);
|
||||
} else {
|
||||
timeWithoutSegments = String.format("\u2009(%d:%02d)", minutes, seconds);
|
||||
timeWithoutSegments = String.format(Locale.ENGLISH, "\u2009(%d:%02d)", minutes, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,6 +743,7 @@ public class SegmentPlaybackController {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void drawSponsorTimeBars(final Canvas canvas, final float posY) {
|
||||
try {
|
||||
if (segments == null) return;
|
||||
|
Loading…
Reference in New Issue
Block a user