Merge branch 'TeamNewPipe:dev' into feature-7870

This commit is contained in:
GGAutomaton 2022-04-13 22:48:26 +08:00 committed by GitHub
commit 813f55152a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 30 deletions

View file

@ -68,7 +68,7 @@ The [checkStyle](https://github.com/checkstyle/checkstyle) plugin verifies that
- Go to `File -> Settings -> Plugins`, search for `checkstyle` and install `CheckStyle-IDEA`. - Go to `File -> Settings -> Plugins`, search for `checkstyle` and install `CheckStyle-IDEA`.
- Go to `File -> Settings -> Tools -> Checkstyle`. - Go to `File -> Settings -> Tools -> Checkstyle`.
- Add NewPipe's configuration file by clicking the `+` in the right toolbar of the "Configuration File" list. - Add NewPipe's configuration file by clicking the `+` in the right toolbar of the "Configuration File" list.
- Under the "Use a local Checkstyle file" bullet, click on `Browse` and pick the file named `checkstyle.xml` in the project's root folder. - Under the "Use a local Checkstyle file" bullet, click on `Browse` and, enter `checkstyle` folder under the project's root path and pick the file named `checkstyle.xml`.
- Enable "Store relative to project location" so that moving the directory around does not create issues. - Enable "Store relative to project location" so that moving the directory around does not create issues.
- Insert a description in the top bar, then click `Next` and then `Finish`. - Insert a description in the top bar, then click `Next` and then `Finish`.
- Activate the configuration file you just added by enabling the checkbox on the left. - Activate the configuration file you just added by enabling the checkbox on the left.

View file

@ -33,8 +33,16 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
private final CompositeDisposable playlistDisposables = new CompositeDisposable(); private final CompositeDisposable playlistDisposables = new CompositeDisposable();
public PlaylistAppendDialog(final List<StreamEntity> streamEntities) { /**
super(streamEntities); * Create a new instance of {@link PlaylistAppendDialog}.
*
* @param streamEntities a list of {@link StreamEntity} to be added to playlists
* @return a new instance of {@link PlaylistAppendDialog}
*/
public static PlaylistAppendDialog newInstance(final List<StreamEntity> streamEntities) {
final PlaylistAppendDialog dialog = new PlaylistAppendDialog();
dialog.setStreamEntities(streamEntities);
return dialog;
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -103,13 +111,14 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
// Helper // Helper
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
/** Display create playlist dialog. */
public void openCreatePlaylistDialog() { public void openCreatePlaylistDialog() {
if (getStreamEntities() == null || !isAdded()) { if (getStreamEntities() == null || !isAdded()) {
return; return;
} }
final PlaylistCreationDialog playlistCreationDialog = final PlaylistCreationDialog playlistCreationDialog =
new PlaylistCreationDialog(getStreamEntities()); PlaylistCreationDialog.newInstance(getStreamEntities());
// Move the dismissListener to the new dialog. // Move the dismissListener to the new dialog.
playlistCreationDialog.setOnDismissListener(this.getOnDismissListener()); playlistCreationDialog.setOnDismissListener(this.getOnDismissListener());
this.setOnDismissListener(null); this.setOnDismissListener(null);

View file

@ -21,8 +21,17 @@ import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
public final class PlaylistCreationDialog extends PlaylistDialog { public final class PlaylistCreationDialog extends PlaylistDialog {
public PlaylistCreationDialog(final List<StreamEntity> streamEntities) {
super(streamEntities); /**
* Create a new instance of {@link PlaylistCreationDialog}.
*
* @param streamEntities a list of {@link StreamEntity} to be added to playlists
* @return a new instance of {@link PlaylistCreationDialog}
*/
public static PlaylistCreationDialog newInstance(final List<StreamEntity> streamEntities) {
final PlaylistCreationDialog dialog = new PlaylistCreationDialog();
dialog.setStreamEntities(streamEntities);
return dialog;
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View file

@ -31,10 +31,6 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
private org.schabi.newpipe.util.SavedState savedState; private org.schabi.newpipe.util.SavedState savedState;
public PlaylistDialog(final List<StreamEntity> streamEntities) {
this.streamEntities = streamEntities;
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// LifeCycle // LifeCycle
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -120,6 +116,10 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
this.onDismissListener = onDismissListener; this.onDismissListener = onDismissListener;
} }
protected void setStreamEntities(final List<StreamEntity> streamEntities) {
this.streamEntities = streamEntities;
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Dialog creation // Dialog creation
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -143,8 +143,8 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(hasPlaylists -> .subscribe(hasPlaylists ->
onExec.accept(hasPlaylists onExec.accept(hasPlaylists
? new PlaylistAppendDialog(streamEntities) ? PlaylistAppendDialog.newInstance(streamEntities)
: new PlaylistCreationDialog(streamEntities)) : PlaylistCreationDialog.newInstance(streamEntities))
); );
} }
} }

View file

@ -116,6 +116,7 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.AppCompatImageButton; import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.PopupMenu;
import androidx.collection.ArraySet;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets; import androidx.core.graphics.Insets;
import androidx.core.view.GestureDetectorCompat; import androidx.core.view.GestureDetectorCompat;
@ -4217,21 +4218,21 @@ public final class Player implements
// in livestreams) so we will be not able to execute the block below. // in livestreams) so we will be not able to execute the block below.
// Reload the play queue manager in this case, which is the behavior when we don't know the // Reload the play queue manager in this case, which is the behavior when we don't know the
// index of the video renderer or playQueueManagerReloadingNeeded returns true. // index of the video renderer or playQueueManagerReloadingNeeded returns true.
if (!getCurrentStreamInfo().isPresent()) { final Optional<StreamInfo> optCurrentStreamInfo = getCurrentStreamInfo();
if (!optCurrentStreamInfo.isPresent()) {
reloadPlayQueueManager(); reloadPlayQueueManager();
setRecovery(); setRecovery();
return; return;
} }
final int videoRenderIndex = getVideoRendererIndex(); final StreamInfo info = optCurrentStreamInfo.get();
final StreamInfo info = getCurrentStreamInfo().get();
// In the case we don't know the source type, fallback to the one with video with audio or // In the case we don't know the source type, fallback to the one with video with audio or
// audio-only source. // audio-only source.
final SourceType sourceType = videoResolver.getStreamSourceType().orElse( final SourceType sourceType = videoResolver.getStreamSourceType().orElse(
SourceType.VIDEO_WITH_AUDIO_OR_AUDIO_ONLY); SourceType.VIDEO_WITH_AUDIO_OR_AUDIO_ONLY);
if (playQueueManagerReloadingNeeded(sourceType, info, videoRenderIndex)) { if (playQueueManagerReloadingNeeded(sourceType, info, getVideoRendererIndex())) {
reloadPlayQueueManager(); reloadPlayQueueManager();
} else { } else {
final StreamType streamType = info.getStreamType(); final StreamType streamType = info.getStreamType();
@ -4242,19 +4243,22 @@ public final class Player implements
return; return;
} }
final TrackGroupArray videoTrackGroupArray = Objects.requireNonNull( final DefaultTrackSelector.ParametersBuilder parametersBuilder =
trackSelector.getCurrentMappedTrackInfo()).getTrackGroups(videoRenderIndex); trackSelector.buildUponParameters();
if (videoEnabled) { if (videoEnabled) {
// Clearing the null selection override enable again the video stream (and its // Enable again the video track and the subtitles, if there is one selected
// fetching). parametersBuilder.setDisabledTrackTypes(Collections.emptySet());
trackSelector.setParameters(trackSelector.buildUponParameters()
.clearSelectionOverride(videoRenderIndex, videoTrackGroupArray));
} else { } else {
// Using setRendererDisabled still fetch the video stream in background, contrary // Disable the video track and the ability to select subtitles
// to setSelectionOverride with a null override. // Use an ArraySet because we can't use Set.of() on all supported APIs by the app
trackSelector.setParameters(trackSelector.buildUponParameters() final ArraySet<Integer> disabledTracks = new ArraySet<>();
.setSelectionOverride(videoRenderIndex, videoTrackGroupArray, null)); disabledTracks.add(C.TRACK_TYPE_TEXT);
disabledTracks.add(C.TRACK_TYPE_VIDEO);
parametersBuilder.setDisabledTrackTypes(disabledTracks);
} }
trackSelector.setParameters(parametersBuilder);
} }
setRecovery(); setRecovery();

View file

@ -54,6 +54,7 @@ public final class SparseItemUtil {
// if the duration is >= 0 (provided that the item is not a livestream) and there is an // if the duration is >= 0 (provided that the item is not a livestream) and there is an
// uploader url, probably all info is already there, so there is no need to fetch it // uploader url, probably all info is already there, so there is no need to fetch it
callback.accept(new SinglePlayQueue(item)); callback.accept(new SinglePlayQueue(item));
return;
} }
// either the duration or the uploader url are not available, so fetch more info // either the duration or the uploader url are not available, so fetch more info
@ -80,12 +81,12 @@ public final class SparseItemUtil {
@NonNull final String url, @NonNull final String url,
@Nullable final String uploaderUrl, @Nullable final String uploaderUrl,
@NonNull final Consumer<String> callback) { @NonNull final Consumer<String> callback) {
if (isNullOrEmpty(uploaderUrl)) { if (!isNullOrEmpty(uploaderUrl)) {
fetchStreamInfoAndSaveToDatabase(context, serviceId, url,
streamInfo -> callback.accept(streamInfo.getUploaderUrl()));
} else {
callback.accept(uploaderUrl); callback.accept(uploaderUrl);
return;
} }
fetchStreamInfoAndSaveToDatabase(context, serviceId, url,
streamInfo -> callback.accept(streamInfo.getUploaderUrl()));
} }
/** /**