changed when video segments are queried

this should fix issues with the background/pop-up player and download dialog
This commit is contained in:
polymorphicshade 2021-02-20 23:55:32 -07:00
parent ea39cb868f
commit 8011192dd3
6 changed files with 116 additions and 92 deletions

View file

@ -101,7 +101,6 @@ import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.SponsorBlockUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.VideoSegment;
import java.util.ArrayList;
import java.util.Iterator;
@ -160,8 +159,12 @@ public final class VideoDetailFragment
private boolean showRelatedStreams;
private boolean showDescription;
private String selectedTabTag;
@AttrRes @NonNull final List<Integer> tabIcons = new ArrayList<>();
@StringRes @NonNull final List<Integer> tabContentDescriptions = new ArrayList<>();
@AttrRes
@NonNull
final List<Integer> tabIcons = new ArrayList<>();
@StringRes
@NonNull
final List<Integer> tabContentDescriptions = new ArrayList<>();
private boolean tabSettingsChanged = false;
private int lastAppBarVerticalOffset = Integer.MAX_VALUE; // prevents useless updates
@ -187,12 +190,13 @@ public final class VideoDetailFragment
private final CompositeDisposable disposables = new CompositeDisposable();
@Nullable
private Disposable positionSubscriber = null;
@Nullable
private Disposable videoSegmentsSubscriber = null;
private List<VideoStream> sortedVideoStreams;
private int selectedVideoStreamIndex = -1;
private BottomSheetBehavior<FrameLayout> bottomSheetBehavior;
private BroadcastReceiver broadcastReceiver;
private VideoSegment[] videoSegments;
/*//////////////////////////////////////////////////////////////////////////
// Views
@ -379,6 +383,9 @@ public final class VideoDetailFragment
if (positionSubscriber != null) {
positionSubscriber.dispose();
}
if (videoSegmentsSubscriber != null) {
videoSegmentsSubscriber.dispose();
}
if (currentWorker != null) {
currentWorker.dispose();
}
@ -678,8 +685,8 @@ public final class VideoDetailFragment
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
animate(binding.touchAppendDetail, true, 250, AnimationType.ALPHA,
0, () ->
animate(binding.touchAppendDetail, false, 1500,
AnimationType.ALPHA, 1000));
animate(binding.touchAppendDetail, false, 1500,
AnimationType.ALPHA, 1000));
}
return false;
};
@ -887,43 +894,7 @@ public final class VideoDetailFragment
private void runWorker(final boolean forceLoad, final boolean addToBackStack) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
final String apiUrl = prefs.getString(getContext()
.getString(R.string.sponsor_block_api_url_key), null);
final boolean isSponsorBlockEnabled = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_enable_key), false);
final boolean includeSponsorCategory = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_category_sponsor_key), false);
final boolean includeIntroCategory = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_category_intro_key), false);
final boolean includeOutroCategory = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_category_outro_key), false);
final boolean includeInteractionCategory = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_category_interaction_key), false);
final boolean includeSelfPromoCategory = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_category_self_promo_key), false);
final boolean includeMusicCategory = prefs.getBoolean(getContext()
.getString(R.string.sponsor_block_category_non_music_key), false);
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
.flatMap(streamInfo -> Single.fromCallable(() -> {
if (isSponsorBlockEnabled
&& streamInfo.getUrl().startsWith("https://www.youtube.com")
&& apiUrl != null
&& !apiUrl.isEmpty()) {
this.videoSegments = SponsorBlockUtils.getYouTubeVideoSegments(
apiUrl,
streamInfo.getId(),
includeSponsorCategory,
includeIntroCategory,
includeOutroCategory,
includeInteractionCategory,
includeSelfPromoCategory,
includeMusicCategory);
}
return streamInfo;
}))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
@ -1182,7 +1153,6 @@ public final class VideoDetailFragment
playerService.getView().setVisibility(View.GONE);
}
addVideoPlayerView();
playerService.setVideoSegments(videoSegments);
final Intent playerIntent = NavigationHelper
.getPlayerIntent(requireContext(), MainPlayer.class, queue, true, autoPlayEnabled);
@ -1634,29 +1604,43 @@ public final class VideoDetailFragment
}
public void openDownloadDialog() {
try {
final DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo);
downloadDialog.setVideoStreams(sortedVideoStreams);
downloadDialog.setAudioStreams(currentInfo.getAudioStreams());
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
downloadDialog.setVideoSegments(videoSegments);
videoSegmentsSubscriber = Single.fromCallable(() -> {
try {
return SponsorBlockUtils.getYouTubeVideoSegments(getContext(), currentInfo);
} catch (final Exception e) {
// TODO: handle
return null;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(videoSegments -> {
try {
final DownloadDialog downloadDialog =
DownloadDialog.newInstance(currentInfo);
downloadDialog.setVideoStreams(sortedVideoStreams);
downloadDialog.setAudioStreams(currentInfo.getAudioStreams());
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
downloadDialog.setVideoSegments(videoSegments);
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
} catch (final Exception e) {
final ErrorInfo info = ErrorInfo.make(UserAction.UI_ERROR,
ServiceList.all()
.get(currentInfo
.getServiceId())
.getServiceInfo()
.getName(), "",
R.string.could_not_setup_download_menu);
downloadDialog.show(
activity.getSupportFragmentManager(), "downloadDialog");
} catch (final Exception e) {
final ErrorInfo info = ErrorInfo.make(UserAction.UI_ERROR,
ServiceList.all()
.get(currentInfo
.getServiceId())
.getServiceInfo()
.getName(), "",
R.string.could_not_setup_download_menu);
ErrorActivity.reportError(activity,
e,
activity.getClass(),
activity.findViewById(android.R.id.content), info);
}
ErrorActivity.reportError(activity,
e,
activity.getClass(),
activity.findViewById(android.R.id.content), info);
}
});
}
/*//////////////////////////////////////////////////////////////////////////

