Skip to content
Merged
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
28 changes: 11 additions & 17 deletions app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.localization.Localization;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
Expand Down Expand Up @@ -88,6 +87,7 @@
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import us.shandian.giga.get.HlsDownloadStreamHelper;
import us.shandian.giga.get.MissionRecoveryInfo;
import us.shandian.giga.get.SabrDownloadStreamHelper;
import us.shandian.giga.postprocessing.Postprocessing;
import us.shandian.giga.service.DownloadManager;
import us.shandian.giga.service.DownloadManagerService;
Expand Down Expand Up @@ -157,29 +157,20 @@ public static DownloadDialog newInstance(final StreamInfo info) {
}

public static DownloadDialog newInstance(final Context context, final StreamInfo info) {
final List<VideoStream> videoStreams = info.getVideoStreams().stream()
.filter(stream -> stream.getDeliveryMethod() != DeliveryMethod.SABR)
.collect(Collectors.toList());
final List<VideoStream> videoOnlyStreams = info.getVideoOnlyStreams().stream()
.filter(stream -> stream.getDeliveryMethod() != DeliveryMethod.SABR)
.collect(Collectors.toList());
final List<AudioStream> audioStreams = info.getAudioStreams().stream()
.filter(stream -> stream.getDeliveryMethod() != DeliveryMethod.SABR)
.collect(Collectors.toList());
final ArrayList<VideoStream> streamsList = new ArrayList<>(ListHelper
.getSortedStreamVideosList(context, videoStreams,
videoOnlyStreams, false, false));
.getSortedStreamVideosList(context, info.getVideoStreams(),
info.getVideoOnlyStreams(), false, false));

final List<VideoStream> filteredVideoStreams = ListHelper
.filterVideoStreamsByPreferredLanguage(context, streamsList,
audioStreams);
info.getAudioStreams());

final int selectedStreamIndex = ListHelper.getDefaultResolutionIndex(
context, filteredVideoStreams);
HlsDownloadStreamHelper.addManifestFallbackIfNeeded(filteredVideoStreams, info);

final List<AudioStream> downloadableAudio = ListHelper
.filterDownloadableAudioStreams(audioStreams);
.filterDownloadableAudioStreams(info.getAudioStreams());
HlsDownloadStreamHelper.addAudioFallbackIfNeeded(downloadableAudio, info);

final DownloadDialog instance = newInstance(info);
Expand Down Expand Up @@ -278,9 +269,11 @@ public void onCreate(@Nullable final Bundle savedInstanceState) {
continue;
}
final AudioStream audioStream = SecondaryStreamHelper
.getAudioStreamFor(getContext(), wrappedAudioStreams.getStreamsList(), videoStreams.get(i));
.getAudioStreamFor(getContext(), SabrDownloadStreamHelper.audioStreamsForVideo(
wrappedAudioStreams.getStreamsList(), videoStreams.get(i)), videoStreams.get(i));

