mirror of
https://github.com/TeamNewPipe/NewPipeExtractor.git
synced 2025-04-28 16:00:33 +05:30
Merge pull request #1269 from AudricV/snd_no_drm_streams
[Soundcloud] Remove DRM-protected and downloadable formats extraction
This commit is contained in:
commit
186e32c9db
@ -6,7 +6,6 @@ import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsing
|
|||||||
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAllImagesFromTrackObject;
|
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAllImagesFromTrackObject;
|
||||||
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAvatarUrl;
|
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAvatarUrl;
|
||||||
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.parseDateFrom;
|
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.parseDateFrom;
|
||||||
import static org.schabi.newpipe.extractor.stream.AudioStream.UNKNOWN_BITRATE;
|
|
||||||
import static org.schabi.newpipe.extractor.stream.Stream.ID_UNKNOWN;
|
import static org.schabi.newpipe.extractor.stream.Stream.ID_UNKNOWN;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
@ -170,14 +169,12 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final JsonArray transcodings = track.getObject("media").getArray("transcodings");
|
final JsonArray transcodings = track.getObject("media")
|
||||||
|
.getArray("transcodings");
|
||||||
if (!isNullOrEmpty(transcodings)) {
|
if (!isNullOrEmpty(transcodings)) {
|
||||||
// Get information about what stream formats are available
|
// Get information about what stream formats are available
|
||||||
extractAudioStreams(transcodings, checkMp3ProgressivePresence(transcodings),
|
extractAudioStreams(transcodings, audioStreams);
|
||||||
audioStreams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDownloadableFileIfAvailable(audioStreams);
|
|
||||||
} catch (final NullPointerException e) {
|
} catch (final NullPointerException e) {
|
||||||
throw new ExtractionException("Could not get audio streams", e);
|
throw new ExtractionException("Could not get audio streams", e);
|
||||||
}
|
}
|
||||||
@ -185,19 +182,16 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
|||||||
return audioStreams;
|
return audioStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkMp3ProgressivePresence(@Nonnull final JsonArray transcodings) {
|
|
||||||
return transcodings.stream()
|
|
||||||
.filter(JsonObject.class::isInstance)
|
|
||||||
.map(JsonObject.class::cast)
|
|
||||||
.anyMatch(transcodingJsonObject -> transcodingJsonObject.getString("preset")
|
|
||||||
.contains("mp3") && transcodingJsonObject.getObject("format")
|
|
||||||
.getString("protocol").equals("progressive"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private String getTranscodingUrl(final String endpointUrl)
|
private String getTranscodingUrl(final String endpointUrl)
|
||||||
throws IOException, ExtractionException {
|
throws IOException, ExtractionException {
|
||||||
final String apiStreamUrl = endpointUrl + "?client_id=" + clientId();
|
String apiStreamUrl = endpointUrl + "?client_id=" + clientId();
|
||||||
|
|
||||||
|
final String trackAuthorization = track.getString("track_authorization");
|
||||||
|
if (!isNullOrEmpty(trackAuthorization)) {
|
||||||
|
apiStreamUrl += "&track_authorization=" + trackAuthorization;
|
||||||
|
}
|
||||||
|
|
||||||
final String response = NewPipe.getDownloader().get(apiStreamUrl).responseBody();
|
final String response = NewPipe.getDownloader().get(apiStreamUrl).responseBody();
|
||||||
final JsonObject urlObject;
|
final JsonObject urlObject;
|
||||||
try {
|
try {
|
||||||
@ -209,27 +203,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
|||||||
return urlObject.getString("url");
|
return urlObject.getString("url");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String getDownloadUrl(@Nonnull final String trackId)
|
|
||||||
throws IOException, ExtractionException {
|
|
||||||
final String response = NewPipe.getDownloader().get(SOUNDCLOUD_API_V2_URL + "tracks/"
|
|
||||||
+ trackId + "/download" + "?client_id=" + clientId()).responseBody();
|
|
||||||
|
|
||||||
final JsonObject downloadJsonObject;
|
|
||||||
try {
|
|
||||||
downloadJsonObject = JsonParser.object().from(response);
|
|
||||||
} catch (final JsonParserException e) {
|
|
||||||
throw new ParsingException("Could not parse download URL", e);
|
|
||||||
}
|
|
||||||
final String redirectUri = downloadJsonObject.getString("redirectUri");
|
|
||||||
if (!isNullOrEmpty(redirectUri)) {
|
|
||||||
return redirectUri;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extractAudioStreams(@Nonnull final JsonArray transcodings,
|
private void extractAudioStreams(@Nonnull final JsonArray transcodings,
|
||||||
final boolean mp3ProgressiveInStreams,
|
|
||||||
final List<AudioStream> audioStreams) {
|
final List<AudioStream> audioStreams) {
|
||||||
transcodings.stream()
|
transcodings.stream()
|
||||||
.filter(JsonObject.class::isInstance)
|
.filter(JsonObject.class::isInstance)
|
||||||
@ -244,23 +218,23 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
|||||||
final String preset = transcoding.getString("preset", ID_UNKNOWN);
|
final String preset = transcoding.getString("preset", ID_UNKNOWN);
|
||||||
final String protocol = transcoding.getObject("format")
|
final String protocol = transcoding.getObject("format")
|
||||||
.getString("protocol");
|
.getString("protocol");
|
||||||
|
|
||||||
|
if (protocol.contains("encrypted")) {
|
||||||
|
// Skip DRM-protected streams, which have encrypted in their protocol
|
||||||
|
// name
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final AudioStream.Builder builder = new AudioStream.Builder()
|
final AudioStream.Builder builder = new AudioStream.Builder()
|
||||||
.setId(preset);
|
.setId(preset);
|
||||||
|
|
||||||
final boolean isHls = protocol.equals("hls");
|
if (protocol.equals("hls")) {
|
||||||
if (isHls) {
|
|
||||||
builder.setDeliveryMethod(DeliveryMethod.HLS);
|
builder.setDeliveryMethod(DeliveryMethod.HLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setContent(getTranscodingUrl(url), true);
|
builder.setContent(getTranscodingUrl(url), true);
|
||||||
|
|
||||||
if (preset.contains("mp3")) {
|
if (preset.contains("mp3")) {
|
||||||
// Don't add the MP3 HLS stream if there is a progressive stream
|
|
||||||
// present because both have the same bitrate
|
|
||||||
if (mp3ProgressiveInStreams && isHls) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.setMediaFormat(MediaFormat.MP3);
|
builder.setMediaFormat(MediaFormat.MP3);
|
||||||
builder.setAverageBitrate(128);
|
builder.setAverageBitrate(128);
|
||||||
} else if (preset.contains("opus")) {
|
} else if (preset.contains("opus")) {
|
||||||
@ -283,39 +257,6 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the downloadable format if it is available.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* A track can have the {@code downloadable} boolean set to {@code true}, but it doesn't mean
|
|
||||||
* we can download it.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* If the value of the {@code has_download_left} boolean is {@code true}, the track can be
|
|
||||||
* downloaded, and not otherwise.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param audioStreams the audio streams to which the downloadable file is added
|
|
||||||
*/
|
|
||||||
public void extractDownloadableFileIfAvailable(final List<AudioStream> audioStreams) {
|
|
||||||
if (track.getBoolean("downloadable") && track.getBoolean("has_downloads_left")) {
|
|
||||||
try {
|
|
||||||
final String downloadUrl = getDownloadUrl(getId());
|
|
||||||
if (!isNullOrEmpty(downloadUrl)) {
|
|
||||||
audioStreams.add(new AudioStream.Builder()
|
|
||||||
.setId("original-format")
|
|
||||||
.setContent(downloadUrl, true)
|
|
||||||
.setAverageBitrate(UNKNOWN_BITRATE)
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
} catch (final Exception ignored) {
|
|
||||||
// If something went wrong when trying to get the download URL, ignore the
|
|
||||||
// exception throw because this "stream" is not necessary to play the track
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VideoStream> getVideoStreams() {
|
public List<VideoStream> getVideoStreams() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
@ -24,6 +24,7 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||||
|
|
||||||
public class SoundcloudStreamExtractorTest {
|
public class SoundcloudStreamExtractorTest {
|
||||||
@ -188,26 +189,33 @@ public class SoundcloudStreamExtractorTest {
|
|||||||
public void testAudioStreams() throws Exception {
|
public void testAudioStreams() throws Exception {
|
||||||
super.testAudioStreams();
|
super.testAudioStreams();
|
||||||
final List<AudioStream> audioStreams = extractor.getAudioStreams();
|
final List<AudioStream> audioStreams = extractor.getAudioStreams();
|
||||||
assertEquals(2, audioStreams.size());
|
assertEquals(3, audioStreams.size()); // 2 MP3 streams (1 progressive, 1 HLS) and 1 OPUS
|
||||||
audioStreams.forEach(audioStream -> {
|
audioStreams.forEach(audioStream -> {
|
||||||
final DeliveryMethod deliveryMethod = audioStream.getDeliveryMethod();
|
final DeliveryMethod deliveryMethod = audioStream.getDeliveryMethod();
|
||||||
final String mediaUrl = audioStream.getContent();
|
final String mediaUrl = audioStream.getContent();
|
||||||
if (audioStream.getFormat() == MediaFormat.OPUS) {
|
if (audioStream.getFormat() == MediaFormat.OPUS) {
|
||||||
// Assert that it's an OPUS 64 kbps media URL with a single range which comes
|
|
||||||
// from an HLS SoundCloud CDN
|
|
||||||
ExtractorAsserts.assertContains("-hls-opus-media.sndcdn.com", mediaUrl);
|
|
||||||
ExtractorAsserts.assertContains(".64.opus", mediaUrl);
|
|
||||||
assertSame(DeliveryMethod.HLS, deliveryMethod,
|
assertSame(DeliveryMethod.HLS, deliveryMethod,
|
||||||
"Wrong delivery method for stream " + audioStream.getId() + ": "
|
"Wrong delivery method for stream " + audioStream.getId() + ": "
|
||||||
+ deliveryMethod);
|
+ deliveryMethod);
|
||||||
} else if (audioStream.getFormat() == MediaFormat.MP3) {
|
// Assert it's an OPUS 64 kbps media playlist URL which comes from an HLS
|
||||||
// Assert that it's a MP3 128 kbps media URL which comes from a progressive
|
|
||||||
// SoundCloud CDN
|
// SoundCloud CDN
|
||||||
ExtractorAsserts.assertContains("-media.sndcdn.com/bKOA7Pwbut93.128.mp3",
|
ExtractorAsserts.assertContains("-hls-opus-media.sndcdn.com", mediaUrl);
|
||||||
mediaUrl);
|
ExtractorAsserts.assertContains(".64.opus", mediaUrl);
|
||||||
assertSame(DeliveryMethod.PROGRESSIVE_HTTP, deliveryMethod,
|
} else if (audioStream.getFormat() == MediaFormat.MP3) {
|
||||||
"Wrong delivery method for stream " + audioStream.getId() + ": "
|
if (deliveryMethod == DeliveryMethod.PROGRESSIVE_HTTP) {
|
||||||
+ deliveryMethod);
|
// Assert it's a MP3 128 kbps media URL which comes from a progressive
|
||||||
|
// SoundCloud CDN
|
||||||
|
ExtractorAsserts.assertContains("-media.sndcdn.com/bKOA7Pwbut93.128.mp3",
|
||||||
|
mediaUrl);
|
||||||
|
} else if (deliveryMethod == DeliveryMethod.HLS) {
|
||||||
|
// Assert it's a MP3 128 kbps media HLS playlist URL which comes from an HLS
|
||||||
|
// SoundCloud CDN
|
||||||
|
ExtractorAsserts.assertContains("-hls-media.sndcdn.com", mediaUrl);
|
||||||
|
ExtractorAsserts.assertContains(".128.mp3", mediaUrl);
|
||||||
|
} else {
|
||||||
|
fail("Wrong delivery method for stream " + audioStream.getId() + ": "
|
||||||
|
+ deliveryMethod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user