Skip to content

Commit 7607688

Browse files
committed
[Soundcloud] Remove DRM-protected and downloadable formats extraction
DRM-protected streams have been added to some tracks, mostly from major music companies. We do not support DRM streams in the extractor, so they shouldn't be extracted and so waste time, energy and resources. Extracting downloadable format requires login for a pretty long time, so there is no point again to do requests to extract this stream to get an unauthorized response. Also send the track_authorization property returned in the track info, like the website does and allow duplicate MP3 formats in progressive and HLS delivery methods to be returned.
1 parent 3a33cef commit 7607688

1 file changed

Lines changed: 18 additions & 77 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();

0 commit comments

Comments
 (0)