Skip to content

Commit e2b7cb9

Browse files
committed
Add SoundcloudChartsExtractor
1 parent 5119dab commit e2b7cb9

6 files changed

Lines changed: 254 additions & 8 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.schabi.newpipe.extractor.services.soundcloud;
2+
3+
import java.io.IOException;
4+
5+
import org.schabi.newpipe.extractor.StreamingService;
6+
import org.schabi.newpipe.extractor.UrlIdHandler;
7+
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
8+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
9+
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
10+
import org.schabi.newpipe.extractor.stream.StreamInfoItemCollector;
11+
12+
public class SoundcloudChartsExtractor extends KioskExtractor {
13+
private String url;
14+
15+
public SoundcloudChartsExtractor(StreamingService service, String url, String nextStreamsUrl) throws IOException, ExtractionException {
16+
super(service, url, nextStreamsUrl);
17+
this.url = url;
18+
}
19+
20+
@Override
21+
public void fetchPage() {
22+
}
23+
24+
@Override
25+
public String getType() throws ParsingException {
26+
return getUrlIdHandler().getId(url);
27+
}
28+
29+
@Override
30+
public UrlIdHandler getUrlIdHandler() {
31+
return new SoundcloudChartsUrlIdHandler();
32+
}
33+
34+
@Override
35+
public NextItemsResult getNextStreams() throws IOException, ExtractionException {
36+
if (!hasMoreStreams()) {
37+
throw new ExtractionException("Chart doesn't have more streams");
38+
}
39+
40+
StreamInfoItemCollector collector = new StreamInfoItemCollector(getServiceId());
41+
nextStreamsUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, nextStreamsUrl, true);
42+
43+
return new NextItemsResult(collector.getItemList(), nextStreamsUrl);
44+
}
45+
46+
@Override
47+
public StreamInfoItemCollector getStreams() throws IOException, ExtractionException {
48+
StreamInfoItemCollector collector = new StreamInfoItemCollector(getServiceId());
49+
50+
String apiUrl = "https://api-v2.soundcloud.com/charts" +
51+
"?genre=soundcloud:genres:all-music" +
52+
"&client_id=" + SoundcloudParsingHelper.clientId();
53+
54+
if (getType().equals("Top 50")) {
55+
apiUrl += "&kind=top";
56+
} else {
57+
apiUrl += "&kind=new";
58+
}
59+
60+
nextStreamsUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl, true);
61+
return collector;
62+
}
63+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.schabi.newpipe.extractor.services.soundcloud;
2+
3+
import org.schabi.newpipe.extractor.UrlIdHandler;
4+
import org.schabi.newpipe.extractor.utils.Parser;
5+
6+
public class SoundcloudChartsUrlIdHandler implements UrlIdHandler {
7+
public String getUrl(String id) {
8+
if (id.equals("Top 50")) {
9+
return "https://soundcloud.com/charts/top";
10+
} else {
11+
return "https://soundcloud.com/charts/new";
12+
}
13+
}
14+
15+
@Override
16+
public String getId(String url) {
17+
if (Parser.isMatch("^https?://(www\\.)?soundcloud.com/charts(/top)?/?([#?].*)?$", url.toLowerCase())) {
18+
return "Top 50";
19+
} else {
20+
return "New & hot";
21+
}
22+
}
23+
24+
@Override
25+
public String cleanUrl(String url) {
26+
if (Parser.isMatch("^https?://(www\\.)?soundcloud.com/charts(/top)?/?([#?].*)?$", url.toLowerCase())) {
27+
return "https://soundcloud.com/charts/top";
28+
} else {
29+
return "https://soundcloud.com/charts/new";
30+
}
31+
}
32+
33+
@Override
34+
public boolean acceptUrl(String url) {
35+
return Parser.isMatch("^https?://(www\\.)?soundcloud.com/charts(/top|/new)?/?([#?].*)?$", url.toLowerCase());
36+
}
37+
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,17 @@ public static String getStreamsFromApiMinItems(int minItems, StreamInfoItemColle
121121
*
122122
* @return the next streams url, empty if don't have
123123
*/
124-
public static String getStreamsFromApi(StreamInfoItemCollector collector, String apiUrl) throws IOException, ReCaptchaException, ParsingException {
124+
public static String getStreamsFromApi(StreamInfoItemCollector collector, String apiUrl, boolean charts) throws IOException, ReCaptchaException, ParsingException {
125125
String response = NewPipe.getDownloader().download(apiUrl);
126126
JSONObject responseObject = new JSONObject(response);
127127

128128
JSONArray responseCollection = responseObject.getJSONArray("collection");
129129
for (int i = 0; i < responseCollection.length(); i++) {
130-
collector.commit(new SoundcloudStreamInfoItemExtractor(responseCollection.getJSONObject(i)));
130+
if (charts) {
131+
collector.commit(new SoundcloudStreamInfoItemExtractor(responseCollection.getJSONObject(i).getJSONObject("track")));
132+
} else {
133+
collector.commit(new SoundcloudStreamInfoItemExtractor(responseCollection.getJSONObject(i)));
134+
}
131135
}
132136

133137
String nextStreamsUrl;
@@ -140,4 +144,8 @@ public static String getStreamsFromApi(StreamInfoItemCollector collector, String
140144

141145
return nextStreamsUrl;
142146
}
147+
148+
public static String getStreamsFromApi(StreamInfoItemCollector collector, String apiUrl) throws ReCaptchaException, ParsingException, IOException {
149+
return getStreamsFromApi(collector, apiUrl, false);
150+
}
143151
}

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

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

3+
import java.io.IOException;
4+
35
import org.schabi.newpipe.extractor.StreamingService;
46
import org.schabi.newpipe.extractor.SuggestionExtractor;
57
import org.schabi.newpipe.extractor.UrlIdHandler;
68
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
79
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
8-
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
910
import org.schabi.newpipe.extractor.kiosk.KioskList;
1011
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
1112
import org.schabi.newpipe.extractor.search.SearchEngine;
1213
import org.schabi.newpipe.extractor.stream.StreamExtractor;
1314

14-
import java.io.IOException;
15-
1615
public class SoundcloudService extends StreamingService {
1716

1817
public SoundcloudService(int id, String name) {
@@ -61,12 +60,17 @@ public SuggestionExtractor getSuggestionExtractor() {
6160
}
6261

6362
@Override
64-
public KioskList getKioskList() {
63+
public KioskList getKioskList() throws ExtractionException {
6564
KioskList list = new KioskList(getServiceId());
6665

6766
// add kiosks here e.g.:
68-
//list.addKioskEntry("trinding", new TrendingKiosk(), new TrendingUrlIdHandler());
69-
67+
SoundcloudChartsUrlIdHandler h = new SoundcloudChartsUrlIdHandler();
68+
try {
69+
list.addKioskEntry(new SoundcloudChartsExtractor(this, h.getUrl("Top 50"), null), h);
70+
list.addKioskEntry(new SoundcloudChartsExtractor(this, h.getUrl("New & hot"), null), h);
71+
} catch (Exception e) {
72+
throw new ExtractionException(e);
73+
}
7074

7175
return list;
7276
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.schabi.newpipe.extractor.services.soundcloud;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertNotNull;
6+
import static org.junit.Assert.assertTrue;
7+
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
8+
9+
import org.junit.Before;
10+
import org.junit.Test;
11+
import org.schabi.newpipe.Downloader;
12+
import org.schabi.newpipe.extractor.InfoItemCollector;
13+
import org.schabi.newpipe.extractor.NewPipe;
14+
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
15+
16+
/**
17+
* Test for {@link SoundcloudChartsUrlIdHandler}
18+
*/
19+
public class SoundcloudChartsExtractorTest {
20+
21+
KioskExtractor extractor;
22+
23+
@Before
24+
public void setUp() throws Exception {
25+
NewPipe.init(Downloader.getInstance());
26+
extractor = SoundCloud.getService()
27+
.getKioskList()
28+
.getExtractorByType("Top 50");
29+
extractor.fetchPage();
30+
}
31+
32+
@Test
33+
public void testGetDownloader() throws Exception {
34+
assertNotNull(NewPipe.getDownloader());
35+
}
36+
37+
@Test
38+
public void testGetName() throws Exception {
39+
assertEquals(extractor.getName(), "Top 50");
40+
}
41+
42+
@Test
43+
public void testId() throws Exception {
44+
assertEquals(extractor.getId(), "Top 50");
45+
}
46+
47+
@Test
48+
public void testGetStreams() throws Exception {
49+
InfoItemCollector collector = extractor.getStreams();
50+
if(!collector.getErrors().isEmpty()) {
51+
System.err.println("----------");
52+
for(Throwable e : collector.getErrors()) {
53+
e.printStackTrace();
54+
System.err.println("----------");
55+
}
56+
}
57+
assertTrue("no streams are received",
58+
!collector.getItemList().isEmpty()
59+
&& collector.getErrors().isEmpty());
60+
}
61+
62+
@Test
63+
public void testGetStreamsErrors() throws Exception {
64+
assertTrue("errors during stream list extraction", extractor.getStreams().getErrors().isEmpty());
65+
}
66+
67+
@Test
68+
public void testHasMoreStreams() throws Exception {
69+
// Setup the streams
70+
extractor.getStreams();
71+
assertTrue("has more streams", extractor.hasMoreStreams());
72+
}
73+
74+
@Test
75+
public void testGetNextStreams() throws Exception {
76+
extractor.getStreams();
77+
assertFalse("extractor has next streams", extractor.getNextStreams() == null
78+
|| extractor.getNextStreams().nextItemsList.isEmpty());
79+
}
80+
81+
@Test
82+
public void testGetCleanUrl() throws Exception {
83+
assertEquals(extractor.getCleanUrl(), "https://soundcloud.com/charts/top");
84+
}
85+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.schabi.newpipe.extractor.services.soundcloud;
2+
3+
import static junit.framework.TestCase.assertFalse;
4+
import static org.junit.Assert.assertEquals;
5+
import static org.junit.Assert.assertTrue;
6+
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
import org.schabi.newpipe.Downloader;
10+
import org.schabi.newpipe.extractor.NewPipe;
11+
12+
/**
13+
* Test for {@link SoundcloudChartsUrlIdHandler}
14+
*/
15+
public class SoundcloudChartsUrlIdHandlerTest {
16+
private SoundcloudChartsUrlIdHandler urlIdHandler;
17+
18+
@Before
19+
public void setUp() throws Exception {
20+
urlIdHandler = new SoundcloudChartsUrlIdHandler();
21+
NewPipe.init(Downloader.getInstance());
22+
}
23+
24+
@Test
25+
public void getUrl() {
26+
assertEquals(urlIdHandler.getUrl("Top 50"), "https://soundcloud.com/charts/top");
27+
assertEquals(urlIdHandler.getUrl("New & hot"), "https://soundcloud.com/charts/new");
28+
}
29+
30+
@Test
31+
public void getId() {
32+
assertEquals(urlIdHandler.getId("http://soundcloud.com/charts/top?genre=all-music"), "Top 50");
33+
assertEquals(urlIdHandler.getId("HTTP://www.soundcloud.com/charts/new/?genre=all-music&country=all-countries"), "New & hot");
34+
}
35+
36+
@Test
37+
public void acceptUrl() {
38+
assertTrue(urlIdHandler.acceptUrl("https://soundcloud.com/charts"));
39+
assertTrue(urlIdHandler.acceptUrl("https://soundcloud.com/charts/"));
40+
assertTrue(urlIdHandler.acceptUrl("https://www.soundcloud.com/charts/new"));
41+
assertTrue(urlIdHandler.acceptUrl("http://soundcloud.com/charts/top?genre=all-music"));
42+
assertTrue(urlIdHandler.acceptUrl("HTTP://www.soundcloud.com/charts/new/?genre=all-music&country=all-countries"));
43+
44+
assertFalse(urlIdHandler.acceptUrl("kdskjfiiejfia"));
45+
assertFalse(urlIdHandler.acceptUrl("soundcloud.com/charts askjkf"));
46+
assertFalse(urlIdHandler.acceptUrl(" soundcloud.com/charts"));
47+
assertFalse(urlIdHandler.acceptUrl(""));
48+
}
49+
}

0 commit comments

Comments
 (0)