Skip to content

Commit d758273

Browse files
committed
merged upstream/dev
2 parents f60c973 + 514ed7b commit d758273

58 files changed

Lines changed: 1225 additions & 341 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

extractor/src/main/java/org/schabi/newpipe/extractor/DownloadResponse.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@
77
import javax.annotation.Nonnull;
88

99
public class DownloadResponse {
10+
private final int responseCode;
1011
private final String responseBody;
1112
private final Map<String, List<String>> responseHeaders;
1213

13-
public DownloadResponse(String responseBody, Map<String, List<String>> headers) {
14+
public DownloadResponse(int responseCode, String responseBody, Map<String, List<String>> headers) {
1415
super();
16+
this.responseCode = responseCode;
1517
this.responseBody = responseBody;
1618
this.responseHeaders = headers;
1719
}
1820

21+
public int getResponseCode() {
22+
return responseCode;
23+
}
24+
1925
public String getResponseBody() {
2026
return responseBody;
2127
}
@@ -33,5 +39,4 @@ public List<String> getResponseCookies(){
3339
else
3440
return cookies;
3541
}
36-
3742
}

extractor/src/main/java/org/schabi/newpipe/extractor/Downloader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ public interface Downloader {
6060
*/
6161
String download(String siteUrl) throws IOException, ReCaptchaException;
6262

63+
DownloadResponse head(String siteUrl) throws IOException, ReCaptchaException;
64+
65+
DownloadResponse get(String siteUrl, Localization localization)
66+
throws IOException, ReCaptchaException;
67+
6368
DownloadResponse get(String siteUrl, DownloadRequest request)
6469
throws IOException, ReCaptchaException;
6570

extractor/src/main/java/org/schabi/newpipe/extractor/exceptions/ReCaptchaException.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@
2121
*/
2222

2323
public class ReCaptchaException extends ExtractionException {
24-
public ReCaptchaException(String message) {
24+
private String url;
25+
26+
public ReCaptchaException(String message, String url) {
2527
super(message);
28+
this.url = url;
29+
}
30+
31+
public String getUrl() {
32+
return url;
2633
}
2734
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ public String getUrl() {
2424

2525
@Override
2626
public String getThumbnailUrl() {
27-
return itemObject.getString("avatar_url", "");
27+
String avatarUrl = itemObject.getString("avatar_url", "");
28+
String avatarUrlBetterResolution = avatarUrl.replace("large.jpg", "crop.jpg");
29+
return avatarUrlBetterResolution;
2830
}
2931

3032
@Override

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

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
import org.jsoup.Jsoup;
88
import org.jsoup.nodes.Document;
99
import org.jsoup.nodes.Element;
10+
import org.jsoup.select.Elements;
11+
import org.schabi.newpipe.extractor.DownloadResponse;
1012
import org.schabi.newpipe.extractor.Downloader;
1113
import org.schabi.newpipe.extractor.NewPipe;
1214
import org.schabi.newpipe.extractor.channel.ChannelInfoItemsCollector;
15+
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
1316
import org.schabi.newpipe.extractor.exceptions.ParsingException;
1417
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
1518
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
@@ -21,40 +24,59 @@
2124
import java.net.URLEncoder;
2225
import java.text.ParseException;
2326
import java.text.SimpleDateFormat;
27+
import java.util.Collections;
2428
import java.util.Date;
2529
import java.util.HashMap;
2630

2731
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
2832

2933
public class SoundcloudParsingHelper {
34+
private static final String HARDCODED_CLIENT_ID = "LHzSAKe8eP9Yy3FgBugfBapRPLncO6Ng"; // Updated on 22/10/19
3035
private static String clientId;
3136

3237
private SoundcloudParsingHelper() {
3338
}
3439

35-
public static String clientId() throws ReCaptchaException, IOException, RegexException {
40+
public static String clientId() throws ExtractionException, IOException {
3641
if (clientId != null && !clientId.isEmpty()) return clientId;
3742

3843
Downloader dl = NewPipe.getDownloader();
39-
String response = dl.download("https://soundcloud.com");
40-
41-
Document doc = Jsoup.parse(response);
42-
Element jsElement = doc.select("script[src^=https://a-v2.sndcdn.com/assets/app]").first();
44+
clientId = HARDCODED_CLIENT_ID;
45+
if (checkIfHardcodedClientIdIsValid(dl)) {
46+
return clientId;
47+
}
4348

49+
final DownloadResponse download = dl.get("https://soundcloud.com");
50+
String response = download.getResponseBody();
4451
final String clientIdPattern = ",client_id:\"(.*?)\"";
4552

46-
try {
47-
final HashMap<String, String> headers = new HashMap<>();
48-
headers.put("Range", "bytes=0-16384");
49-
String js = dl.download(jsElement.attr("src"), headers);
50-
51-
return clientId = Parser.matchGroup1(clientIdPattern, js);
52-
} catch (IOException | RegexException ignored) {
53-
// Ignore it and proceed to download the whole js file
53+
Document doc = Jsoup.parse(response);
54+
final Elements possibleScripts = doc.select("script[src*=\"sndcdn.com/assets/\"][src$=\".js\"]");
55+
// The one containing the client id will likely be the last one
56+
Collections.reverse(possibleScripts);
57+
58+
final HashMap<String, String> headers = new HashMap<>();
59+
headers.put("Range", "bytes=0-16384");
60+
61+
for (Element element : possibleScripts) {
62+
final String srcUrl = element.attr("src");
63+
if (srcUrl != null && !srcUrl.isEmpty()) {
64+
try {
65+
return clientId = Parser.matchGroup1(clientIdPattern, dl.download(srcUrl, headers));
66+
} catch (RegexException ignored) {
67+
// Ignore it and proceed to try searching other script
68+
}
69+
}
5470
}
5571

56-
String js = dl.download(jsElement.attr("src"));
57-
return clientId = Parser.matchGroup1(clientIdPattern, js);
72+
// Officially give up
73+
throw new ExtractionException("Couldn't extract client id");
74+
}
75+
76+
static boolean checkIfHardcodedClientIdIsValid(Downloader dl) throws IOException, ReCaptchaException {
77+
final String apiUrl = "https://api.soundcloud.com/connect?client_id=" + HARDCODED_CLIENT_ID;
78+
// Should return 200 to indicate that the client id is valid, a 401 is returned otherwise.
79+
return dl.head(apiUrl).getResponseCode() == 200;
5880
}
5981

6082
public static String toDateString(String time) throws ParsingException {
@@ -79,7 +101,7 @@ public static String toDateString(String time) throws ParsingException {
79101
*
80102
* See https://developers.soundcloud.com/docs/api/reference#resolve
81103
*/
82-
public static JsonObject resolveFor(Downloader downloader, String url) throws IOException, ReCaptchaException, ParsingException {
104+
public static JsonObject resolveFor(Downloader downloader, String url) throws IOException, ExtractionException {
83105
String apiUrl = "https://api.soundcloud.com/resolve"
84106
+ "?url=" + URLEncoder.encode(url, "UTF-8")
85107
+ "&client_id=" + clientId();
@@ -113,7 +135,10 @@ public static String resolveIdWithEmbedPlayer(String url) throws IOException, Re
113135

114136
String response = NewPipe.getDownloader().download("https://w.soundcloud.com/player/?url="
115137
+ URLEncoder.encode(url, "UTF-8"));
116-
return Parser.matchGroup1(",\"id\":(.*?),", response);
138+
// handle playlists / sets different and get playlist id via uir field in JSON
139+
if (url.contains("sets") && !url.endsWith("sets") && !url.endsWith("sets/"))
140+
return Parser.matchGroup1("\"uri\":\\s*\"https:\\/\\/api\\.soundcloud\\.com\\/playlists\\/((\\d)*?)\"", response);
141+
return Parser.matchGroup1(",\"id\":(([^}\\n])*?),", response);
117142
}
118143

119144
/**

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,15 @@ public String getThumbnailUrl() {
7171
final String thumbnailUrl = item.getThumbnailUrl();
7272
if (thumbnailUrl == null || thumbnailUrl.isEmpty()) continue;
7373

74-
return thumbnailUrl;
74+
String thumbnailUrlBetterResolution = thumbnailUrl.replace("large.jpg", "crop.jpg");
75+
return thumbnailUrlBetterResolution;
7576
}
7677
} catch (Exception ignored) {
7778
}
7879
}
7980

80-
return artworkUrl;
81+
String artworkUrlBetterResolution = artworkUrl.replace("large.jpg", "crop.jpg");
82+
return artworkUrlBetterResolution;
8183
}
8284

8385
@Override

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ public String getThumbnailUrl() throws ParsingException {
3232
// Over-engineering at its finest
3333
if (itemObject.isString(ARTWORK_URL_KEY)) {
3434
final String artworkUrl = itemObject.getString(ARTWORK_URL_KEY, "");
35-
if (!artworkUrl.isEmpty()) return artworkUrl;
35+
if (!artworkUrl.isEmpty()) {
36+
String artworkUrlBetterResolution = artworkUrl.replace("large.jpg", "crop.jpg");
37+
return artworkUrlBetterResolution;
38+
}
3639
}
3740

3841
try {
@@ -42,8 +45,11 @@ public String getThumbnailUrl() throws ParsingException {
4245

4346
// First look for track artwork url
4447
if (trackObject.isString(ARTWORK_URL_KEY)) {
45-
final String url = trackObject.getString(ARTWORK_URL_KEY, "");
46-
if (!url.isEmpty()) return url;
48+
String artworkUrl = trackObject.getString(ARTWORK_URL_KEY, "");
49+
if (!artworkUrl.isEmpty()) {
50+
String artworkUrlBetterResolution = artworkUrl.replace("large.jpg", "crop.jpg");
51+
return artworkUrlBetterResolution;
52+
}
4753
}
4854

4955
// Then look for track creator avatar url

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

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

3+
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
34
import org.schabi.newpipe.extractor.exceptions.ParsingException;
45
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
56
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
@@ -48,10 +49,10 @@ public String getUrl(String id, List<String> contentFilter, String sortFilter) t
4849

4950
} catch (UnsupportedEncodingException e) {
5051
throw new ParsingException("Could not encode query", e);
51-
} catch (IOException e) {
52-
throw new ParsingException("Could not get client id", e);
5352
} catch (ReCaptchaException e) {
5453
throw new ParsingException("ReCaptcha required", e);
54+
} catch (IOException | ExtractionException e) {
55+
throw new ParsingException("Could not get client id", e);
5556
}
5657
}
5758

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public KioskExtractor createNewKiosk(StreamingService streamingService,
9595
try {
9696
list.addKioskEntry(chartsFactory, h, "Top 50");
9797
list.addKioskEntry(chartsFactory, h, "New & hot");
98+
list.setDefaultKiosk("New & hot");
9899
} catch (Exception e) {
99100
throw new ExtractionException(e);
100101
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ public String getUploadDate() throws ParsingException {
5757
@Nonnull
5858
@Override
5959
public String getThumbnailUrl() {
60-
return track.getString("artwork_url", "");
60+
String artworkUrl = track.getString("artwork_url", "");
61+
if (artworkUrl.isEmpty()) {
62+
artworkUrl = track.getObject("user").getString("avatar_url", "");
63+
}
64+
String artworkUrlBetterResolution = artworkUrl.replace("large.jpg", "crop.jpg");
65+
return artworkUrlBetterResolution;
6166
}
6267

6368
@Nonnull

0 commit comments

Comments
 (0)