if (audioStream != null) {
if (audioStream != null && SabrDownloadStreamHelper
.isCompatibleSecondaryStream(videoStreams.get(i), audioStream)) {
secondaryStreams
.append(i, new SecondaryStreamHelper<>(wrappedAudioStreams, audioStream));
} else if (DEBUG) {
Expand Down Expand Up @@ -1154,7 +1147,8 @@ private void continueSelectedDownload(@NonNull final StoredFileHelper storage) {
resourceIsUrls = HlsDownloadStreamHelper
.buildResourceIsUrls(selectedStream, secondaryStream);
if (HlsDownloadStreamHelper.containsHlsResource(resourceDeliveryMethods,
resourceManifestUrls, urls)) {
resourceManifestUrls, urls)
|| SabrDownloadStreamHelper.containsSabrStream(selectedStream, secondaryStream)) {
psName = null;
psArgs = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import androidx.media3.exoplayer.source.MediaSource;

import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.helper.PlayerDataSource;
import org.schabi.newpipe.player.helper.PlayerHelper;
Expand Down Expand Up @@ -52,10 +51,6 @@ public MediaSource resolve(@NonNull final StreamInfo info) {

List<AudioStream> audioStreams = info.getAudioStreams()
.stream().filter(s -> !blacklistUrls.contains(s.getContent())).collect(Collectors.toList());
if (audioStreams.stream().anyMatch(
stream -> stream.getDeliveryMethod() == DeliveryMethod.SABR)) {
audioStreams.removeIf(stream -> stream.getDeliveryMethod() == DeliveryMethod.HLS);
}
removeTorrentStreams(audioStreams);
audioStreams = filterUnsupportedFormats(audioStreams, context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -80,20 +79,6 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
final List<MediaSource> mediaSources = new ArrayList<>();
final List<VideoStream> videoStreams = new ArrayList<>(info.getVideoStreams());
final List<VideoStream> videoOnlyStreams = new ArrayList<>(info.getVideoOnlyStreams());
final List<AudioStream> playbackAudioStreams = new ArrayList<>(info.getAudioStreams());

final boolean hasSabr = videoStreams.stream().anyMatch(
stream -> stream.getDeliveryMethod() == DeliveryMethod.SABR)
|| videoOnlyStreams.stream().anyMatch(
stream -> stream.getDeliveryMethod() == DeliveryMethod.SABR)
|| playbackAudioStreams.stream().anyMatch(
stream -> stream.getDeliveryMethod() == DeliveryMethod.SABR);
if (hasSabr) {
videoStreams.removeIf(stream -> stream.getDeliveryMethod() == DeliveryMethod.HLS);
videoOnlyStreams.removeIf(stream -> stream.getDeliveryMethod() == DeliveryMethod.HLS);
playbackAudioStreams.removeIf(
stream -> stream.getDeliveryMethod() == DeliveryMethod.HLS);
}

removeTorrentStreams(videoStreams);
removeTorrentStreams(videoOnlyStreams);
Expand All @@ -115,7 +100,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
.anyMatch(s -> s.getAudioTrackId() != null);
if (hasVideoAudioTracks) {
final List<AudioStream> allAudioStreams = ListHelper.getFilteredAudioStreams(
context, playbackAudioStreams);
context, info.getAudioStreams());
final int defaultIdx = ListHelper.getDefaultAudioFormat(context, allAudioStreams);
if (defaultIdx >= 0 && defaultIdx < allAudioStreams.size()) {
final String defaultTrackId = allAudioStreams.get(defaultIdx).getAudioTrackId();
Expand Down Expand Up @@ -164,7 +149,7 @@ public MediaSource resolve(@NonNull final StreamInfo info) {

// Create optional audio stream source
final List<AudioStream> audioStreams = ListHelper.getFilteredAudioStreams(context,
playbackAudioStreams
info.getAudioStreams()
.stream().filter(s -> !blacklistUrls.contains(s.getContent()))
.collect(Collectors.toList()));
final int audioIndex = ListHelper.getAudioFormatIndex(context, audioStreams, audioTrack);
Expand Down
25 changes: 25 additions & 0 deletions app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.services.youtube.sabr.YoutubeSabrFormat;
import org.schabi.newpipe.extractor.services.youtube.sabr.YoutubeSabrInfo;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
import org.schabi.newpipe.extractor.stream.Stream;
Expand Down Expand Up @@ -264,6 +266,11 @@ public static <X extends Stream> Single<Boolean> fetchSizeForWrapper(
hasChanged = true;
continue;
}
if (stream.getDeliveryMethod() == DeliveryMethod.SABR) {
streamsWrapper.setSize(stream, getSabrContentLength(stream));
hasChanged = true;
continue;
}

final long contentLength = DownloaderImpl.getInstance().getContentLength(
stream.getUrl());
Expand All @@ -279,6 +286,24 @@ public static <X extends Stream> Single<Boolean> fetchSizeForWrapper(
.onErrorReturnItem(true);
}

private static long getSabrContentLength(final Stream stream) {
if (!(stream.getDeliveryMethodInfo() instanceof YoutubeSabrInfo)) {
return -1;
}
final int itag;
if (stream instanceof AudioStream) {
itag = ((AudioStream) stream).getItag();
} else if (stream instanceof VideoStream) {
itag = ((VideoStream) stream).getItag();
} else {
return -1;
}
final YoutubeSabrFormat format = ((YoutubeSabrInfo) stream.getDeliveryMethodInfo())
.findFormatByItag(itag);
return format != null && format.getContentLength() > 0
? format.getContentLength() : -1;
}

public static <X extends Stream> StreamSizeWrapper<X> empty() {
//noinspection unchecked
return (StreamSizeWrapper<X>) EMPTY;
Expand Down
9 changes: 6 additions & 3 deletions app/src/main/java/us/shandian/giga/get/DirectDownloader.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@ public void init(){
continue;
}
final AudioStream audioStream = SecondaryStreamHelper
.getAudioStreamFor(context, wrappedAudioStreams.getStreamsList(), videoStreams.get(i));
.getAudioStreamFor(context, SabrDownloadStreamHelper.audioStreamsForVideo(
wrappedAudioStreams.getStreamsList(), videoStreams.get(i)), videoStreams.get(i));

if (audioStream != null) {
if (audioStream != null && SabrDownloadStreamHelper
.isCompatibleSecondaryStream(videoStreams.get(i), audioStream)) {
secondaryStreams
.append(i, new SecondaryStreamHelper<>(wrappedAudioStreams, audioStream));
}
Expand Down Expand Up @@ -270,7 +272,8 @@ public void startDownload(StoredFileHelper storage) {
resourceIsUrls = HlsDownloadStreamHelper
.buildResourceIsUrls(selectedStream, secondaryStream);
if (HlsDownloadStreamHelper.containsHlsResource(resourceDeliveryMethods,
resourceManifestUrls, urls)) {
resourceManifestUrls, urls)
|| SabrDownloadStreamHelper.containsSabrStream(selectedStream, secondaryStream)) {
psName = null;
psArgs = null;
}
Expand Down
26 changes: 23 additions & 3 deletions app/src/main/java/us/shandian/giga/get/DownloadMission.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class DownloadMission extends Mission {
public static final int ERROR_PROGRESS_LOST = 1011;
public static final int ERROR_TIMEOUT = 1012;
public static final int ERROR_RESOURCE_GONE = 1013;
public static final int ERROR_SABR_DOWNLOAD = 1014;
public static final int ERROR_HTTP_NO_CONTENT = 204;
static final int ERROR_HTTP_FORBIDDEN = 403;
static final int ERROR_HTTP_AUTH = 401;
Expand Down Expand Up @@ -128,12 +129,15 @@ public class DownloadMission extends Mission {
public MissionRecoveryInfo[] recoveryInfo;

/**
* Optional typed metadata for resources. Used only to route HLS resources to the HLS downloader.
* Optional typed metadata for resources. Used to route session/manifest resources to their
* dedicated downloaders instead of the direct HTTP range downloader.
*/
public String[] resourceDeliveryMethods;
public String[] resourceManifestUrls;
public boolean[] resourceIsUrls;
public HlsDownloadCheckpoint hlsCheckpoint;
public SabrDownloadCheckpoint sabrCheckpoint;
public boolean sabrStarted;

private transient int finishCount;
public transient volatile boolean running;
Expand Down Expand Up @@ -317,6 +321,8 @@ synchronized void notifyError(Exception err) {
notifyError(ERROR_UNKNOWN_HOST, null);
} else if (err instanceof SocketTimeoutException) {
notifyError(ERROR_TIMEOUT, null);
} else if (err instanceof SabrDownloadException) {
notifyError(ERROR_SABR_DOWNLOAD, err);
} else {
notifyError(ERROR_UNKNOWN_EXCEPTION, err);
}
Expand Down Expand Up @@ -461,6 +467,11 @@ public void start() {
return;
}

if (hasSabrResource()) {
init = runAsync(DownloadInitializer.mId, new SabrDownloader(this));
return;
}

if (hasHlsResource()) {
init = runAsync(DownloadInitializer.mId, new HlsDownloader(this));
return;
Expand Down Expand Up @@ -540,6 +551,7 @@ private void pauseThreads() {
public boolean delete() {
if (psAlgorithm != null) psAlgorithm.cleanupTemporalDir();
HlsDownloader.cleanup(this);
SabrDownloader.cleanup(this);

notify(DownloadManagerService.MESSAGE_DELETED);

Expand All @@ -565,7 +577,11 @@ public void resetState(boolean rollback, boolean persistChanges, int errorCode)
fallbackResumeOffset = 0;
blocks = null;
blockAcquired = null;
if (rollback) hlsCheckpoint = null;
if (rollback) {
hlsCheckpoint = null;
sabrCheckpoint = null;
sabrStarted = false;
}

if (rollback) current = 0;
if (persistChanges) writeThisToFile();
Expand Down Expand Up @@ -630,14 +646,18 @@ public boolean isPsRunning() {
* @return true, otherwise, false
*/
public boolean isInitialized() {
return blocks != null || hlsCheckpoint != null; // DownloadMissionInitializer or HLS downloader was executed
return blocks != null || hlsCheckpoint != null || sabrStarted;
}

boolean hasHlsResource() {
return HlsDownloadStreamHelper.containsHlsResource(resourceDeliveryMethods,
resourceManifestUrls, urls);
}

boolean hasSabrResource() {
return SabrDownloadStreamHelper.containsSabrResource(resourceDeliveryMethods, recoveryInfo);
}

/**
* Gets the approximated final length of the file
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,29 @@ class MissionRecoveryInfo(
var kind: Char = Char.MIN_VALUE,
var validateCondition: String? = null,
var audioTrackId: String? = null,
var isHls: Boolean = false
var isHls: Boolean = false,
var isSabr: Boolean = false,
var itag: Int = -1,
var deliveryMethodInfo: Serializable? = null
) : Serializable, Parcelable {
constructor(stream: Stream) : this(format = stream.getFormat()!!) {
isHls = stream.getDeliveryMethod() == DeliveryMethod.HLS
isSabr = stream.getDeliveryMethod() == DeliveryMethod.SABR
deliveryMethodInfo = stream.deliveryMethodInfo
when (stream) {
is AudioStream -> {
desiredBitrate = stream.averageBitrate
isDesired2 = false
kind = 'a'
audioTrackId = stream.audioTrackId
itag = stream.itag
}
is VideoStream -> {
desired = stream.resolution
isDesired2 = stream.isVideoOnly
kind = 'v'
audioTrackId = stream.audioTrackId
itag = stream.itag
}
is SubtitlesStream -> {
desired = stream.languageTag
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/us/shandian/giga/get/SabrDownloadCheckpoint.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package us.shandian.giga.get

import java.io.Serializable

data class SabrDownloadCheckpoint(
val version: Int = VERSION,
val resources: List<SabrResourceCheckpoint> = emptyList(),
) : Serializable {
companion object {
private const val serialVersionUID = 1L
const val VERSION = 1
}
}

data class SabrResourceCheckpoint(
val resourceIndex: Int,
val itag: Int,
val tempFilePath: String,
val nextWriteSequence: Int,
val bytesWritten: Long,
val initializationBytes: Int,
) : Serializable {
companion object {
private const val serialVersionUID = 1L
}
}
20 changes: 20 additions & 0 deletions app/src/main/java/us/shandian/giga/get/SabrDownloadException.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package us.shandian.giga.get

import java.io.IOException

internal class SabrDownloadException(
val reason: Reason,
message: String,
cause: Throwable? = null,
) : IOException(message, cause) {
enum class Reason {
FORMAT,
INITIALIZATION,
PROTECTED,
STALLED,
NETWORK,
MUXING,
STORAGE,
PROTOCOL,
}
}
Loading