Skip to content

Commit 036196a

Browse files
committed
Filter streams using Java 8 Stream's API instead of removing streams with list iterators and add a better toast when there is no audio stream for external players
This ensures to not remove streams from the StreamInfo lists themselves, and so to not have to create list copies. The toast shown in RouterActivity, when there is no audio stream available for external players, is now shown, in the same case, when pressing the background button in VideoDetailFragment.
1 parent 73855ca commit 036196a

6 files changed

Lines changed: 123 additions & 132 deletions

File tree

app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969

7070
import java.io.File;
7171
import java.io.IOException;
72-
import java.util.ArrayList;
7372
import java.util.List;
7473
import java.util.Locale;
7574
import java.util.Objects;
@@ -84,7 +83,7 @@
8483
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
8584
import us.shandian.giga.service.MissionState;
8685

87-
import static org.schabi.newpipe.util.ListHelper.keepStreamsWithDelivery;
86+
import static org.schabi.newpipe.util.ListHelper.getStreamsOfSpecifiedDelivery;
8887
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
8988

9089
public class DownloadDialog extends DialogFragment
@@ -149,25 +148,24 @@ public class DownloadDialog extends DialogFragment
149148
public static DownloadDialog newInstance(final Context context,
150149
@NonNull final StreamInfo info) {
151150
// TODO: Adapt this code when the downloader support other types of stream deliveries
152-
final List<VideoStream> videoStreams = new ArrayList<>(info.getVideoStreams());
153151
final List<VideoStream> progressiveHttpVideoStreams =
154-
keepStreamsWithDelivery(videoStreams, DeliveryMethod.PROGRESSIVE_HTTP);
152+
getStreamsOfSpecifiedDelivery(info.getVideoStreams(),
153+
DeliveryMethod.PROGRESSIVE_HTTP);
155154

156-
final List<VideoStream> videoOnlyStreams = new ArrayList<>(info.getVideoOnlyStreams());
157155
final List<VideoStream> progressiveHttpVideoOnlyStreams =
158-
keepStreamsWithDelivery(videoOnlyStreams, DeliveryMethod.PROGRESSIVE_HTTP);
156+
getStreamsOfSpecifiedDelivery(info.getVideoOnlyStreams(),
157+
DeliveryMethod.PROGRESSIVE_HTTP);
159158

160-
final List<AudioStream> audioStreams = new ArrayList<>(info.getAudioStreams());
161159
final List<AudioStream> progressiveHttpAudioStreams =
162-
keepStreamsWithDelivery(audioStreams, DeliveryMethod.PROGRESSIVE_HTTP);
160+
getStreamsOfSpecifiedDelivery(info.getAudioStreams(),
161+
DeliveryMethod.PROGRESSIVE_HTTP);
163162

164-
final List<SubtitlesStream> subtitlesStreams = new ArrayList<>(info.getSubtitles());
165163
final List<SubtitlesStream> progressiveHttpSubtitlesStreams =
166-
keepStreamsWithDelivery(subtitlesStreams, DeliveryMethod.PROGRESSIVE_HTTP);
164+
getStreamsOfSpecifiedDelivery(info.getSubtitles(),
165+
DeliveryMethod.PROGRESSIVE_HTTP);
167166

168-
final List<VideoStream> videoStreamsList = new ArrayList<>(
169-
ListHelper.getSortedStreamVideosList(context, progressiveHttpVideoStreams,
170-
progressiveHttpVideoOnlyStreams, false, false));
167+
final List<VideoStream> videoStreamsList = ListHelper.getSortedStreamVideosList(context,
168+
progressiveHttpVideoStreams, progressiveHttpVideoOnlyStreams, false, false);
171169

172170
final DownloadDialog instance = new DownloadDialog();
173171
instance.setInfo(info);

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import android.view.animation.DecelerateInterpolator;
3232
import android.widget.FrameLayout;
3333
import android.widget.RelativeLayout;
34+
import android.widget.Toast;
3435

3536
import androidx.annotation.AttrRes;
3637
import androidx.annotation.NonNull;
@@ -122,7 +123,7 @@
122123
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
123124
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
124125
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
125-
import static org.schabi.newpipe.util.ListHelper.removeNonUrlAndTorrentStreams;
126+
import static org.schabi.newpipe.util.ListHelper.getNonUrlAndNonTorrentStreams;
126127

127128
public final class VideoDetailFragment
128129
extends BaseStateFragment<StreamInfo>
@@ -1092,9 +1093,6 @@ private void toggleFullscreenIfInFullscreenMode() {
10921093
}
10931094

10941095
private void openBackgroundPlayer(final boolean append) {
1095-
final AudioStream audioStream = currentInfo.getAudioStreams()
1096-
.get(ListHelper.getDefaultAudioFormat(activity, currentInfo.getAudioStreams()));
1097-
10981096
final boolean useExternalAudioPlayer = PreferenceManager
10991097
.getDefaultSharedPreferences(activity)
11001098
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
@@ -1109,7 +1107,17 @@ private void openBackgroundPlayer(final boolean append) {
11091107
if (!useExternalAudioPlayer) {
11101108
openNormalBackgroundPlayer(append);
11111109
} else {
1112-
startOnExternalPlayer(activity, currentInfo, audioStream);
1110+
final List<AudioStream> audioStreams = getNonUrlAndNonTorrentStreams(
1111+
currentInfo.getAudioStreams());
1112+
final int index = ListHelper.getDefaultAudioFormat(activity, audioStreams);
1113+
1114+
if (index == -1) {
1115+
Toast.makeText(activity, R.string.no_audio_streams_available_for_external_players,
1116+
Toast.LENGTH_SHORT).show();
1117+
return;
1118+
}
1119+
1120+
startOnExternalPlayer(activity, currentInfo, audioStreams.get(index));
11131121
}
11141122
}
11151123

@@ -2147,10 +2155,10 @@ private void showExternalPlaybackDialog() {
21472155
return;
21482156
}
21492157

2150-
final List<VideoStream> videoStreams = removeNonUrlAndTorrentStreams(
2151-
new ArrayList<>(currentInfo.getVideoStreams()));
2152-
final List<VideoStream> videoOnlyStreams = removeNonUrlAndTorrentStreams(
2153-
new ArrayList<>(currentInfo.getVideoOnlyStreams()));
2158+
final List<VideoStream> videoStreams = getNonUrlAndNonTorrentStreams(
2159+
currentInfo.getVideoStreams());
2160+
final List<VideoStream> videoOnlyStreams = getNonUrlAndNonTorrentStreams(
2161+
currentInfo.getVideoOnlyStreams());
21542162

21552163
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
21562164
builder.setTitle(R.string.select_quality_external_players);

app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.schabi.newpipe.player.resolver;
22

3-
import static org.schabi.newpipe.util.ListHelper.removeTorrentStreams;
3+
import static org.schabi.newpipe.util.ListHelper.getNonTorrentStreams;
44

55
import android.content.Context;
66
import android.util.Log;
@@ -18,7 +18,6 @@
1818
import org.schabi.newpipe.util.ListHelper;
1919

2020
import java.io.IOException;
21-
import java.util.ArrayList;
2221
import java.util.List;
2322

2423
public class AudioPlaybackResolver implements PlaybackResolver {
@@ -43,8 +42,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
4342
return liveSource;
4443
}
4544

46-
final List<AudioStream> audioStreams = new ArrayList<>(info.getAudioStreams());
47-
removeTorrentStreams(audioStreams);
45+
final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams());
4846

4947
final int index = ListHelper.getDefaultAudioFormat(context, audioStreams);
5048
if (index < 0 || index >= info.getAudioStreams().size()) {

app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
import java.util.Optional;
3030

3131
import static com.google.android.exoplayer2.C.TIME_UNSET;
32-
import static org.schabi.newpipe.util.ListHelper.removeNonUrlAndTorrentStreams;
33-
import static org.schabi.newpipe.util.ListHelper.removeTorrentStreams;
32+
import static org.schabi.newpipe.util.ListHelper.getNonUrlAndNonTorrentStreams;
33+
import static org.schabi.newpipe.util.ListHelper.getNonTorrentStreams;
3434

3535
public class VideoPlaybackResolver implements PlaybackResolver {
3636
private static final String TAG = VideoPlaybackResolver.class.getSimpleName();
@@ -70,24 +70,21 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
7070
}
7171

7272
final List<MediaSource> mediaSources = new ArrayList<>();
73-
final List<VideoStream> videoStreams = new ArrayList<>(info.getVideoStreams());
74-
final List<VideoStream> videoOnlyStreams = new ArrayList<>(info.getVideoOnlyStreams());
75-
76-
removeTorrentStreams(videoStreams);
77-
removeTorrentStreams(videoOnlyStreams);
7873

7974
// Create video stream source
80-
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context,
81-
videoStreams, videoOnlyStreams, false, true);
75+
final List<VideoStream> videoStreamsList = ListHelper.getSortedStreamVideosList(context,
76+
getNonTorrentStreams(info.getVideoStreams()),
77+
getNonTorrentStreams(info.getVideoOnlyStreams()), false, true);
8278
final int index;
83-
if (videos.isEmpty()) {
79+
if (videoStreamsList.isEmpty()) {
8480
index = -1;
8581
} else if (playbackQuality == null) {
86-
index = qualityResolver.getDefaultResolutionIndex(videos);
82+
index = qualityResolver.getDefaultResolutionIndex(videoStreamsList);
8783
} else {
88-
index = qualityResolver.getOverrideResolutionIndex(videos, getPlaybackQuality());
84+
index = qualityResolver.getOverrideResolutionIndex(videoStreamsList,
85+
getPlaybackQuality());
8986
}
90-
final MediaItemTag tag = StreamInfoTag.of(info, videos, index);
87+
final MediaItemTag tag = StreamInfoTag.of(info, videoStreamsList, index);
9188
@Nullable final VideoStream video = tag.getMaybeQuality()
9289
.map(MediaItemTag.Quality::getSelectedVideoStream)
9390
.orElse(null);
@@ -104,8 +101,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
104101
}
105102

106103
// Create optional audio stream source
107-
final List<AudioStream> audioStreams = info.getAudioStreams();
108-
removeTorrentStreams(audioStreams);
104+
final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams());
109105
final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get(
110106
ListHelper.getDefaultAudioFormat(context, audioStreams));
111107

