Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ dependencies {
exclude module: 'support-annotations'
}

implementation 'com.github.TeamNewPipe:NewPipeExtractor:bda83fe6a5b9a8a0751669fbc444fa49d72d0d2f'
implementation 'com.github.mauriciocolli:NewPipeExtractor:c234a6d2bdce228ed3a9e84952e7389afca13fa8'

implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
implementation "org.jsoup:jsoup:1.13.1"
Expand Down
17 changes: 14 additions & 3 deletions app/src/main/java/org/schabi/newpipe/RouterActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,15 @@ private void handleChoice(final String selectedChoiceKey) {
finish();
}

private Disposable downloadDisposable;

@SuppressLint("CheckResult")
private void openDownloadDialog() {
ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, true)
if (downloadDisposable != null) {
return;
}

downloadDisposable = ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, true)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((@NonNull StreamInfo result) -> {
Expand All @@ -492,9 +498,14 @@ private void openDownloadDialog() {
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
downloadDialog.show(fm, "downloadDialog");
fm.executePendingTransactions();
downloadDialog.getDialog().setOnDismissListener(dialog -> {
// TODO: Improve this dialog dismiss logic
if (downloadDialog.getDialog() != null) {
downloadDialog.getDialog().setOnDismissListener(dialog -> {
finish();
});
} else {
finish();
});
}
}, (@NonNull Throwable throwable) -> {
onError();
});
Expand Down
78 changes: 66 additions & 12 deletions app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.localization.Localization;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
Expand All @@ -64,6 +65,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

Expand Down Expand Up @@ -149,15 +151,59 @@ private void setInfo(final StreamInfo info) {
}

public void setAudioStreams(final List<AudioStream> audioStreams) {
setAudioStreams(new StreamSizeWrapper<>(audioStreams, getContext()));
// TODO: Remove this when the downloader support other types of stream deliveries
final List<AudioStream> listAudioStreams = new ArrayList<>(audioStreams);
wasSomeStreamRemoved = removeNotDirectStreams(listAudioStreams) || wasSomeStreamRemoved;

setAudioStreams(new StreamSizeWrapper<>(listAudioStreams, getContext()));
}

public void setAudioStreams(final StreamSizeWrapper<AudioStream> was) {
this.wrappedAudioStreams = was;
}

public void setVideoStreams(final List<VideoStream> videoStreams) {
setVideoStreams(new StreamSizeWrapper<>(videoStreams, getContext()));
// TODO: Remove this when the downloader support other types of stream deliveries
final List<VideoStream> listVideoStreams = new ArrayList<>(videoStreams);
wasSomeStreamRemoved = removeNotDirectStreams(listVideoStreams) || wasSomeStreamRemoved;

setVideoStreams(new StreamSizeWrapper<>(listVideoStreams, getContext()));
}

public void setSubtitleStreams(final List<SubtitlesStream> subtitleStreams) {
// TODO: Remove this when the downloader support other types of stream deliveries
final List<SubtitlesStream> listSubtitleStreams = new ArrayList<>(subtitleStreams);
wasSomeStreamRemoved = removeNotDirectStreams(listSubtitleStreams) || wasSomeStreamRemoved;

setSubtitleStreams(new StreamSizeWrapper<>(listSubtitleStreams, getContext()));
}

private Toast removedStreamToast = null;
boolean wasSomeStreamRemoved = false;

private void showIfStreamsWereRemovedMessage() {
if (wasSomeStreamRemoved && removedStreamToast == null) {
removedStreamToast = Toast.makeText(
requireContext(),
R.string.streams_hidden_download_not_supported_yet,
Toast.LENGTH_LONG
);
removedStreamToast.show();
}
}

private static boolean removeNotDirectStreams(final List<? extends Stream> streamList) {
boolean wasSomeStreamRemoved = false;
final Iterator<? extends Stream> streamIterator = streamList.iterator();
while (streamIterator.hasNext()) {
final Stream stream = streamIterator.next();
if (!(stream.getDeliveryFormat() instanceof DeliveryFormat.Direct)) {
streamIterator.remove();
wasSomeStreamRemoved = true;
}
}

return wasSomeStreamRemoved;
}

/*//////////////////////////////////////////////////////////////////////////
Expand All @@ -168,10 +214,6 @@ public void setVideoStreams(final StreamSizeWrapper<VideoStream> wvs) {
this.wrappedVideoStreams = wvs;
}

public void setSubtitleStreams(final List<SubtitlesStream> subtitleStreams) {
setSubtitleStreams(new StreamSizeWrapper<>(subtitleStreams, getContext()));
}

public void setSubtitleStreams(
final StreamSizeWrapper<SubtitlesStream> wss) {
this.wrappedSubtitleStreams = wss;
Expand Down Expand Up @@ -199,11 +241,12 @@ public void onCreate(@Nullable final Bundle savedInstanceState) {

if (!PermissionHelper.checkStoragePermissions(getActivity(),
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
getDialog().dismiss();
dismiss();
return;
}

context = getContext();
showIfStreamsWereRemovedMessage();

setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
Icepick.restoreInstanceState(this, savedInstanceState);
Expand Down Expand Up @@ -277,8 +320,10 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
super.onViewCreated(view, savedInstanceState);
nameEditText = view.findViewById(R.id.file_name);
nameEditText.setText(FilenameUtils.createFilename(getContext(), currentInfo.getName()));
selectedAudioIndex = ListHelper
.getDefaultAudioFormat(getContext(), currentInfo.getAudioStreams());
selectedAudioIndex = ListHelper.getDefaultAudioFormat(getContext(),
wrappedAudioStreams.getStreamsList());
final int videoStreamListSize = wrappedVideoStreams.getStreamsList().size();
selectedVideoIndex = Math.max(0, Math.min(selectedVideoIndex, videoStreamListSize - 1));

selectedSubtitleIndex = getSubtitleIndexBy(subtitleStreamsAdapter.getAll());

Expand Down Expand Up @@ -527,7 +572,7 @@ protected void setupDownloadOptions() {
} else {
Toast.makeText(getContext(), R.string.no_streams_available_download,
Toast.LENGTH_SHORT).show();
getDialog().dismiss();
dismiss();
}
}

Expand Down Expand Up @@ -898,16 +943,25 @@ private void continueSelectedDownload(@NonNull final StoredFileHelper storage) {
return;
}

if (!(selectedStream.getDeliveryFormat() instanceof DeliveryFormat.Direct)) {
throw new IllegalArgumentException("Unsupported stream delivery format");
}

if (secondaryStream == null) {
urls = new String[]{
selectedStream.getUrl()
((DeliveryFormat.Direct) selectedStream.getDeliveryFormat()).getUrl()
};
recoveryInfo = new MissionRecoveryInfo[]{
new MissionRecoveryInfo(selectedStream)
};
} else {
if (!(secondaryStream.getDeliveryFormat() instanceof DeliveryFormat.Direct)) {
throw new IllegalArgumentException("Unsupported stream delivery format");
}

urls = new String[]{
selectedStream.getUrl(), secondaryStream.getUrl()
((DeliveryFormat.Direct) selectedStream.getDeliveryFormat()).getUrl(),
((DeliveryFormat.Direct) secondaryStream.getDeliveryFormat()).getUrl()
};
recoveryInfo = new MissionRecoveryInfo[]{new MissionRecoveryInfo(selectedStream),
new MissionRecoveryInfo(secondaryStream)};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {

final AudioStream audio = info.getAudioStreams().get(index);
final MediaSourceTag tag = new MediaSourceTag(info);
return buildMediaSource(dataSource, audio.getUrl(), PlayerHelper.cacheKeyOf(info, audio),
return buildMediaSource(dataSource, audio, PlayerHelper.cacheKeyOf(info, audio),
MediaFormat.getSuffixById(audio.getFormatId()), tag);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package org.schabi.newpipe.player.resolver;

import android.net.Uri;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;

import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.player.helper.PlayerDataSource;

import java.io.ByteArrayInputStream;
import java.io.IOException;

public interface PlaybackResolver extends Resolver<StreamInfo, MediaSource> {

@Nullable
Expand Down Expand Up @@ -57,29 +62,39 @@ default MediaSource buildLiveMediaSource(@NonNull final PlayerDataSource dataSou

@NonNull
default MediaSource buildMediaSource(@NonNull final PlayerDataSource dataSource,
@NonNull final String sourceUrl,
@NonNull final Stream sourceStream,
@NonNull final String cacheKey,
@NonNull final String overrideExtension,
@NonNull final MediaSourceTag metadata) {
final Uri uri = Uri.parse(sourceUrl);
@C.ContentType final int type = TextUtils.isEmpty(overrideExtension)
? Util.inferContentType(uri) : Util.inferContentType("." + overrideExtension);
final DeliveryFormat deliveryFormat = sourceStream.getDeliveryFormat();
if (deliveryFormat instanceof DeliveryFormat.Direct) {
final String url = ((DeliveryFormat.Direct) deliveryFormat).getUrl();
return dataSource.getExtractorMediaSourceFactory(cacheKey).setTag(metadata)
.createMediaSource(Uri.parse(url));

switch (type) {
case C.TYPE_SS:
return dataSource.getLiveSsMediaSourceFactory().setTag(metadata)
.createMediaSource(uri);
case C.TYPE_DASH:
return dataSource.getDashMediaSourceFactory().setTag(metadata)
.createMediaSource(uri);
case C.TYPE_HLS:
return dataSource.getHlsMediaSourceFactory().setTag(metadata)
.createMediaSource(uri);
case C.TYPE_OTHER:
return dataSource.getExtractorMediaSourceFactory(cacheKey).setTag(metadata)
.createMediaSource(uri);
default:
throw new IllegalStateException("Unsupported type: " + type);
} else if (deliveryFormat instanceof DeliveryFormat.HLS) {
final String url = ((DeliveryFormat.HLS) deliveryFormat).getUrl();
return dataSource.getHlsMediaSourceFactory().setTag(metadata)
.createMediaSource(Uri.parse(url));

} else if (deliveryFormat instanceof DeliveryFormat.ManualDASH) {
final DashManifest dashManifest;
try {
final DeliveryFormat.ManualDASH manualDash =
(DeliveryFormat.ManualDASH) deliveryFormat;
final ByteArrayInputStream dashManifestInput = new ByteArrayInputStream(
manualDash.getManualDashManifest().getBytes("UTF-8"));

dashManifest = new DashManifestParser().parse(Uri.parse(manualDash.getBaseUrl()),
dashManifestInput);
} catch (IOException e) {
throw new IllegalStateException("Error while parsing manual dash manifest", e);
}

return dataSource.getDashMediaSourceFactory().setTag(metadata)
.createMediaSource(dashManifest);
} else {
throw new IllegalArgumentException("Unsupported delivery format: " + deliveryFormat);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
@Nullable final VideoStream video = tag.getSelectedVideoStream();

if (video != null) {
final MediaSource streamSource = buildMediaSource(dataSource, video.getUrl(),
final MediaSource streamSource = buildMediaSource(dataSource, video,
PlayerHelper.cacheKeyOf(info, video),
MediaFormat.getSuffixById(video.getFormatId()), tag);
mediaSources.add(streamSource);
Expand All @@ -82,7 +82,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
// Use the audio stream if there is no video stream, or
// Merge with audio stream in case if video does not contain audio
if (audio != null && (video == null || video.isVideoOnly)) {
final MediaSource audioSource = buildMediaSource(dataSource, audio.getUrl(),
final MediaSource audioSource = buildMediaSource(dataSource, audio,
PlayerHelper.cacheKeyOf(info, audio),
MediaFormat.getSuffixById(audio.getFormatId()), tag);
mediaSources.add(audioSource);
Expand All @@ -106,7 +106,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
SELECTION_FLAG_AUTOSELECT,
PlayerHelper.captionLanguageOf(context, subtitle));
final MediaSource textSource = dataSource.getSampleMediaSourceFactory()
.createMediaSource(Uri.parse(subtitle.getURL()), textFormat, TIME_UNSET);
.createMediaSource(Uri.parse(subtitle.getUrl()), textFormat, TIME_UNSET);
mediaSources.add(textSource);
}
}
Expand Down
15 changes: 14 additions & 1 deletion app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -223,9 +224,21 @@ public static void playOnExternalVideoPlayer(final Context context, final Stream

public static void playOnExternalPlayer(final Context context, final String name,
final String artist, final Stream stream) {
final String url;
final DeliveryFormat deliveryFormat = stream.getDeliveryFormat();
if (deliveryFormat instanceof DeliveryFormat.Direct) {
url = ((DeliveryFormat.Direct) deliveryFormat).getUrl();
} else if (deliveryFormat instanceof DeliveryFormat.HLS) {
url = ((DeliveryFormat.HLS) deliveryFormat).getUrl();
} else {
Toast.makeText(context, R.string.selected_stream_external_player_not_supported,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this means external players can't play DASH videos, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's right.

Although, we could send instead the url pointing to the DASH manifest containing all the resolutions, but it'd make the resolution picker a little useless and maybe confusing.

Maybe even saving a file containing a manually crafted video+audio manifest and sending that to external players? I think it could work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume such videos would throw an error if shared from the Youtube app to VLC, for example?

Toast.LENGTH_SHORT).show();
return;
}

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(stream.getUrl()), stream.getFormat().getMimeType());
intent.setDataAndType(Uri.parse(url), stream.getFormat().getMimeType());
intent.putExtra(Intent.EXTRA_TITLE, name);
intent.putExtra("title", name);
intent.putExtra("artist", artist);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private static void setSelectedServicePreferences(final Context context,

public static long getCacheExpirationMillis(final int serviceId) {
if (serviceId == SoundCloud.getServiceId()) {
return TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES);
return TimeUnit.MILLISECONDS.convert(2, TimeUnit.MINUTES);
} else {
return TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -209,9 +210,15 @@ public static <X extends Stream> Single<Boolean> fetchSizeForWrapper(
continue;
}

final DeliveryFormat deliveryFormat = stream.getDeliveryFormat();
if (!(deliveryFormat instanceof DeliveryFormat.Direct)) {
continue;
}

final long contentLength = DownloaderImpl.getInstance().getContentLength(
stream.getUrl());
((DeliveryFormat.Direct) deliveryFormat).getUrl());
streamsWrapper.setSize(stream, contentLength);

hasChanged = true;
}
return hasChanged;
Expand Down
Loading