SponsorBlock: Added exclusion list feature

Added the ability to add uploaders to a persistent exclusion list by long-pressing the SponsorBlock icon. Segments won't be skipped, but they will still be marked.
This commit is contained in:
polymorphicshade 2020-08-23 15:03:48 -06:00
parent dfb94a2503
commit 4cadf54bc2
9 changed files with 164 additions and 24 deletions

View file

@ -76,9 +76,11 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.resolver.MediaSourceTag; import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.SerializedCache; import org.schabi.newpipe.util.SerializedCache;
import org.schabi.newpipe.util.SponsorBlockMode;
import org.schabi.newpipe.util.VideoSegment; import org.schabi.newpipe.util.VideoSegment;
import java.io.IOException; import java.io.IOException;
import java.util.Set;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
@ -205,7 +207,7 @@ public abstract class BasePlayer implements
private Disposable stateLoader; private Disposable stateLoader;
protected int currentState = STATE_PREFLIGHT; protected int currentState = STATE_PREFLIGHT;
private boolean isBlockingSponsors; private SponsorBlockMode sponsorBlockMode = SponsorBlockMode.DISABLED;
public BasePlayer(@NonNull final Context context) { public BasePlayer(@NonNull final Context context) {
this.context = context; this.context = context;
@ -237,9 +239,6 @@ public abstract class BasePlayer implements
this.renderFactory = new DefaultRenderersFactory(context); this.renderFactory = new DefaultRenderersFactory(context);
this.mPrefs = PreferenceManager.getDefaultSharedPreferences(App.getApp()); this.mPrefs = PreferenceManager.getDefaultSharedPreferences(App.getApp());
isBlockingSponsors = mPrefs.getBoolean(context.getString(R.string.sponsor_block_enable_key),
false);
} }
public void setup() { public void setup() {
@ -699,11 +698,25 @@ public abstract class BasePlayer implements
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onBlockingSponsorsButtonClicked() called"); Log.d(TAG, "onBlockingSponsorsButtonClicked() called");
} }
isBlockingSponsors = !isBlockingSponsors;
switch (sponsorBlockMode) {
case DISABLED:
sponsorBlockMode = SponsorBlockMode.ENABLED;
break;
case ENABLED:
sponsorBlockMode = SponsorBlockMode.DISABLED;
break;
case EXCLUDE:
// ignored
}
} }
public boolean isBlockingSponsors() { public SponsorBlockMode getSponsorBlockMode() {
return isBlockingSponsors; return sponsorBlockMode;
}
public void setSponsorBlockMode(final SponsorBlockMode mode) {
sponsorBlockMode = mode;
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -731,9 +744,7 @@ public abstract class BasePlayer implements
simpleExoPlayer.getBufferedPercentage() simpleExoPlayer.getBufferedPercentage()
); );
if (isBlockingSponsors if (sponsorBlockMode == SponsorBlockMode.ENABLED) {
&& mPrefs.getBoolean(
context.getString(R.string.sponsor_block_enable_key), false)) {
final VideoSegment segment = getSkippableSegment(currentProgress); final VideoSegment segment = getSkippableSegment(currentProgress);
if (segment == null) { if (segment == null) {
return; return;
@ -1165,11 +1176,22 @@ public abstract class BasePlayer implements
initThumbnail(info.getThumbnailUrl()); initThumbnail(info.getThumbnailUrl());
registerView(); registerView();
final boolean isSponsorBlockEnabled = mPrefs.getBoolean(
context.getString(R.string.sponsor_block_enable_key), false);
final Set<String> channelExclusions = mPrefs.getStringSet(
context.getString(R.string.sponsor_block_exclusion_list_key), null);
if (channelExclusions != null && channelExclusions.contains(info.getUploaderName())) {
sponsorBlockMode = SponsorBlockMode.EXCLUDE;
} else {
sponsorBlockMode = isSponsorBlockEnabled
? SponsorBlockMode.ENABLED
: SponsorBlockMode.DISABLED;
}
if (info.getUrl().startsWith("https://www.youtube.com")) { if (info.getUrl().startsWith("https://www.youtube.com")) {
final String apiUrl = mPrefs final String apiUrl = mPrefs
.getString(context.getString(R.string.sponsor_block_api_url_key), null); .getString(context.getString(R.string.sponsor_block_api_url_key), null);
final boolean isSponsorBlockEnabled = mPrefs
.getBoolean(context.getString(R.string.sponsor_block_enable_key), false);
if (apiUrl != null && !apiUrl.isEmpty() && isSponsorBlockEnabled) { if (apiUrl != null && !apiUrl.isEmpty() && isSponsorBlockEnabled) {
try { try {

View file

@ -100,8 +100,11 @@ import org.schabi.newpipe.util.KoreUtil;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ShareUtils; import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.SponsorBlockMode;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import static android.content.Context.WINDOW_SERVICE; import static android.content.Context.WINDOW_SERVICE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@ -409,7 +412,7 @@ public class VideoPlayerImpl extends VideoPlayer
channelTextView.setVisibility(View.VISIBLE); channelTextView.setVisibility(View.VISIBLE);
} }
setMuteButton(muteButton, isMuted()); setMuteButton(muteButton, isMuted());
setBlockSponsorsButton(blockSponsorsButton, isBlockingSponsors()); setBlockSponsorsButton(blockSponsorsButton);
animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0); animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0);
} }
@ -483,6 +486,7 @@ public class VideoPlayerImpl extends VideoPlayer
if (blockSponsorsButton != null) { if (blockSponsorsButton != null) {
blockSponsorsButton.setOnClickListener(this); blockSponsorsButton.setOnClickListener(this);
blockSponsorsButton.setOnLongClickListener(this);
} }
settingsContentObserver = new ContentObserver(new Handler()) { settingsContentObserver = new ContentObserver(new Handler()) {
@ -630,6 +634,8 @@ public class VideoPlayerImpl extends VideoPlayer
showHideKodiButton(); showHideKodiButton();
setBlockSponsorsButton(blockSponsorsButton);
titleTextView.setText(tag.getMetadata().getName()); titleTextView.setText(tag.getMetadata().getName());
channelTextView.setText(tag.getMetadata().getUploaderName()); channelTextView.setText(tag.getMetadata().getUploaderName());
@ -656,13 +662,18 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public void onBlockingSponsorsButtonClicked() { public void onBlockingSponsorsButtonClicked() {
super.onBlockingSponsorsButtonClicked(); super.onBlockingSponsorsButtonClicked();
setBlockSponsorsButton(blockSponsorsButton, isBlockingSponsors()); setBlockSponsorsButton(blockSponsorsButton);
Toast.makeText(context, switch (getSponsorBlockMode()) {
isBlockingSponsors() case DISABLED:
? "SponsorBlock enabled" Toast.makeText(context, "SponsorBlock disabled", Toast.LENGTH_SHORT).show();
: "SponsorBlock disabled", break;
Toast.LENGTH_SHORT).show(); case ENABLED:
Toast.makeText(context, "SponsorBlock enabled", Toast.LENGTH_SHORT).show();
break;
case EXCLUDE:
// ignored
}
} }
@Override @Override
@ -857,6 +868,43 @@ public class VideoPlayerImpl extends VideoPlayer
fragmentListener.onMoreOptionsLongClicked(); fragmentListener.onMoreOptionsLongClicked();
hideControls(0, 0); hideControls(0, 0);
hideSystemUIIfNeeded(); hideSystemUIIfNeeded();
} else if (v.getId() == blockSponsorsButton.getId()) {
final MediaSourceTag currentMetadata = getCurrentMetadata();
if (currentMetadata == null) {
return true;
}
final Set<String> channelExclusions =
mPrefs.getStringSet(
context.getString(R.string.sponsor_block_exclusion_list_key),
new HashSet<>());
final String toastText;
if (getSponsorBlockMode() == SponsorBlockMode.EXCLUDE) {
if (channelExclusions != null) {
channelExclusions.remove(currentMetadata.getMetadata().getUploaderName());
}
setSponsorBlockMode(SponsorBlockMode.ENABLED);
toastText = "Uploader removed from SponsorBlock exclusion list";
} else {
if (channelExclusions != null) {
channelExclusions.add(currentMetadata.getMetadata().getUploaderName());
}
setSponsorBlockMode(SponsorBlockMode.EXCLUDE);
toastText = "Uploader excluded from SponsorBlock";
}
mPrefs.edit()
.putStringSet(
context.getString(R.string.sponsor_block_exclusion_list_key),
channelExclusions)
.apply();
setBlockSponsorsButton(blockSponsorsButton);
Toast.makeText(context, toastText, Toast.LENGTH_LONG).show();
} }
return true; return true;
} }
@ -1605,15 +1653,29 @@ public class VideoPlayerImpl extends VideoPlayer
? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_up_white_24dp)); ? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_up_white_24dp));
} }
protected void setBlockSponsorsButton(final ImageButton button, protected void setBlockSponsorsButton(final ImageButton button) {
final boolean isBlockingSponsors) {
if (button == null) { if (button == null) {
return; return;
} }
button.setImageDrawable(AppCompatResources.getDrawable(service, isBlockingSponsors final SponsorBlockMode sponsorBlockMode = getSponsorBlockMode();
? R.drawable.ic_sponsor_block_enable_white_24dp final int resId;
: R.drawable.ic_sponsor_block_disable_white_24dp));
switch (sponsorBlockMode) {
case DISABLED:
resId = R.drawable.ic_sponsor_block_disable_white_24dp;
break;
case ENABLED:
resId = R.drawable.ic_sponsor_block_enable_white_24dp;
break;
case EXCLUDE:
resId = R.drawable.ic_sponsor_block_exclude_white_24dp;
break;
default:
return;
}
button.setImageDrawable(AppCompatResources.getDrawable(service, resId));
} }
/** /**

View file

@ -40,6 +40,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@ -169,6 +170,19 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
updateDependencies(preference, newValue); updateDependencies(preference, newValue);
return true; return true;
}); });
final Preference sponsorBlockClearExclusionListPreference =
findPreference(getString(R.string.sponsor_block_clear_exclusion_list_key));
sponsorBlockClearExclusionListPreference.setOnPreferenceClickListener((Preference p) -> {
getPreferenceManager()
.getSharedPreferences()
.edit()
.putStringSet(
getString(R.string.sponsor_block_exclusion_list_key), new HashSet<>())
.apply();
Toast.makeText(getContext(), "Exclusion list cleared", Toast.LENGTH_SHORT).show();
return true;
});
} }
@Override @Override

View file

@ -0,0 +1,7 @@
package org.schabi.newpipe.util;
public enum SponsorBlockMode {
DISABLED,
ENABLED,
EXCLUDE
}

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,24c-0.5,0 -1,-0.1 -1.4,-0.4C4.1,19.6 0.1,12.7 0,5.1c0,-1 0.5,-2 1.4,-2.5C8,-0.9 16,-0.9 22.6,2.7C23.5,3.1 24,4.1 24,5.1c-0.1,7.6 -4.1,14.5 -10.5,18.5C13,23.9 12.5,24 12,24zM12,0.8c-3.5,0 -7,0.9 -10.2,2.6c-0.6,0.3 -1,1 -1,1.7C0.9,12.4 4.7,19 11,22.9c0.6,0.4 1.4,0.4 2,0c6.3,-3.8 10,-10.5 10.2,-17.8c0,-0.7 -0.4,-1.4 -1,-1.7C19,1.7 15.5,0.8 12,0.8z"/>
<path
android:fillColor="#FF000000"
android:pathData="M21.7,4.2C15.6,1 8.4,1 2.3,4.2C2,4.4 1.8,4.7 1.8,5.1c0.1,7.2 3.9,13.4 9.7,17c0.3,0.2 0.7,0.2 1,0c5.7,-3.5 9.6,-9.8 9.7,-17C22.2,4.7 22,4.4 21.7,4.2zM12,15.8c0,0 -5,-4 -5,-6.6c0,-1.7 1.1,-2.7 2.5,-2.7c1.2,0 2.5,1.3 2.5,1.3s1.2,-1.3 2.5,-1.3c1.4,0 2.5,0.9 2.5,2.7C17,11.8 12,15.8 12,15.8z"/>
</vector>

View file

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<path
android:fillColor="#FF000000"
android:pathData="M12,24c-0.5,0 -1,-0.1 -1.4,-0.4C4.1,19.6 0.1,12.7 0,5.1c0,-1 0.5,-2 1.4,-2.5C8,-0.9 16,-0.9 22.6,2.7C23.5,3.1 24,4.1 24,5.1c-0.1,7.6 -4.1,14.5 -10.5,18.5C13,23.9 12.5,24 12,24zM12,0.8c-3.5,0 -7,0.9 -10.2,2.6c-0.6,0.3 -1,1 -1,1.7C0.9,12.4 4.7,19 11,22.9c0.6,0.4 1.4,0.4 2,0c6.3,-3.8 10,-10.5 10.2,-17.8c0,-0.7 -0.4,-1.4 -1,-1.7C19,1.7 15.5,0.8 12,0.8z"/>
<path
android:fillColor="#FF000000"
android:pathData="M21.7,4.2C15.6,1 8.4,1 2.3,4.2C2,4.4 1.8,4.7 1.8,5.1c0.1,7.2 3.9,13.4 9.7,17c0.3,0.2 0.7,0.2 1,0c5.7,-3.5 9.6,-9.8 9.7,-17C22.2,4.7 22,4.4 21.7,4.2zM12,15.8c0,0 -5,-4 -5,-6.6c0,-1.7 1.1,-2.7 2.5,-2.7c1.2,0 2.5,1.3 2.5,1.3s1.2,-1.3 2.5,-1.3c1.4,0 2.5,0.9 2.5,2.7C17,11.8 12,15.8 12,15.8z"/>
</vector>

View file

@ -258,6 +258,8 @@
<string name="sponsor_block_category_self_promo_color_key" translatable="false">sponsor_block_category_self_promo_color</string> <string name="sponsor_block_category_self_promo_color_key" translatable="false">sponsor_block_category_self_promo_color</string>
<string name="sponsor_block_category_non_music_key" translatable="false">sponsor_block_category_music</string> <string name="sponsor_block_category_non_music_key" translatable="false">sponsor_block_category_music</string>
<string name="sponsor_block_category_non_music_color_key" translatable="false">sponsor_block_category_music_color</string> <string name="sponsor_block_category_non_music_color_key" translatable="false">sponsor_block_category_music_color</string>
<string name="sponsor_block_exclusion_list_key" translatable="false">sponsor_block_exclusion_list</string>
<string name="sponsor_block_clear_exclusion_list_key" translatable="false">sponsor_block_clear_exclusion_list</string>
<!-- FileName Downloads --> <!-- FileName Downloads -->
<string name="settings_file_charset_key" translatable="false">file_rename_charset</string> <string name="settings_file_charset_key" translatable="false">file_rename_charset</string>

View file

@ -706,4 +706,6 @@
<string name="sponsor_block_skip_self_promo_message">Skipped unpaid/self promo</string> <string name="sponsor_block_skip_self_promo_message">Skipped unpaid/self promo</string>
<string name="sponsor_block_skip_non_music_message">Skipped non-music</string> <string name="sponsor_block_skip_non_music_message">Skipped non-music</string>
<string name="sponsor_block_toggle_skipping">Toggle skipping sponsors</string> <string name="sponsor_block_toggle_skipping">Toggle skipping sponsors</string>
<string name="sponsor_block_clear_exclusion_list_title">Clear Exclusion List</string>
<string name="sponsor_block_clear_exclusion_list_summary">Clear the list of uploaders excluded from SponsorBlock.</string>
</resources> </resources>

View file

@ -164,5 +164,11 @@
android:title="@string/settings_category_sponsor_block_categories_title" android:title="@string/settings_category_sponsor_block_categories_title"
android:summary="@string/settings_category_sponsor_block_categories_summary"/> android:summary="@string/settings_category_sponsor_block_categories_summary"/>
<Preference
app:iconSpaceReserved="false"
android:key="@string/sponsor_block_clear_exclusion_list_key"
android:summary="@string/sponsor_block_clear_exclusion_list_summary"
android:title="@string/sponsor_block_clear_exclusion_list_title"/>
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>