fix(youtube/sponsorblock): fix toast shown when scrubbing thru a paused video (#401)

This commit is contained in:
LisoUseInAIKyrios 2023-05-16 10:31:23 +04:00 committed by GitHub
parent fc2ad5fa76
commit 7da56738a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 36 deletions

View File

@ -15,7 +15,7 @@ import app.revanced.integrations.shared.PlayerOverlays;
@SuppressWarnings("unused")
public class PlayerOverlaysHookPatch {
/**
* Hook into YouTubePlayerOverlaysLayout.onFinishInflate() method
* Injection point.
*
* @param thisRef reference to the view
* @smali YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava / lang / Object ;)V

View File

@ -3,32 +3,25 @@ package app.revanced.integrations.patches;
import androidx.annotation.Nullable;
import app.revanced.integrations.shared.PlayerType;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.shared.VideoState;
/**
* Hook receiver class for 'player-type-hook' patch
*
* @usedBy app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
* @smali Lapp/revanced/integrations/patches/PlayerTypeHookPatch;
*/
@SuppressWarnings("unused")
public class PlayerTypeHookPatch {
/**
* Hook into YouTubePlayerOverlaysLayout.updatePlayerLayout() method
*
* @param type the new player type
* @smali YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V
* Injection point.
*/
public static void YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(@Nullable Object type) {
if (type == null) return;
public static void setPlayerType(@Nullable Enum<?> youTubePlayerType) {
if (youTubePlayerType == null) return;
// update current player type
final PlayerType newType = PlayerType.safeParseFromString(type.toString());
if (newType == null) {
LogHelper.printException(() -> "Unknown PlayerType encountered: " + type);
} else {
PlayerType.setCurrent(newType);
LogHelper.printDebug(() -> "PlayerType was updated to: " + newType);
}
PlayerType.setFromString(youTubePlayerType.name());
}
/**
* Injection point.
*/
public static void setVideoState(@Nullable Enum<?> youTubeVideoState) {
if (youTubeVideoState == null) return;
VideoState.setFromString(youTubeVideoState.name());
}
}

View File

@ -7,6 +7,7 @@ import java.lang.reflect.Method;
import java.util.Objects;
import app.revanced.integrations.patches.playback.speed.RememberPlaybackSpeedPatch;
import app.revanced.integrations.shared.VideoState;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
@ -183,7 +184,12 @@ public final class VideoInformation {
* @return If the playback is at the end of the video.
*
* If video is playing in the background with no video visible,
* this always returns false (even if the video is actually at the end)
* this always returns false (even if the video is actually at the end).
*
* This is equivalent to checking for {@link VideoState#ENDED},
* but can give a more up to date result for code calling from some hooks.
*
* @see VideoState
*/
public static boolean isAtEndOfVideo() {
return videoTime > 0 && videoLength > 0 && videoTime >= videoLength;

View File

@ -1,11 +1,11 @@
package app.revanced.integrations.shared
import app.revanced.integrations.utils.Event
import app.revanced.integrations.utils.LogHelper
/**
* WatchWhile player type
*/
@Suppress("unused")
enum class PlayerType {
/**
* Includes Shorts and Stories playback.
@ -40,15 +40,15 @@ enum class PlayerType {
private val nameToPlayerType = values().associateBy { it.name }
/**
* safely parse from a string
*
* @param name the name to find
* @return the enum constant, or null if not found
*/
@JvmStatic
fun safeParseFromString(name: String): PlayerType? {
return nameToPlayerType[name]
fun setFromString(enumName: String) {
val newType = nameToPlayerType[enumName]
if (newType == null) {
LogHelper.printException { "Unknown PlayerType encountered: $enumName" }
} else if (current != newType) {
LogHelper.printDebug { "PlayerType changed to: $newType" }
current = newType
}
}
/**
@ -57,7 +57,7 @@ enum class PlayerType {
@JvmStatic
var current
get() = currentPlayerType
set(value) {
private set(value) {
currentPlayerType = value
onChange(currentPlayerType)
}
@ -90,7 +90,7 @@ enum class PlayerType {
* although can return false positive if the player is minimized.
*
* @return If nothing, a Short, a Story,
* or a regular minimized video is sliding off screen to a dismissed or hidden state.
* or a regular video is minimized video or sliding off screen to a dismissed or hidden state.
*/
fun isNoneHiddenOrMinimized(): Boolean {
return this == NONE || this == HIDDEN

View File

@ -0,0 +1,48 @@
package app.revanced.integrations.shared
import app.revanced.integrations.utils.LogHelper
import app.revanced.integrations.patches.VideoInformation
/**
* VideoState playback state.
*/
enum class VideoState {
NEW,
PLAYING,
PAUSED,
RECOVERABLE_ERROR,
UNRECOVERABLE_ERROR,
/**
* @see [VideoInformation.isAtEndOfVideo]
*/
ENDED;
companion object {
private val nameToVideoState = values().associateBy { it.name }
@JvmStatic
fun setFromString(enumName: String) {
val state = nameToVideoState[enumName]
if (state == null) {
LogHelper.printException { "Unknown VideoState encountered: $enumName" }
} else if (currentVideoState != state) {
LogHelper.printDebug { "VideoState changed to: $state" }
currentVideoState = state
}
}
/**
* Depending on which hook this is called from,
* this value may not be up to date with the actual playback state.
*/
@JvmStatic
var current: VideoState?
get() = currentVideoState
private set(value) {
currentVideoState = value
}
private var currentVideoState : VideoState? = null
}
}

View File

@ -20,6 +20,7 @@ import java.util.Objects;
import app.revanced.integrations.patches.VideoInformation;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.shared.PlayerType;
import app.revanced.integrations.shared.VideoState;
import app.revanced.integrations.sponsorblock.objects.CategoryBehaviour;
import app.revanced.integrations.sponsorblock.objects.SegmentCategory;
import app.revanced.integrations.sponsorblock.objects.SponsorSegment;
@ -522,6 +523,7 @@ public class SegmentPlaybackController {
return;
}
final boolean videoIsPaused = VideoState.getCurrent() == VideoState.PAUSED;
if (!userManuallySkipped) {
// check for any smaller embedded segments, and count those as autoskipped
final boolean showSkipToast = SettingsEnum.SB_TOAST_ON_SKIP.getBoolean();
@ -532,7 +534,10 @@ public class SegmentPlaybackController {
if (otherSegment == segmentToSkip ||
(otherSegment.category != SegmentCategory.HIGHLIGHT && segmentToSkip.containsSegment(otherSegment))) {
otherSegment.didAutoSkipped = true;
if (showSkipToast) {
// Do not show a toast if the user is scrubbing thru a paused video.
// Cannot do this video state check in setTime or earlier in this method, as the video state may not be up to date.
// So instead, only hide toasts because all other skip logic done while paused causes no harm.
if (showSkipToast && !videoIsPaused) {
showSkippedSegmentToast(otherSegment);
}
}
@ -542,7 +547,7 @@ public class SegmentPlaybackController {
if (segmentToSkip.category == SegmentCategory.UNSUBMITTED) {
removeUnsubmittedSegments();
SponsorBlockUtils.setNewSponsorSegmentPreviewed();
} else {
} else if (!videoIsPaused) {
SponsorBlockUtils.sendViewRequestAsync(segmentToSkip);
}
} catch (Exception ex) {