View file

@ -37,7 +37,6 @@ import androidx.core.content.ContextCompat;
import org.schabi.newpipe.App;
import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.VideoSegment;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
@ -244,10 +243,6 @@ public final class MainPlayer extends Service {
}
}
public void setVideoSegments(final VideoSegment[] videoSegments) {
player.setVideoSegments(videoSegments);
}
public class LocalBinder extends Binder {

View file

@ -227,6 +227,7 @@ public final class Player implements
public static final String SELECT_ON_APPEND = "select_on_append";
public static final String PLAYER_TYPE = "player_type";
public static final String IS_MUTED = "is_muted";
public static final String VIDEO_SEGMENTS = "video_segments";
/*//////////////////////////////////////////////////////////////////////////
// Time constants
@ -381,7 +382,6 @@ public final class Player implements
/*//////////////////////////////////////////////////////////////////////////
// SponsorBlock
//////////////////////////////////////////////////////////////////////////*/
private VideoSegment[] videoSegments;
private SponsorBlockMode sponsorBlockMode = SponsorBlockMode.DISABLED;
@ -842,7 +842,7 @@ public final class Player implements
}
if (playQueue != null) {
playQueueManager = new MediaSourceManager(this, playQueue);
playQueueManager = new MediaSourceManager(context, this, playQueue);
}
}
@ -4223,13 +4223,6 @@ public final class Player implements
// SponsorBlock
//////////////////////////////////////////////////////////////////////////*/
//region
public VideoSegment[] getVideoSegments() {
return videoSegments;
}
public void setVideoSegments(final VideoSegment[] videoSegments) {
this.videoSegments = videoSegments;
}
public void onBlockingSponsorsButtonClicked() {
if (DEBUG) {
@ -4263,6 +4256,7 @@ public final class Player implements
}
public VideoSegment getSkippableSegment(final int progress) {
final VideoSegment[] videoSegments = currentItem.getVideoSegments();
if (videoSegments == null) {
return null;
}
@ -4285,7 +4279,7 @@ public final class Player implements
private void markSegments() {
binding.playbackSeekBar.clearMarkers();
final VideoSegment[] segments = getVideoSegments();
final VideoSegment[] segments = currentItem.getVideoSegments();
if (segments == null || segments.length == 0) {
return;

View file

@ -1,5 +1,6 @@
package org.schabi.newpipe.player.playback;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
@ -23,6 +24,7 @@ import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent;
import org.schabi.newpipe.player.playqueue.events.RemoveEvent;
import org.schabi.newpipe.player.playqueue.events.ReorderEvent;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.SponsorBlockUtils;
import java.util.Collection;
import java.util.Collections;
@ -69,6 +71,8 @@ public class MediaSourceManager {
*/
private static final int MAXIMUM_LOADER_SIZE = WINDOW_SIZE * 2 + 1;
@NonNull
private final Context context;
@NonNull
private final PlaybackListener playbackListener;
@NonNull
@ -125,14 +129,16 @@ public class MediaSourceManager {
private final Handler removeMediaSourceHandler = new Handler();
public MediaSourceManager(@NonNull final PlaybackListener listener,
public MediaSourceManager(@NonNull final Context context,
@NonNull final PlaybackListener listener,
@NonNull final PlayQueue playQueue) {
this(listener, playQueue, 400L,
this(context, listener, playQueue, 400L,
/*playbackNearEndGapMillis=*/TimeUnit.MILLISECONDS.convert(30, TimeUnit.SECONDS),
/*progressUpdateIntervalMillis*/TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS));
}
private MediaSourceManager(@NonNull final PlaybackListener listener,
private MediaSourceManager(@NonNull final Context context,
@NonNull final PlaybackListener listener,
@NonNull final PlayQueue playQueue,
final long loadDebounceMillis,
final long playbackNearEndGapMillis,
@ -146,6 +152,7 @@ public class MediaSourceManager {
+ " ms] for them to be useful.");
}
this.context = context;
this.playbackListener = listener;
this.playQueue = playQueue;
@ -428,6 +435,9 @@ public class MediaSourceManager {
final long expiration = System.currentTimeMillis()
+ ServiceHelper.getCacheExpirationMillis(streamInfo.getServiceId());
stream.setVideoSegments(SponsorBlockUtils.getYouTubeVideoSegments(context, streamInfo));
return new LoadedMediaSource(source, stream, expiration);
}).onErrorReturn(throwable -> new FailedMediaSource(stream,
new StreamInfoLoadException(throwable)));

View file

@ -7,6 +7,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.VideoSegment;
import java.io.Serializable;
@ -35,6 +36,8 @@ public class PlayQueueItem implements Serializable {
private long recoveryPosition;
private Throwable error;
private VideoSegment[] videoSegments;
PlayQueueItem(@NonNull final StreamInfo info) {
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
info.getThumbnailUrl(), info.getUploaderName(), info.getStreamType());
@ -142,4 +145,12 @@ public class PlayQueueItem implements Serializable {
public void setAutoQueued(final boolean autoQueued) {
isAutoQueued = autoQueued;
}
public VideoSegment[] getVideoSegments() {
return videoSegments;
}
public void setVideoSegments(final VideoSegment[] videoSegments) {
this.videoSegments = videoSegments;
}
}

View file

@ -2,10 +2,13 @@ package org.schabi.newpipe.util;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.preference.PreferenceManager;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
@ -13,6 +16,8 @@ import com.grack.nanojson.JsonParser;
import org.schabi.newpipe.App;
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@ -29,15 +34,40 @@ public final class SponsorBlockUtils {
}
@SuppressWarnings("CheckStyle")
public static VideoSegment[] getYouTubeVideoSegments(final String apiUrl,
final String videoId,
final boolean includeSponsorCategory,
final boolean includeIntroCategory,
final boolean includeOutroCategory,
final boolean includeInteractionCategory,
final boolean includeSelfPromoCategory,
final boolean includeMusicCategory)
public static VideoSegment[] getYouTubeVideoSegments(final Context context,
final StreamInfo streamInfo)
throws UnsupportedEncodingException {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
final boolean isSponsorBlockEnabled = prefs.getBoolean(context
.getString(R.string.sponsor_block_enable_key), false);
if (!isSponsorBlockEnabled) {
return null;
}
final String apiUrl = prefs.getString(context
.getString(R.string.sponsor_block_api_url_key), null);
if (!streamInfo.getUrl().startsWith("https://www.youtube.com")
|| apiUrl == null
|| apiUrl.isEmpty()) {
return null;
}
final boolean includeSponsorCategory = prefs.getBoolean(context
.getString(R.string.sponsor_block_category_sponsor_key), false);
final boolean includeIntroCategory = prefs.getBoolean(context
.getString(R.string.sponsor_block_category_intro_key), false);
final boolean includeOutroCategory = prefs.getBoolean(context
.getString(R.string.sponsor_block_category_outro_key), false);
final boolean includeInteractionCategory = prefs.getBoolean(context
.getString(R.string.sponsor_block_category_interaction_key), false);
final boolean includeSelfPromoCategory = prefs.getBoolean(context
.getString(R.string.sponsor_block_category_self_promo_key), false);
final boolean includeMusicCategory = prefs.getBoolean(context
.getString(R.string.sponsor_block_category_non_music_key), false);
final ArrayList<String> categoryParamList = new ArrayList<>();
if (includeSponsorCategory) {
@ -66,7 +96,7 @@ public final class SponsorBlockUtils {
String categoryParams = "[\"" + TextUtils.join("\",\"", categoryParamList) + "\"]";
categoryParams = URLEncoder.encode(categoryParams, "utf-8");
final String videoIdHash = toSha256(videoId);
final String videoIdHash = toSha256(streamInfo.getId());
if (videoIdHash == null) {
return null;
@ -106,7 +136,7 @@ public final class SponsorBlockUtils {
final JsonObject jObj1 = (JsonObject) obj1;
final String responseVideoId = jObj1.getString("videoID");
if (!responseVideoId.equals(videoId)) {
if (!responseVideoId.equals(streamInfo.getId())) {
continue;
}