Skip to content

Commit 186e32c

Browse files
authored
Merge pull request #1269 from AudricV/snd_no_drm_streams
[Soundcloud] Remove DRM-protected and downloadable formats extraction
2 parents 3a33cef + a336a8c commit 186e32c

2 files changed

Lines changed: 38 additions & 89 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java

Lines changed: 18 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAllImagesFromTrackObject;
77
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.getAvatarUrl;
88
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.parseDateFrom;
9-
import static org.schabi.newpipe.extractor.stream.AudioStream.UNKNOWN_BITRATE;
109
import static org.schabi.newpipe.extractor.stream.Stream.ID_UNKNOWN;
1110
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
1211

@@ -170,34 +169,29 @@ public List<AudioStream> getAudioStreams() throws ExtractionException {
170169
}
171170

172171
try {
173-
final JsonArray transcodings = track.getObject("media").getArray("transcodings");
172+
final JsonArray transcodings = track.getObject("media")
173+
.getArray("transcodings");
174174
if (!isNullOrEmpty(transcodings)) {
175175
// Get information about what stream formats are available
176-
extractAudioStreams(transcodings, checkMp3ProgressivePresence(transcodings),
177-
audioStreams);
176+
extractAudioStreams(transcodings, audioStreams);
178177
}
179-
180-
extractDownloadableFileIfAvailable(audioStreams);
181178
} catch (final NullPointerException e) {
182179
throw new ExtractionException("Could not get audio streams", e);
183180
}
184181

185182
return audioStreams;
186183
}
187184

