Skip to content

Commit 8e53fda

Browse files
committed
[SoundCloud] Fix getAudioStreams 401 response
Fix TeamNewPipe/NewPipe#2823
1 parent 8cb3250 commit 8e53fda

1 file changed

Lines changed: 41 additions & 6 deletions

File tree

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

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.schabi.newpipe.extractor.services.soundcloud;
22

3+
import com.grack.nanojson.JsonArray;
34
import com.grack.nanojson.JsonObject;
45
import com.grack.nanojson.JsonParser;
56
import com.grack.nanojson.JsonParserException;
@@ -143,7 +144,7 @@ public List<AudioStream> getAudioStreams() throws IOException, ExtractionExcepti
143144
List<AudioStream> audioStreams = new ArrayList<>();
144145
Downloader dl = NewPipe.getDownloader();
145146

146-
String apiUrl = "https://api.soundcloud.com/i1/tracks/" + urlEncode(getId()) + "/streams"
147+
String apiUrl = "https://api-v2.soundcloud.com/tracks/" + urlEncode(getId())
147148
+ "?client_id=" + urlEncode(SoundcloudParsingHelper.clientId());
148149

149150
String response = dl.get(apiUrl, getExtractorLocalization()).responseBody();
@@ -154,11 +155,45 @@ public List<AudioStream> getAudioStreams() throws IOException, ExtractionExcepti
154155
throw new ParsingException("Could not parse json response", e);
155156
}
156157

157-
String mp3Url = responseObject.getString("http_mp3_128_url");
158-
if (mp3Url != null && !mp3Url.isEmpty()) {
159-
audioStreams.add(new AudioStream(mp3Url, MediaFormat.MP3, 128));
160-
} else {
161-
throw new ExtractionException("Could not get SoundCloud's track audio url");
158+
// Streams can be streamable and downloadable - or explicitly not.
159+
// For playing the track, it is only necessary to have a streamable track.
160+
// If this is not the case, this track might not be published yet.
161+
if (!responseObject.getBoolean("streamable")) return audioStreams;
162+
163+
try {
164+
JsonArray transcodings = responseObject.getObject("media").getArray("transcodings");
165+
166+
// get information about what stream formats are available
167+
for (Object transcoding : transcodings) {
168+
169+
JsonObject t = (JsonObject) transcoding;
170+
String url = t.getString("url");
171+
172+
if (url != null && !url.isEmpty()) {
173+
174+
// We can only play the mp3 format, but not handle m3u playlists / streams.
175+
// what about Opus?
176+
if (t.getString("preset").contains("mp3")
177+
&& t.getObject("format").getString("protocol").equals("progressive")) {
178+
// This url points to the endpoint which generates a unique and short living url to the stream.
179+
// TODO: move this to a separate method to generate valid urls when needed (e.g. resuming a paused stream)
180+
url += "?client_id=" + SoundcloudParsingHelper.clientId();
181+
String res = dl.get(url).responseBody();
182+
183+
try {
184+
JsonObject mp3UrlObject = JsonParser.object().from(res);
185+
// Links in this file are also only valid for a short period.
186+
audioStreams.add(new AudioStream(mp3UrlObject.getString("url"),
187+
MediaFormat.MP3, 128));
188+
} catch (JsonParserException e) {
189+
throw new ParsingException("Could not parse streamable url", e);
190+
}
191+
}
192+
}
193+
}
194+
195+
} catch (NullPointerException e) {
196+
throw new ExtractionException("Could not get SoundCloud's track audio url", e);
162197
}
163198

164199
return audioStreams;

0 commit comments

Comments
 (0)