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
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 @@ -4,19 +4,17 @@
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException;

import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
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 All @@ -25,6 +23,7 @@
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
Expand All @@ -33,10 +32,7 @@
import java.util.List;
import java.util.Locale;

import javax.annotation.Nonnull;

import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;

public class SoundcloudStreamExtractor extends StreamExtractor {
private JsonObject track;
Expand Down Expand Up @@ -175,54 +171,72 @@ public String getHlsUrl() throws ParsingException {

@Override
public List<AudioStream> getAudioStreams() throws IOException, ExtractionException {
List<AudioStream> audioStreams = new ArrayList<>();
Downloader dl = NewPipe.getDownloader();
final List<AudioStream> audioStreams = new ArrayList<>();

// Streams can be streamable and downloadable - or explicitly not.
// For playing the track, it is only necessary to have a streamable track.
// If this is not the case, this track might not be published yet.
if (!track.getBoolean("streamable")) return audioStreams;

try {
JsonArray transcodings = track.getObject("media").getArray("transcodings");
final JsonArray transcodings = track.getObject("media").getArray("transcodings");

// get information about what stream formats are available
// Get information about what stream formats are available
for (Object transcoding : transcodings) {
final JsonObject transcodingObject = (JsonObject) transcoding;
String url = transcodingObject.getString("url");
final String preset = transcodingObject.getString("preset");
final JsonObject format = transcodingObject.getObject("format");
final String protocol = format.getString("protocol");

final MediaFormat mediaFormat;
final int mediaQuality;

if (preset.startsWith("mp3")) {
mediaFormat = MediaFormat.MP3;
} else if (preset.startsWith("opus")) {
mediaFormat = MediaFormat.OPUS;
} else {
throw new ParsingException("Unsupported media format: " + preset);
}

if (preset.equals("mp3_0_0") || preset.equals("mp3_0_1")
|| preset.equals("mp3_standard")) {
mediaQuality = 128;
} else if (preset.equals("opus_0_0")) {
mediaQuality = 64;
} else {
throw new ParsingException("Unsupported media quality: " + preset);
}

JsonObject t = (JsonObject) transcoding;
String url = t.getString("url");

if (!isNullOrEmpty(url)) {

// We can only play the mp3 format, but not handle m3u playlists / streams.
// what about Opus?
if (t.getString("preset").contains("mp3")
&& t.getObject("format").getString("protocol").equals("progressive")) {
// This url points to the endpoint which generates a unique and short living url to the stream.
// TODO: move this to a separate method to generate valid urls when needed (e.g. resuming a paused stream)
url += "?client_id=" + SoundcloudParsingHelper.clientId();
String res = dl.get(url).responseBody();

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"),
MediaFormat.MP3, 128));
} catch (JsonParserException e) {
throw new ParsingException("Could not parse streamable url", e);
}
}
url += "?client_id=" + SoundcloudParsingHelper.clientId();
final String urlResponse = getDownloader().get(url).responseBody();

final JsonObject urlObject;
try {
urlObject = JsonParser.object().from(urlResponse);
} catch (JsonParserException e) {
throw new ParsingException("Could not parse url response", e);
}

final DeliveryFormat deliveryFormat;
final String mediaUrl = urlObject.getString("url");

if (protocol.equalsIgnoreCase("progressive")) {
deliveryFormat = DeliveryFormat.direct(mediaUrl);
} else if (protocol.equalsIgnoreCase("hls")) {
deliveryFormat = DeliveryFormat.hls(mediaUrl);
} else {
throw new ParsingException("Unsupported protocol: " + protocol);
}

audioStreams.add(new AudioStream(deliveryFormat, mediaFormat, mediaQuality));
}

} catch (NullPointerException e) {
throw new ExtractionException("Could not get SoundCloud's track audio url", e);
}

if (audioStreams.isEmpty()) {
throw new ContentNotSupportedException("HLS audio streams are not yet supported");
}

return audioStreams;
}

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
Loading