188-
private static boolean checkMp3ProgressivePresence(@Nonnull final JsonArray transcodings) {
189-
return transcodings.stream()
190-
.filter(JsonObject.class::isInstance)
191-
.map(JsonObject.class::cast)
192-
.anyMatch(transcodingJsonObject -> transcodingJsonObject.getString("preset")
193-
.contains("mp3") && transcodingJsonObject.getObject("format")
194-
.getString("protocol").equals("progressive"));
195-
}
196-
197185
@Nonnull
198186
private String getTranscodingUrl(final String endpointUrl)
199187
throws IOException, ExtractionException {
200-
final String apiStreamUrl = endpointUrl + "?client_id=" + clientId();
188+
String apiStreamUrl = endpointUrl + "?client_id=" + clientId();
189+
190+
final String trackAuthorization = track.getString("track_authorization");
191+
if (!isNullOrEmpty(trackAuthorization)) {
192+
apiStreamUrl += "&track_authorization=" + trackAuthorization;
193+
}
194+
201195
final String response = NewPipe.getDownloader().get(apiStreamUrl).responseBody();
202196
final JsonObject urlObject;
203197
try {
@@ -209,27 +203,7 @@ private String getTranscodingUrl(final String endpointUrl)
209203
return urlObject.getString("url");
210204
}
211205

212-
@Nullable
213-
private String getDownloadUrl(@Nonnull final String trackId)
214-
throws IOException, ExtractionException {
215-
final String response = NewPipe.getDownloader().get(SOUNDCLOUD_API_V2_URL + "tracks/"
216-
+ trackId + "/download" + "?client_id=" + clientId()).responseBody();
217-
218-
final JsonObject downloadJsonObject;
219-
try {
220-
downloadJsonObject = JsonParser.object().from(response);
221-
} catch (final JsonParserException e) {
222-
throw new ParsingException("Could not parse download URL", e);
223-
}
224-
final String redirectUri = downloadJsonObject.getString("redirectUri");
225-
if (!isNullOrEmpty(redirectUri)) {
226-
return redirectUri;
227-
}
228-
return null;
229-
}
230-
231206
private void extractAudioStreams(@Nonnull final JsonArray transcodings,
232-
final boolean mp3ProgressiveInStreams,
233207
final List<AudioStream> audioStreams) {
234208
transcodings.stream()
235209
.filter(JsonObject.class::isInstance)
@@ -244,23 +218,23 @@ private void extractAudioStreams(@Nonnull final JsonArray transcodings,
244218
final String preset = transcoding.getString("preset", ID_UNKNOWN);
245219
final String protocol = transcoding.getObject("format")
246220
.getString("protocol");
221+
222+
if (protocol.contains("encrypted")) {
223+
// Skip DRM-protected streams, which have encrypted in their protocol
224+
// name
225+
return;
226+
}
227+
247228
final AudioStream.Builder builder = new AudioStream.Builder()
248229
.setId(preset);
249230

250-
final boolean isHls = protocol.equals("hls");
251-
if (isHls) {
231+
if (protocol.equals("hls")) {
252232
builder.setDeliveryMethod(DeliveryMethod.HLS);
253233
}
254234

255235
builder.setContent(getTranscodingUrl(url), true);
256236

257237
if (preset.contains("mp3")) {
258-
// Don't add the MP3 HLS stream if there is a progressive stream
259-
// present because both have the same bitrate
260-
if (mp3ProgressiveInStreams && isHls) {
261-
return;
262-
}
263-
264238
builder.setMediaFormat(MediaFormat.MP3);
265239
builder.setAverageBitrate(128);
266240
} else if (preset.contains("opus")) {
@@ -283,39 +257,6 @@ private void extractAudioStreams(@Nonnull final JsonArray transcodings,
283257
});
284258
}
285259

286-
/**
287-
* Add the downloadable format if it is available.
288-
*
289-
* <p>
290-
* A track can have the {@code downloadable} boolean set to {@code true}, but it doesn't mean
291-
* we can download it.
292-
* </p>
293-
*
294-
* <p>
295-
* If the value of the {@code has_download_left} boolean is {@code true}, the track can be
296-
* downloaded, and not otherwise.
297-
* </p>
298-
*
299-
* @param audioStreams the audio streams to which the downloadable file is added
300-
*/
301-
public void extractDownloadableFileIfAvailable(final List<AudioStream> audioStreams) {
302-
if (track.getBoolean("downloadable") && track.getBoolean("has_downloads_left")) {
303-
try {
304-
final String downloadUrl = getDownloadUrl(getId());
305-
if (!isNullOrEmpty(downloadUrl)) {
306-
audioStreams.add(new AudioStream.Builder()
307-
.setId("original-format")
308-
.setContent(downloadUrl, true)
309-
.setAverageBitrate(UNKNOWN_BITRATE)
310-
.build());
311-
}
312-
} catch (final Exception ignored) {
313-
// If something went wrong when trying to get the download URL, ignore the
314-
// exception throw because this "stream" is not necessary to play the track
315-
}
316-
}
317-
}
318-
319260
@Override
320261
public List<VideoStream> getVideoStreams() {
321262
return Collections.emptyList();

extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import static org.junit.jupiter.api.Assertions.assertEquals;
2626
import static org.junit.jupiter.api.Assertions.assertSame;
27+
import static org.junit.jupiter.api.Assertions.fail;
2728
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
2829

2930
public class SoundcloudStreamExtractorTest {
@@ -188,26 +189,33 @@ public static void setUp() throws Exception {
188189
public void testAudioStreams() throws Exception {
189190
super.testAudioStreams();
190191
final List<AudioStream> audioStreams = extractor.getAudioStreams();
191-
assertEquals(2, audioStreams.size());
192+
assertEquals(3, audioStreams.size()); // 2 MP3 streams (1 progressive, 1 HLS) and 1 OPUS
192193
audioStreams.forEach(audioStream -> {
193194
final DeliveryMethod deliveryMethod = audioStream.getDeliveryMethod();
194195
final String mediaUrl = audioStream.getContent();
195196
if (audioStream.getFormat() == MediaFormat.OPUS) {
196-
// Assert that it's an OPUS 64 kbps media URL with a single range which comes
197-
// from an HLS SoundCloud CDN
198-
ExtractorAsserts.assertContains("-hls-opus-media.sndcdn.com", mediaUrl);
199-
ExtractorAsserts.assertContains(".64.opus", mediaUrl);
200197
assertSame(DeliveryMethod.HLS, deliveryMethod,
201198
"Wrong delivery method for stream " + audioStream.getId() + ": "
202199
+ deliveryMethod);
203-
} else if (audioStream.getFormat() == MediaFormat.MP3) {
204-
// Assert that it's a MP3 128 kbps media URL which comes from a progressive
200+
// Assert it's an OPUS 64 kbps media playlist URL which comes from an HLS
205201
// SoundCloud CDN
206-
ExtractorAsserts.assertContains("-media.sndcdn.com/bKOA7Pwbut93.128.mp3",
207-
mediaUrl);
208-
assertSame(DeliveryMethod.PROGRESSIVE_HTTP, deliveryMethod,
209-
"Wrong delivery method for stream " + audioStream.getId() + ": "
210-
+ deliveryMethod);
202+
ExtractorAsserts.assertContains("-hls-opus-media.sndcdn.com", mediaUrl);
203+
ExtractorAsserts.assertContains(".64.opus", mediaUrl);
204+
} else if (audioStream.getFormat() == MediaFormat.MP3) {
205+
if (deliveryMethod == DeliveryMethod.PROGRESSIVE_HTTP) {
206+
// Assert it's a MP3 128 kbps media URL which comes from a progressive
207+
// SoundCloud CDN
208+
ExtractorAsserts.assertContains("-media.sndcdn.com/bKOA7Pwbut93.128.mp3",
209+
mediaUrl);
210+
} else if (deliveryMethod == DeliveryMethod.HLS) {
211+
// Assert it's a MP3 128 kbps media HLS playlist URL which comes from an HLS
212+
// SoundCloud CDN
213+
ExtractorAsserts.assertContains("-hls-media.sndcdn.com", mediaUrl);
214+
ExtractorAsserts.assertContains(".128.mp3", mediaUrl);
215+
} else {
216+
fail("Wrong delivery method for stream " + audioStream.getId() + ": "
217+
+ deliveryMethod);
218+
}
211219
}
212220
});
213221
}

0 commit comments

Comments
 (0)