Skip to content

Commit

Permalink
Per-category skip modes & Unskip support (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikooomich authored Jan 27, 2024
1 parent de131ee commit 2f8e863
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 3 deletions.
162 changes: 159 additions & 3 deletions app/src/main/java/org/schabi/newpipe/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.SponsorBlockMode;
import org.schabi.newpipe.util.SponsorBlockSecondaryMode;
import org.schabi.newpipe.util.SponsorBlockHelper;
import org.schabi.newpipe.util.image.PicassoHelper;
import org.schabi.newpipe.util.SerializedCache;
Expand Down Expand Up @@ -174,6 +175,7 @@ public final class Player implements PlaybackListener, Listener {

public static final int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds
public static final int PROGRESS_LOOP_INTERVAL_MILLIS = 1000; // 1 second
private static final int UNSKIP_WINDOW_MILLIS = 5000; // 5 seconds

/*//////////////////////////////////////////////////////////////////////////
// Other constants
Expand Down Expand Up @@ -269,6 +271,8 @@ public final class Player implements PlaybackListener, Listener {
@NonNull
private final HistoryRecordManager recordManager;
private SponsorBlockMode sponsorBlockMode = SponsorBlockMode.DISABLED;
private SponsorBlockSegment lastSegment;
private boolean autoSkipGracePeriod = false;

private final SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;

Expand Down Expand Up @@ -950,10 +954,16 @@ public boolean isProgressLoopRunning() {
}

public void triggerProgressUpdate() {
triggerProgressUpdate(false);
triggerProgressUpdate(false, false, false);
}

public void triggerProgressUpdate(final boolean isRewind) {
triggerProgressUpdate(isRewind, false, false);
}

private void triggerProgressUpdate(final boolean isRewind,
final boolean isGracedRewind,
final boolean bypassSecondaryMode) {
if (exoPlayerIsNull()) {
return;
}
Expand All @@ -965,16 +975,70 @@ public void triggerProgressUpdate(final boolean isRewind) {
(int) simpleExoPlayer.getDuration(),
simpleExoPlayer.getBufferedPercentage());

triggerCheckForSponsorBlockSegments(currentProgress, isRewind);
triggerCheckForSponsorBlockSegments(currentProgress, isRewind,
isGracedRewind, bypassSecondaryMode);
}

private void triggerCheckForSponsorBlockSegments(final int currentProgress,
final boolean isRewind) {
final boolean isRewind,
final boolean isGracedRewind,
final boolean bypassSecondaryMode) {
if (sponsorBlockMode != SponsorBlockMode.ENABLED || !isPrepared) {
return;
}

getSkippableSponsorBlockSegment(currentProgress).ifPresent(sponsorBlockSegment -> {

final boolean showManualButtons = prefs.getBoolean(
context.getString(R.string.sponsor_block_show_manual_skip_key), false);
// per-sponsorBlockSegment category skip setting
final SponsorBlockSecondaryMode secondaryMode = getSecondaryMode(sponsorBlockSegment);

// show/hide manual skip buttons
if (showManualButtons && secondaryMode != SponsorBlockSecondaryMode.HIGHLIGHT) {
if (currentProgress < sponsorBlockSegment.endTime
&& currentProgress > sponsorBlockSegment.startTime) {
UIs.call(PlayerUi::showAutoSkip);
} else {
UIs.call(PlayerUi::hideAutoSkip);
}

if (currentProgress > sponsorBlockSegment.startTime
&& currentProgress < sponsorBlockSegment.endTime + UNSKIP_WINDOW_MILLIS) {
UIs.call(PlayerUi::showAutoUnskip);
} else {
UIs.call(PlayerUi::hideAutoUnskip);
}
}

if (DEBUG) {
Log.d("SPONSOR_BLOCK", "Un-skip grace: isGracedRewind = "
+ isGracedRewind + ", autoSkipGracePeriod = " + autoSkipGracePeriod);
}

// temporarily pause auto skipping
// bypass grace when this is an un-skip request
if (!isGracedRewind) {
if (autoSkipGracePeriod) {
return;
}
} else {

autoSkipGracePeriod = true;
}

// prevent skip looping in unship window
if (lastSegment == sponsorBlockSegment && !bypassSecondaryMode) {
return;
}

// Do not skip if highlight mode. Do not skip if manual mode + no explicit bypass
if (secondaryMode == SponsorBlockSecondaryMode.HIGHLIGHT
|| (secondaryMode == SponsorBlockSecondaryMode.MANUAL
&& !bypassSecondaryMode)) {
return;
}

int skipTarget = isRewind
? (int) Math.ceil((sponsorBlockSegment.startTime)) - 1
: (int) Math.ceil((sponsorBlockSegment.endTime));
Expand All @@ -990,6 +1054,7 @@ private void triggerCheckForSponsorBlockSegments(final int currentProgress,
seekTo(skipTarget);

simpleExoPlayer.setSeekParameters(seekParams);
lastSegment = sponsorBlockSegment;

if (prefs.getBoolean(
context.getString(R.string.sponsor_block_notifications_key), false)) {
Expand Down Expand Up @@ -1288,6 +1353,15 @@ public void toggleShuffleModeEnabled() {
simpleExoPlayer.setShuffleModeEnabled(!simpleExoPlayer.getShuffleModeEnabled());
}
}

public void toggleUnskip() {
triggerProgressUpdate(true, true, true);
}

public void toggleSkip() {
autoSkipGracePeriod = false;
triggerProgressUpdate(false, true, true);
}
//endregion


Expand Down Expand Up @@ -1793,6 +1867,12 @@ public void fastRewind() {
Log.d(TAG, "fastRewind() called");
}
seekBy(-retrieveSeekDurationFromPreferences(this));
if (prefs.getBoolean(
context.getString(R.string.sponsor_block_graced_rewind_key), false)) {
triggerProgressUpdate(true, true, false);
return;
}

triggerProgressUpdate(true);
}
//endregion
Expand Down Expand Up @@ -2409,10 +2489,86 @@ public Optional<SponsorBlockSegment> getSkippableSponsorBlockSegment(final int p
return sponsorBlockSegment;
}

// fallback on old SponsorBlockSegment (for un-skip)
if (lastSegment != null
&& progress > lastSegment.endTime + UNSKIP_WINDOW_MILLIS) {
// un-skip window is over
destroyUnskipVars();
} else if (lastSegment != null
&& progress < lastSegment.endTime + UNSKIP_WINDOW_MILLIS
&& progress >= lastSegment.startTime) {
// use old sponsorBlockSegment if exists AND currentProgress in bounds
return lastSegment;
}

destroyUnskipVars();
return null;
});
}

private void destroyUnskipVars() {
if (DEBUG) {
Log.d("SPONSOR_BLOCK", "Destroying last segment variables, hiding manual skip buttons");
}
lastSegment = null;
autoSkipGracePeriod = false;
UIs.call(PlayerUi::hideAutoSkip);
UIs.call(PlayerUi::hideAutoUnskip);
}

private SponsorBlockSecondaryMode getSecondaryMode(final SponsorBlockSegment segment) {
if (segment == null) {
return SponsorBlockSecondaryMode.DISABLED;
}

// get pref
final String defaultValue = context.getString(R.string.sponsor_block_skip_mode_enabled);
final String key = switch (segment.category) {
case SPONSOR -> prefs.getString(
context.getString(R.string.sponsor_block_category_sponsor_mode_key),
defaultValue);
case INTRO -> prefs.getString(
context.getString(R.string.sponsor_block_category_intro_mode_key),
defaultValue);
case OUTRO -> prefs.getString(
context.getString(R.string.sponsor_block_category_outro_mode_key),
defaultValue);
case INTERACTION -> prefs.getString(
context.getString(R.string.sponsor_block_category_interaction_mode_key),
defaultValue);
case HIGHLIGHT -> "Highlight Only"; // not a regular "skippable" segment
case SELF_PROMO -> prefs.getString(
context.getString(R.string.sponsor_block_category_self_promo_mode_key),
defaultValue);
case NON_MUSIC -> prefs.getString(
context.getString(R.string.sponsor_block_category_non_music_mode_key),
defaultValue);
case PREVIEW -> prefs.getString(
context.getString(R.string.sponsor_block_category_preview_mode_key),
defaultValue);
case FILLER -> prefs.getString(
context.getString(R.string.sponsor_block_category_filler_mode_key),
defaultValue);
default -> "";
};

// map pref to enum
final SponsorBlockSecondaryMode pref =
switch (key) {
case "Automatic" -> SponsorBlockSecondaryMode.ENABLED;
case "Manual" -> SponsorBlockSecondaryMode.MANUAL;
case "Highlight Only" -> SponsorBlockSecondaryMode.HIGHLIGHT;
default -> SponsorBlockSecondaryMode.DISABLED;
};

if (DEBUG) {
Log.d("SPONSOR_BLOCK", "Sponsor segment secondary mode: category = ["
+ segment.category + "], preference = [" + pref + "]");
}

return pref;
}

/**
* @return the user interfaces connected with the player
*/
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,28 @@ public void onPlayQueueEdited() {
*/
public void onVideoSizeChanged(@NonNull final VideoSize videoSize) {
}

/**
* Show SponsorBlock segment un-skip button.
*/
public void showAutoUnskip() {
}

/**
* Hide SponsorBlock segment un-skip button.
*/
public void hideAutoUnskip() {
}

/**
* Show SponsorBlock segment skip button.
*/
public void showAutoSkip() {
}

/**
* Hide SponsorBlock segment skip button.
*/
public void hideAutoSkip() {
}
}
33 changes: 33 additions & 0 deletions app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ protected void initListeners() {

binding.repeatButton.setOnClickListener(v -> onRepeatClicked());
binding.shuffleButton.setOnClickListener(v -> onShuffleClicked());
binding.unskipButton.setOnClickListener(v -> onUnskipClicked());
binding.skipButton.setOnClickListener(v -> onSkipClicked());

binding.playPauseButton.setOnClickListener(makeOnClickListener(player::playPause));
binding.playPreviousButton.setOnClickListener(makeOnClickListener(player::playPrevious));
Expand Down Expand Up @@ -292,6 +294,8 @@ protected void deinitListeners() {

binding.repeatButton.setOnClickListener(null);
binding.shuffleButton.setOnClickListener(null);
binding.unskipButton.setOnClickListener(null);
binding.skipButton.setOnClickListener(null);

binding.playPauseButton.setOnClickListener(null);
binding.playPreviousButton.setOnClickListener(null);
Expand Down Expand Up @@ -857,6 +861,21 @@ public void onBuffering() {
binding.getRoot().setKeepScreenOn(true);
}

public void showAutoUnskip() {
binding.unskipButton.setVisibility(View.VISIBLE);
}

public void hideAutoUnskip() {
binding.unskipButton.setVisibility(View.GONE);
}

public void showAutoSkip() {
binding.skipButton.setVisibility(View.VISIBLE);
}
public void hideAutoSkip() {
binding.skipButton.setVisibility(View.GONE);
}

@Override
public void onPaused() {
super.onPaused();
Expand Down Expand Up @@ -953,6 +972,20 @@ public void onShuffleClicked() {
player.toggleShuffleModeEnabled();
}

public void onUnskipClicked() {
if (DEBUG) {
Log.d(TAG, "onUnskipClicked() called");
}
player.toggleUnskip();
}

public void onSkipClicked() {
if (DEBUG) {
Log.d(TAG, "onSkipClicked() called");
}
player.toggleSkip();
}

@Override
public void onRepeatModeChanged(@RepeatMode final int repeatMode) {
super.onRepeatModeChanged(repeatMode);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.schabi.newpipe.util;

public enum SponsorBlockSecondaryMode {
DISABLED,
ENABLED,
MANUAL,
HIGHLIGHT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#64000000" />
<corners android:radius="5dp"/>
</shape>
Loading

0 comments on commit 2f8e863

Please sign in to comment.