Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
Expand Down Expand Up @@ -160,7 +161,8 @@ public List<AudioStream> getAudioStreams() throws ExtractionException {
throw new ExtractionException("Unknown media format: " + mimeType);
}

audioStreams.add(new AudioStream(recording.getString("recording_url"),
audioStreams.add(new AudioStream(
DeliveryFormat.direct(recording.getString("recording_url")),
mediaFormat, -1));
}
}
Expand All @@ -186,7 +188,8 @@ public List<VideoStream> getVideoStreams() throws ExtractionException {
throw new ExtractionException("Unknown media format: " + mimeType);
}

videoStreams.add(new VideoStream(recording.getString("recording_url"),
videoStreams.add(new VideoStream(
DeliveryFormat.direct(recording.getString("recording_url")),
mediaFormat, recording.getInt("height") + "p"));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
Expand Down Expand Up @@ -209,7 +210,8 @@ public List<VideoStream> getVideoStreams() throws IOException, ExtractionExcepti
String resolution = JsonUtils.getString(stream, "resolution.label");
String extension = url.substring(url.lastIndexOf(".") + 1);
MediaFormat format = MediaFormat.getFromSuffix(extension);
VideoStream videoStream = new VideoStream(url, torrentUrl, format, resolution);
VideoStream videoStream = new VideoStream(torrentUrl, DeliveryFormat.direct(url),
format, resolution, false);
if (!Stream.containSimilarStream(videoStream, videoStreams)) {
videoStreams.add(videoStream);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
Expand Down Expand Up @@ -206,7 +207,8 @@ public List<AudioStream> getAudioStreams() throws IOException, ExtractionExcepti
try {
JsonObject mp3UrlObject = JsonParser.object().from(res);
// Links in this file are also only valid for a short period.
audioStreams.add(new AudioStream(mp3UrlObject.getString("url"),
audioStreams.add(new AudioStream(
DeliveryFormat.direct(mp3UrlObject.getString("url")),
MediaFormat.MP3, 128));
} catch (JsonParserException e) {
throw new ParsingException("Could not parse streamable url", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.DeliveryFormat;
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.Frameset;
import org.schabi.newpipe.extractor.stream.Stream;
Expand Down Expand Up @@ -422,10 +423,11 @@ public List<AudioStream> getAudioStreams() throws ExtractionException {
assertPageFetched();
List<AudioStream> audioStreams = new ArrayList<>();
try {
for (Map.Entry<String, ItagItem> entry : getItags(ADAPTIVE_FORMATS, ItagItem.ItagType.AUDIO).entrySet()) {
for (Map.Entry<DeliveryFormat, ItagItem> entry : getItags(ADAPTIVE_FORMATS, ItagItem.ItagType.AUDIO).entrySet()) {
ItagItem itag = entry.getValue();

AudioStream audioStream = new AudioStream(entry.getKey(), itag.getMediaFormat(), itag.avgBitrate);
AudioStream audioStream = new AudioStream(entry.getKey(),
itag.getMediaFormat(), itag.avgBitrate);
if (!Stream.containSimilarStream(audioStream, audioStreams)) {
audioStreams.add(audioStream);
}
Expand All @@ -442,10 +444,11 @@ public List<VideoStream> getVideoStreams() throws ExtractionException {
assertPageFetched();
List<VideoStream> videoStreams = new ArrayList<>();
try {
for (Map.Entry<String, ItagItem> entry : getItags(FORMATS, ItagItem.ItagType.VIDEO).entrySet()) {
for (Map.Entry<DeliveryFormat, ItagItem> entry : getItags(FORMATS, ItagItem.ItagType.VIDEO).entrySet()) {
ItagItem itag = entry.getValue();

VideoStream videoStream = new VideoStream(entry.getKey(), itag.getMediaFormat(), itag.resolutionString);
VideoStream videoStream = new VideoStream(entry.getKey(),
itag.getMediaFormat(), itag.resolutionString);
if (!Stream.containSimilarStream(videoStream, videoStreams)) {
videoStreams.add(videoStream);
}
Expand All @@ -462,10 +465,11 @@ public List<VideoStream> getVideoOnlyStreams() throws ExtractionException {
assertPageFetched();
List<VideoStream> videoOnlyStreams = new ArrayList<>();
try {
for (Map.Entry<String, ItagItem> entry : getItags(ADAPTIVE_FORMATS, ItagItem.ItagType.VIDEO_ONLY).entrySet()) {
for (Map.Entry<DeliveryFormat, ItagItem> entry : getItags(ADAPTIVE_FORMATS, ItagItem.ItagType.VIDEO_ONLY).entrySet()) {
ItagItem itag = entry.getValue();

VideoStream videoStream = new VideoStream(entry.getKey(), itag.getMediaFormat(), itag.resolutionString, true);
VideoStream videoStream = new VideoStream(entry.getKey(), itag.getMediaFormat(),
itag.resolutionString, true);
if (!Stream.containSimilarStream(videoStream, videoOnlyStreams)) {
videoOnlyStreams.add(videoStream);
}
Expand Down Expand Up @@ -909,8 +913,8 @@ private static String getVideoInfoUrl(final String id, final String sts) {
"&sts=" + sts + "&ps=default&gl=US&hl=en";
}

private Map<String, ItagItem> getItags(String streamingDataKey, ItagItem.ItagType itagTypeWanted) throws ParsingException {
Map<String, ItagItem> urlAndItags = new LinkedHashMap<>();
private Map<DeliveryFormat, ItagItem> getItags(String streamingDataKey, ItagItem.ItagType itagTypeWanted) throws ParsingException {
Map<DeliveryFormat, ItagItem> urlAndItags = new LinkedHashMap<>();
JsonObject streamingData = playerResponse.getObject("streamingData");
if (!streamingData.has(streamingDataKey)) {
return urlAndItags;
Expand All @@ -926,6 +930,14 @@ private Map<String, ItagItem> getItags(String streamingDataKey, ItagItem.ItagTyp
ItagItem itagItem = ItagItem.getItag(itag);
if (itagItem.itagType == itagTypeWanted) {
String streamUrl;

// Ignore streams that are delivered using YouTube's OTF format,
// as they will generally be available in when extracting the MPD.
if (formatData.getString("type", EMPTY_STRING)
.equalsIgnoreCase("FORMAT_STREAM_TYPE_OTF")) {
continue;
}

if (formatData.has("url")) {
streamUrl = formatData.getString("url");
} else {
Expand All @@ -938,7 +950,7 @@ private Map<String, ItagItem> getItags(String streamingDataKey, ItagItem.ItagTyp
+ decryptSignature(cipher.get("s"), decryptionCode);
}

urlAndItags.put(streamUrl, itagItem);
urlAndItags.put(DeliveryFormat.direct(streamUrl), itagItem);
}
} catch (UnsupportedEncodingException ignored) {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ public class AudioStream extends Stream {

/**
* Create a new audio stream
* @param url the url
*
* @param deliveryFormat how this stream is delivered
* @param format the format
* @param averageBitrate the average bitrate
*/
public AudioStream(String url, MediaFormat format, int averageBitrate) {
super(url, format);
public AudioStream(DeliveryFormat deliveryFormat, MediaFormat format, int averageBitrate) {
super(deliveryFormat, format);
this.average_bitrate = averageBitrate;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package org.schabi.newpipe.extractor.stream;

import java.io.Serializable;

import edu.umd.cs.findbugs.annotations.NonNull;

/**
* A class that is used to represent the way that a streaming service deliver their streams.
*/
public abstract class DeliveryFormat implements Serializable {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you make this class an interface and add a getUrl method? This will save us some casts.


public static Direct direct(@NonNull String url) {
return new Direct(url);
}

public static HLS hls(@NonNull String url) {
return new HLS(url);
}

public static ManualDASH manualDASH(@NonNull String baseUrl,
@NonNull String manualDashManifest) {
return new ManualDASH(baseUrl, manualDashManifest);
}

/**
* Used when a service offer a direct link to their streams.
*/
public static class Direct extends DeliveryFormat {
private final String url;

private Direct(String url) {
this.url = url;
}

public String getUrl() {
return url;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Direct direct = (Direct) o;

//noinspection EqualsReplaceableByObjectsCall
return url != null ? url.equals(direct.url) : direct.url == null;
}

@Override
public int hashCode() {
return url != null ? url.hashCode() : 0;
}
}

/**
* Used when a service uses HLS playlists for delivering their content.
*/
public static class HLS extends DeliveryFormat {
private final String url;

private HLS(String url) {
this.url = url;
}

public String getUrl() {
return url;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

HLS hls = (HLS) o;

//noinspection EqualsReplaceableByObjectsCall
return url != null ? url.equals(hls.url) : hls.url == null;
}

@Override
public int hashCode() {
return url != null ? url.hashCode() : 0;
}
}

/**
* Used when a service uses DASH Manifests to deliver their streams.
* <p>
* This is useful for extracting a specific stream from the entire manifest.
*/
public static class ManualDASH extends DeliveryFormat {
private final String baseUrl;
private final String manualDashManifest;

private ManualDASH(String baseUrl, String manualDashManifest) {
this.baseUrl = baseUrl;
this.manualDashManifest = manualDashManifest;
}

public String getBaseUrl() {
return baseUrl;
}

public String getManualDashManifest() {
return manualDashManifest;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

ManualDASH that = (ManualDASH) o;

//noinspection EqualsReplaceableByObjectsCall
if (baseUrl != null ? !baseUrl.equals(that.baseUrl) : that.baseUrl != null) {
return false;
}

//noinspection EqualsReplaceableByObjectsCall
return manualDashManifest != null
? manualDashManifest.equals(that.manualDashManifest)
: that.manualDashManifest == null;
}

@Override
public int hashCode() {
int result = baseUrl != null ? baseUrl.hashCode() : 0;
result = 31 * result + (manualDashManifest != null ? manualDashManifest.hashCode() : 0);
return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/
public abstract class Stream implements Serializable {
private final MediaFormat mediaFormat;
public final String url;
public final String torrentUrl;
private final DeliveryFormat deliveryFormat;

/**
* @deprecated Use {@link #getFormat()} or {@link #getFormatId()}
Expand All @@ -24,23 +24,23 @@ public abstract class Stream implements Serializable {
/**
* Instantiates a new stream object.
*
* @param url the url
* @param deliveryFormat how this stream is delivered
* @param format the format
*/
public Stream(String url, MediaFormat format) {
this(url, null, format);
public Stream(DeliveryFormat deliveryFormat, MediaFormat format) {
this(null, deliveryFormat, format);
}

/**
* Instantiates a new stream object.
*
* @param url the url
* @param torrentUrl the url to torrent file, example https://webtorrent.io/torrents/big-buck-bunny.torrent
* @param deliveryFormat how this stream is delivered
* @param format the format
*/
public Stream(String url, String torrentUrl, MediaFormat format) {
this.url = url;
public Stream(String torrentUrl,
DeliveryFormat deliveryFormat, MediaFormat format) {
this.torrentUrl = torrentUrl;
this.deliveryFormat = deliveryFormat;
this.format = format.id;
this.mediaFormat = format;
}
Expand All @@ -56,7 +56,7 @@ public boolean equalStats(Stream cmp) {
* Reveals whether two Streams are equal
*/
public boolean equals(Stream cmp) {
return equalStats(cmp) && url.equals(cmp.url);
return equalStats(cmp) && deliveryFormat.equals(cmp.deliveryFormat);
}

/**
Expand All @@ -70,15 +70,6 @@ public static boolean containSimilarStream(Stream stream, List<? extends Stream>
return false;
}

/**
* Gets the url.
*
* @return the url
*/
public String getUrl() {
return url;
}

/**
* Gets the torrent url.
*
Expand All @@ -88,6 +79,13 @@ public String getTorrentUrl() {
return torrentUrl;
}

/**
* @return how this stream is delivered by a service.
*/
public DeliveryFormat getDeliveryFormat() {
return deliveryFormat;
}

/**
* Gets the format.
*
Expand Down
Loading