Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SoundCloud] Use a lightweight request to check if the hardcoded client_id is valid, fix the extraction of mobile URLs and more #627

Merged
merged 5 commits into from
May 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.*;
import org.schabi.newpipe.extractor.localization.ContentCountry;
Expand All @@ -23,7 +22,7 @@

public class SoundcloudService extends StreamingService {

public SoundcloudService(int id) {
public SoundcloudService(final int id) {
super(id, "SoundCloud", asList(AUDIO, COMMENTS));
}

Expand Down Expand Up @@ -54,29 +53,29 @@ public ListLinkHandlerFactory getPlaylistLHFactory() {

@Override
public List<ContentCountry> getSupportedCountries() {
//Country selector here https://soundcloud.com/charts/top?genre=all-music
// Country selector here: https://soundcloud.com/charts/top?genre=all-music
return ContentCountry.listFrom(
"AU", "CA", "DE", "FR", "GB", "IE", "NL", "NZ", "US"
);
}

@Override
public StreamExtractor getStreamExtractor(LinkHandler LinkHandler) {
return new SoundcloudStreamExtractor(this, LinkHandler);
public StreamExtractor getStreamExtractor(final LinkHandler linkHandler) {
return new SoundcloudStreamExtractor(this, linkHandler);
}

@Override
public ChannelExtractor getChannelExtractor(ListLinkHandler linkHandler) {
public ChannelExtractor getChannelExtractor(final ListLinkHandler linkHandler) {
return new SoundcloudChannelExtractor(this, linkHandler);
}

@Override
public PlaylistExtractor getPlaylistExtractor(ListLinkHandler linkHandler) {
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
return new SoundcloudPlaylistExtractor(this, linkHandler);
}

@Override
public SearchExtractor getSearchExtractor(SearchQueryHandler queryHandler) {
public SearchExtractor getSearchExtractor(final SearchQueryHandler queryHandler) {
return new SoundcloudSearchExtractor(this, queryHandler);
}

Expand All @@ -87,26 +86,19 @@ public SoundcloudSuggestionExtractor getSuggestionExtractor() {

@Override
public KioskList getKioskList() throws ExtractionException {
KioskList.KioskExtractorFactory chartsFactory = new KioskList.KioskExtractorFactory() {
@Override
public KioskExtractor createNewKiosk(StreamingService streamingService,
String url,
String id)
throws ExtractionException {
return new SoundcloudChartsExtractor(SoundcloudService.this,
final KioskList.KioskExtractorFactory chartsFactory = (streamingService, url, id) ->
new SoundcloudChartsExtractor(SoundcloudService.this,
new SoundcloudChartsLinkHandlerFactory().fromUrl(url), id);
}
};

KioskList list = new KioskList(this);
final KioskList list = new KioskList(this);

// add kiosks here e.g.:
final SoundcloudChartsLinkHandlerFactory h = new SoundcloudChartsLinkHandlerFactory();
try {
list.addKioskEntry(chartsFactory, h, "Top 50");
list.addKioskEntry(chartsFactory, h, "New & hot");
list.setDefaultKiosk("New & hot");
} catch (Exception e) {
} catch (final Exception e) {
throw new ExtractionException(e);
}

Expand All @@ -124,9 +116,8 @@ public ListLinkHandlerFactory getCommentsLHFactory() {
}

@Override
public CommentsExtractor getCommentsExtractor(ListLinkHandler linkHandler)
public CommentsExtractor getCommentsExtractor(final ListLinkHandler linkHandler)
throws ExtractionException {
return new SoundcloudCommentsExtractor(this, linkHandler);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,33 @@
import javax.annotation.Nonnull;
import java.io.IOException;

import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.SOUNDCLOUD_API_V2_URL;
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;

@SuppressWarnings("WeakerAccess")
public class SoundcloudChannelExtractor extends ChannelExtractor {
private String userId;
private JsonObject user;
private static final String USERS_ENDPOINT = SOUNDCLOUD_API_V2_URL + "users/";

public SoundcloudChannelExtractor(final StreamingService service, final ListLinkHandler linkHandler) {
public SoundcloudChannelExtractor(final StreamingService service,
final ListLinkHandler linkHandler) {
super(service, linkHandler);
}

@Override
public void onFetchPage(@Nonnull final Downloader downloader) throws IOException, ExtractionException {
public void onFetchPage(@Nonnull final Downloader downloader) throws IOException,
ExtractionException {

userId = getLinkHandler().getId();
final String apiUrl = "https://api-v2.soundcloud.com/users/" + userId +
"?client_id=" + SoundcloudParsingHelper.clientId();
final String apiUrl = USERS_ENDPOINT + userId + "?client_id="
+ SoundcloudParsingHelper.clientId();

final String response = downloader.get(apiUrl, getExtractorLocalization()).responseBody();
try {
user = JsonParser.object().from(response);
} catch (JsonParserException e) {
} catch (final JsonParserException e) {
throw new ParsingException("Could not parse json response", e);
}
}
Expand All @@ -63,7 +67,8 @@ public String getAvatarUrl() {

@Override
public String getBannerUrl() {
return user.getObject("visuals").getArray("visuals").getObject(0).getString("visual_url");
return user.getObject("visuals").getArray("visuals").getObject(0)
.getString("visual_url");
}

@Override
Expand Down Expand Up @@ -105,29 +110,31 @@ public boolean isVerified() throws ParsingException {
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws ExtractionException {
try {
final StreamInfoItemsCollector streamInfoItemsCollector = new StreamInfoItemsCollector(getServiceId());
final StreamInfoItemsCollector streamInfoItemsCollector =
new StreamInfoItemsCollector(getServiceId());

final String apiUrl = "https://api-v2.soundcloud.com/users/" + getId() + "/tracks"
+ "?client_id=" + SoundcloudParsingHelper.clientId()
+ "&limit=20"
+ "&linked_partitioning=1";
final String apiUrl = USERS_ENDPOINT + getId() + "/tracks" + "?client_id="
+ SoundcloudParsingHelper.clientId() + "&limit=20" + "&linked_partitioning=1";

final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApiMinItems(15, streamInfoItemsCollector, apiUrl);
final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApiMinItems(15,
streamInfoItemsCollector, apiUrl);

return new InfoItemsPage<>(streamInfoItemsCollector, new Page(nextPageUrl));
} catch (Exception e) {
} catch (final Exception e) {
throw new ExtractionException("Could not get next page", e);
}
}

@Override
public InfoItemsPage<StreamInfoItem> getPage(final Page page) throws IOException, ExtractionException {
public InfoItemsPage<StreamInfoItem> getPage(final Page page) throws IOException,
ExtractionException {
if (page == null || isNullOrEmpty(page.getUrl())) {
throw new IllegalArgumentException("Page doesn't contain an URL");
}

final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApiMinItems(15, collector, page.getUrl());
final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApiMinItems(15, collector,
page.getUrl());

return new InfoItemsPage<>(collector, new Page(nextPageUrl));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
public class SoundcloudChannelInfoItemExtractor implements ChannelInfoItemExtractor {
private final JsonObject itemObject;

public SoundcloudChannelInfoItemExtractor(JsonObject itemObject) {
public SoundcloudChannelInfoItemExtractor(final JsonObject itemObject) {
this.itemObject = itemObject;
}

Expand All @@ -26,8 +26,8 @@ public String getUrl() {
@Override
public String getThumbnailUrl() {
String avatarUrl = itemObject.getString("avatar_url", EMPTY_STRING);
String avatarUrlBetterResolution = avatarUrl.replace("large.jpg", "crop.jpg");
return avatarUrlBetterResolution;
// An avatar URL with a better resolution
return avatarUrl.replace("large.jpg", "crop.jpg");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@
import java.io.IOException;

import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.SOUNDCLOUD_API_V2_URL;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;

public class SoundcloudChartsExtractor extends KioskExtractor<StreamInfoItem> {
public SoundcloudChartsExtractor(StreamingService service,
ListLinkHandler linkHandler,
String kioskId) {
public SoundcloudChartsExtractor(final StreamingService service,
final ListLinkHandler linkHandler,
final String kioskId) {
super(service, linkHandler, kioskId);
}

@Override
public void onFetchPage(@Nonnull Downloader downloader) {
public void onFetchPage(@Nonnull final Downloader downloader) {
}

@Nonnull
Expand All @@ -35,13 +36,15 @@ public String getName() {
}

@Override
public InfoItemsPage<StreamInfoItem> getPage(final Page page) throws IOException, ExtractionException {
public InfoItemsPage<StreamInfoItem> getPage(final Page page) throws IOException,
ExtractionException {
if (page == null || isNullOrEmpty(page.getUrl())) {
throw new IllegalArgumentException("Page doesn't contain an URL");
}

final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, page.getUrl(), true);
final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector,
page.getUrl(), true);

return new InfoItemsPage<>(collector, new Page(nextPageUrl));
}
Expand All @@ -51,9 +54,8 @@ public InfoItemsPage<StreamInfoItem> getPage(final Page page) throws IOException
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException {
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());

String apiUrl = "https://api-v2.soundcloud.com/charts" +
"?genre=soundcloud:genres:all-music" +
"&client_id=" + SoundcloudParsingHelper.clientId();
String apiUrl = SOUNDCLOUD_API_V2_URL + "charts" + "?genre=soundcloud:genres:all-music"
+ "&client_id=" + SoundcloudParsingHelper.clientId();

if (getId().equals("Top 50")) {
apiUrl += "&kind=top";
Expand All @@ -64,15 +66,18 @@ public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, Extrac
final ContentCountry contentCountry = SoundCloud.getContentCountry();
String apiUrlWithRegion = null;
if (getService().getSupportedCountries().contains(contentCountry)) {
apiUrlWithRegion = apiUrl + "&region=soundcloud:regions:" + contentCountry.getCountryCode();
apiUrlWithRegion = apiUrl + "&region=soundcloud:regions:"
+ contentCountry.getCountryCode();
}

String nextPageUrl;
try {
nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrlWithRegion == null ? apiUrl : apiUrlWithRegion, true);
} catch (IOException e) {
// Request to other region may be geo-restricted. See https://github.com/TeamNewPipe/NewPipeExtractor/issues/537
// we retry without the specified region.
nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector,
apiUrlWithRegion == null ? apiUrl : apiUrlWithRegion, true);
} catch (final IOException e) {
// Request to other region may be geo-restricted.
// See https://github.com/TeamNewPipe/NewPipeExtractor/issues/537.
// We retry without the specified region.
nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,36 @@
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;

public class SoundcloudCommentsExtractor extends CommentsExtractor {
public SoundcloudCommentsExtractor(final StreamingService service, final ListLinkHandler uiHandler) {
public SoundcloudCommentsExtractor(final StreamingService service,
final ListLinkHandler uiHandler) {
super(service, uiHandler);
}

@Nonnull
@Override
public InfoItemsPage<CommentsInfoItem> getInitialPage() throws ExtractionException, IOException {
public InfoItemsPage<CommentsInfoItem> getInitialPage() throws ExtractionException,
IOException {
final Downloader downloader = NewPipe.getDownloader();
final Response response = downloader.get(getUrl());

final JsonObject json;
try {
json = JsonParser.object().from(response.responseBody());
} catch (JsonParserException e) {
} catch (final JsonParserException e) {
throw new ParsingException("Could not parse json", e);
}

final CommentsInfoItemsCollector collector = new CommentsInfoItemsCollector(getServiceId());
final CommentsInfoItemsCollector collector = new CommentsInfoItemsCollector(
getServiceId());

collectStreamsFrom(collector, json.getArray("collection"));

return new InfoItemsPage<>(collector, new Page(json.getString("next_href")));
}

@Override
public InfoItemsPage<CommentsInfoItem> getPage(final Page page) throws ExtractionException, IOException {
public InfoItemsPage<CommentsInfoItem> getPage(final Page page) throws ExtractionException,
IOException {
if (page == null || isNullOrEmpty(page.getUrl())) {
throw new IllegalArgumentException("Page doesn't contain an URL");
}
Expand All @@ -60,11 +64,12 @@ public InfoItemsPage<CommentsInfoItem> getPage(final Page page) throws Extractio
final JsonObject json;
try {
json = JsonParser.object().from(response.responseBody());
} catch (JsonParserException e) {
} catch (final JsonParserException e) {
throw new ParsingException("Could not parse json", e);
}

final CommentsInfoItemsCollector collector = new CommentsInfoItemsCollector(getServiceId());
final CommentsInfoItemsCollector collector = new CommentsInfoItemsCollector(
getServiceId());

collectStreamsFrom(collector, json.getArray("collection"));

Expand All @@ -74,9 +79,10 @@ public InfoItemsPage<CommentsInfoItem> getPage(final Page page) throws Extractio
@Override
public void onFetchPage(@Nonnull final Downloader downloader) { }

private void collectStreamsFrom(final CommentsInfoItemsCollector collector, final JsonArray entries) throws ParsingException {
private void collectStreamsFrom(final CommentsInfoItemsCollector collector,
final JsonArray entries) throws ParsingException {
final String url = getUrl();
for (Object comment : entries) {
for (final Object comment : entries) {
collector.commit(new SoundcloudCommentsInfoItemExtractor((JsonObject) comment, url));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import java.util.Objects;

public class SoundcloudCommentsInfoItemExtractor implements CommentsInfoItemExtractor {
private JsonObject json;
private String url;
private final JsonObject json;
private final String url;

public SoundcloudCommentsInfoItemExtractor(JsonObject json, String url) {
public SoundcloudCommentsInfoItemExtractor(final JsonObject json, final String url) {
this.json = json;
this.url = url;
}
Expand Down
Loading