@@ -129,13 +125,14 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
129125
if (mediaSources.isEmpty()) {
130126
return null;
131127
}
128+
132129
// Below are auxiliary media sources
133130

134131
// Create subtitle sources
135132
final List<SubtitlesStream> subtitlesStreams = info.getSubtitles();
136133
if (subtitlesStreams != null) {
137134
// Torrent and non URL subtitles are not supported by ExoPlayer
138-
final List<SubtitlesStream> nonTorrentAndUrlStreams = removeNonUrlAndTorrentStreams(
135+
final List<SubtitlesStream> nonTorrentAndUrlStreams = getNonUrlAndNonTorrentStreams(
139136
subtitlesStreams);
140137
for (final SubtitlesStream subtitle : nonTorrentAndUrlStreams) {
141138
final MediaFormat mediaFormat = subtitle.getFormat();

app/src/main/java/org/schabi/newpipe/util/ListHelper.java

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
import java.util.Comparator;
2424
import java.util.HashMap;
2525
import java.util.HashSet;
26-
import java.util.Iterator;
2726
import java.util.List;
2827
import java.util.Objects;
2928
import java.util.Set;
29+
import java.util.function.Predicate;
3030
import java.util.stream.Collectors;
3131

3232
public final class ListHelper {
@@ -116,27 +116,17 @@ public static int getDefaultAudioFormat(final Context context,
116116
* Return a {@link Stream} list which uses the given delivery method from a {@link Stream}
117117
* list.
118118
*
119-
* @param streamList the original stream list
120-
* @param deliveryMethod the delivery method
119+
* @param streamList the original {@link Stream stream} list
120+
* @param deliveryMethod the {@link DeliveryMethod delivery method}
121121
* @param <S> the item type's class that extends {@link Stream}
122-
* @return a stream list which uses the given delivery method
122+
* @return a {@link Stream stream} list which uses the given delivery method
123123
*/
124124
@NonNull
125-
public static <S extends Stream> List<S> keepStreamsWithDelivery(
126-
@NonNull final List<S> streamList,
125+
public static <S extends Stream> List<S> getStreamsOfSpecifiedDelivery(
126+
final List<S> streamList,
127127
final DeliveryMethod deliveryMethod) {
128-
if (streamList.isEmpty()) {
129-
return Collections.emptyList();
130-
}
131-
132-
final Iterator<S> streamListIterator = streamList.iterator();
133-
while (streamListIterator.hasNext()) {
134-
if (streamListIterator.next().getDeliveryMethod() != deliveryMethod) {
135-
streamListIterator.remove();
136-
}
137-
}
138-
139-
return streamList;
128+
return getFilteredStreamList(streamList,
129+
stream -> stream.getDeliveryMethod() == deliveryMethod);
140130
}
141131

142132
/**
@@ -147,21 +137,10 @@ public static <S extends Stream> List<S> keepStreamsWithDelivery(
147137
* @return a stream list which only contains URL streams and non-torrent streams
148138
*/
149139
@NonNull
150-
public static <S extends Stream> List<S> removeNonUrlAndTorrentStreams(
151-
@NonNull final List<S> streamList) {
152-
if (streamList.isEmpty()) {
153-
return Collections.emptyList();
154-
}
155-
156-
final Iterator<S> streamListIterator = streamList.iterator();
157-
while (streamListIterator.hasNext()) {
158-
final S stream = streamListIterator.next();
159-
if (!stream.isUrl() || stream.getDeliveryMethod() == DeliveryMethod.TORRENT) {
160-
streamListIterator.remove();
161-
}
162-
}
163-
164-
return streamList;
140+
public static <S extends Stream> List<S> getNonUrlAndNonTorrentStreams(
141+
final List<S> streamList) {
142+
return getFilteredStreamList(streamList,
143+
stream -> stream.isUrl() && stream.getDeliveryMethod() != DeliveryMethod.TORRENT);
165144
}
166145

167146
/**
@@ -172,21 +151,10 @@ public static <S extends Stream> List<S> removeNonUrlAndTorrentStreams(
172151
* @return a stream list which only contains non-torrent streams
173152
*/
174153
@NonNull
175-
public static <S extends Stream> List<S> removeTorrentStreams(
176-
@NonNull final List<S> streamList) {
177-
if (streamList.isEmpty()) {
178-
return Collections.emptyList();
179-
}
180-
181-
final Iterator<S> streamListIterator = streamList.iterator();
182-
while (streamListIterator.hasNext()) {
183-
final S stream = streamListIterator.next();
184-
if (stream.getDeliveryMethod() == DeliveryMethod.TORRENT) {
185-
streamListIterator.remove();
186-
}
187-
}
188-
189-
return streamList;
154+
public static <S extends Stream> List<S> getNonTorrentStreams(
155+
final List<S> streamList) {
156+
return getFilteredStreamList(streamList,
157+
stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT);
190158
}
191159

192160
/**
@@ -224,6 +192,26 @@ public static List<VideoStream> getSortedStreamVideosList(
224192
// Utils
225193
//////////////////////////////////////////////////////////////////////////*/
226194

195+
/**
196+
* Get a filtered stream list, by using Java 8 Stream's API and the given predicate.
197+
*
198+
* @param streamList the stream list to filter
199+
* @param streamListPredicate the predicate which will be used to filter streams
200+
* @param <S> the item type's class that extends {@link Stream}
201+
* @return a new stream list filtered using the given predicate
202+
*/
203+
private static <S extends Stream> List<S> getFilteredStreamList(
204+
final List<S> streamList,
205+
final Predicate<S> streamListPredicate) {
206+
if (streamList == null) {
207+
return Collections.emptyList();
208+
}
209+
210+
return streamList.stream()
211+
.filter(streamListPredicate)
212+
.collect(Collectors.toList());
213+
}
214+
227215
private static String computeDefaultResolution(final Context context, final int key,
228216
final int value) {
229217
final SharedPreferences preferences

0 commit comments

Comments
 (0)