Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public InfoItemsPage<CommentsInfoItem> getInitialPage() throws ExtractionExcepti
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");
return InfoItemsPage.emptyPage();
}
return getPage(page.getUrl());
}
Expand All @@ -63,7 +63,8 @@ private InfoItemsPage<CommentsInfoItem> getPage(@Nonnull final String url)
getServiceId());

collectStreamsFrom(collector, json.getArray("collection"));
return new InfoItemsPage<>(collector, new Page(json.getString("next_href", null)));
final String nextHref = json.getString("next_href");
return new InfoItemsPage<>(collector, isNullOrEmpty(nextHref) ? null : new Page(nextHref));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.schabi.newpipe.extractor.services.soundcloud;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.services.DefaultSimpleExtractorTest;

import java.io.IOException;

public class SoundcloudCommentsExtractorTest {

Check failure on line 18 in extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudCommentsExtractorTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add some tests to this class.

See more on https://sonarcloud.io/project/issues?id=TeamNewPipe_NewPipeExtractor&issues=AZ2KIc_byB-eWHH5fU2a&open=AZ2KIc_byB-eWHH5fU2a&pullRequest=1476

/**
* Regression test for <a href="https://github.com/TeamNewPipe/NewPipeExtractor/issues/1243">
* issue #1243</a>: when the SoundCloud API returns {@code "next_href": null} (no more pages),
* a subsequent call to {@link CommentsExtractor#getPage(Page)} with a null URL must not throw
* {@link IllegalArgumentException} ("Page doesn't contain an URL"). Instead the extractor
* must return {@link InfoItemsPage#emptyPage()}.
*
* <p>The crash manifests during pagination: the last page of comments stores
* {@code new Page(null)} as the next page, and when Paging 3 tries to fetch it the
* exception propagates and kills the app.</p>
*/
@Nested
class TrackWithComments extends DefaultSimpleExtractorTest<CommentsExtractor> {
// This track is known to reproduce issue #1243: it has comments, but when pagination
// exhausts the pages the API returns next_href=null, which previously caused a crash.
private static final String URL = "https://soundcloud.com/user-722618400/a-real-playa";

@Override
protected CommentsExtractor createExtractor() throws Exception {
return SoundCloud.getCommentsExtractor(URL);
}

/**
* The initial page must load successfully without throwing any exception.
*/
@Test
void testGetInitialPageSucceeds() throws IOException, ExtractionException {
final InfoItemsPage<CommentsInfoItem> page = extractor().getInitialPage();
// The track has comments; we only assert the call itself does not throw
// and that the result is a valid (non-null) page.
assertTrue(page.getErrors().isEmpty(),
"Expected no extractor errors on initial page");
}

/**
* Regression test for issue #1243: calling {@link CommentsExtractor#getPage(Page)} with a
* {@link Page} whose URL is null (which is what gets stored when {@code next_href} is
* absent in the API response) must return {@link InfoItemsPage#emptyPage()} rather than
* throw {@link IllegalArgumentException}.
*/
@Test
void testGetPageWithNullUrlReturnsEmptyPage() throws IOException, ExtractionException {
final InfoItemsPage<CommentsInfoItem> page = extractor().getPage(new Page((String) null));
assertTrue(page.getItems().isEmpty(),
"Expected empty items when page URL is null");
assertFalse(page.hasNextPage(),
"Expected no next page when page URL is null");
}
}

/**
* Tests a SoundCloud track that has no comments.
*
* <p>Verifies that the extractor handles an empty collection gracefully:
* the initial page must load without error, return no items, and have no next page.</p>
*/
@Nested
class TrackWithNoComments extends DefaultSimpleExtractorTest<CommentsExtractor> {
private static final String URL = "https://soundcloud.com/user285130010/jdkskls";

@Override
protected CommentsExtractor createExtractor() throws Exception {
return SoundCloud.getCommentsExtractor(URL);
}

/**
* The initial page must load successfully, return an empty items list,
* and report no next page.
*/
@Test
void testGetInitialPageIsEmpty() throws IOException, ExtractionException {
final InfoItemsPage<CommentsInfoItem> page = extractor().getInitialPage();
assertTrue(page.getErrors().isEmpty(),
"Expected no extractor errors on initial page");
assertTrue(page.getItems().isEmpty(),
"Expected no comments for a track with no comments");
assertFalse(page.hasNextPage(),
"Expected no next page for a track with no comments");
}
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"request": {
"httpMethod": "GET",
"url": "https://api-widget.soundcloud.com/resolve?url\u003dhttps%3A%2F%2Fsoundcloud.com%2Fuser-722618400%2Fa-real-playa\u0026format\u003djson\u0026client_id\u003dCkCiIyf14rHi27fhk7HxhPOzc85okfSJ",
"headers": {
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "OK",
"responseHeaders": {
"cache-control": [
"private, max-age\u003d0"
],
"connection": [
"keep-alive"
],
"content-type": [
"application/json; charset\u003dutf-8"
],
"date": [
"Tue, 14 Apr 2026 03:30:30 GMT"
],
"referrer-policy": [
"no-referrer"
],
"server": [
"am/2"
],
"strict-transport-security": [
"max-age\u003d63072000"
],
"vary": [
"Origin"
],
"via": [
"1.1 a21dc4de5833aaa6d917631becb22680.cloudfront.net (CloudFront)"
],
"x-amz-cf-id": [
"HJt_lcobUD2i62Zgo_Olkgeo21xHnG_Ri6ezzh6eWmY94QBsuKjIJA\u003d\u003d"
],
"x-amz-cf-pop": [
"MAD56-P2"
],
"x-cache": [
"Miss from cloudfront"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"DENY"
],
"x-robots-tag": [
"noindex"
]
},
"responseBody": "{\"artwork_url\":\"https://i1.sndcdn.com/artworks-te4SwNsMypkflClB-xRgdyA-large.jpg\",\"caption\":null,\"commentable\":true,\"comment_count\":8,\"created_at\":\"2023-11-20T17:45:43Z\",\"description\":\"\",\"downloadable\":false,\"download_count\":0,\"duration\":205937,\"full_duration\":205923,\"embeddable_by\":\"all\",\"genre\":\"\",\"has_downloads_left\":false,\"id\":1670147625,\"kind\":\"track\",\"label_name\":null,\"last_modified\":\"2023-11-20T17:45:50Z\",\"license\":\"all-rights-reserved\",\"likes_count\":4724,\"permalink\":\"a-real-playa\",\"permalink_url\":\"https://soundcloud.com/user-722618400/a-real-playa\",\"playback_count\":486999,\"public\":true,\"publisher_metadata\":null,\"purchase_title\":null,\"purchase_url\":null,\"release_date\":null,\"reposts_count\":25,\"secret_token\":null,\"sharing\":\"public\",\"state\":\"finished\",\"streamable\":true,\"tag_list\":\"\",\"title\":\"A real playa\",\"uri\":\"https://api.soundcloud.com/tracks/soundcloud%3Atracks%3A1670147625\",\"urn\":\"soundcloud:tracks:1670147625\",\"user_id\":910824574,\"visuals\":null,\"waveform_url\":\"https://wave.sndcdn.com/a2nCRfj9JoLO_m.json\",\"display_date\":\"2023-11-20T17:45:43Z\",\"media\":{\"transcodings\":[{\"url\":\"https://api-widget.soundcloud.com/media/soundcloud:tracks:1670147625/872aed92-cbc3-41bf-b6c2-9cede4bd733d/stream/hls\",\"preset\":\"abr_sq\",\"duration\":205937,\"snipped\":false,\"format\":{\"protocol\":\"hls\",\"mime_type\":\"audio/mpegurl\"},\"quality\":\"sq\",\"is_legacy_transcoding\":false},{\"url\":\"https://api-widget.soundcloud.com/media/soundcloud:tracks:1670147625/3d877120-2536-439d-b511-1162dd39339c/stream/hls\",\"preset\":\"mp3_1_0\",\"duration\":205923,\"snipped\":false,\"format\":{\"protocol\":\"hls\",\"mime_type\":\"audio/mpeg\"},\"quality\":\"sq\",\"is_legacy_transcoding\":true},{\"url\":\"https://api-widget.soundcloud.com/media/soundcloud:tracks:1670147625/3d877120-2536-439d-b511-1162dd39339c/stream/progressive\",\"preset\":\"mp3_1_0\",\"duration\":205923,\"snipped\":false,\"format\":{\"protocol\":\"progressive\",\"mime_type\":\"audio/mpeg\"},\"quality\":\"sq\",\"is_legacy_transcoding\":true}]},\"station_urn\":\"soundcloud:system-playlists:track-stations:1670147625\",\"station_permalink\":\"track-stations:1670147625\",\"track_authorization\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJnZW8iOiJFUyIsInN1YiI6IiIsInJpZCI6IjViMDU5NmQyLTc4NjgtNDU3OS1iYTcxLWNiYjUxNDA4YWVmYyIsImlhdCI6MTc3NjEzNzQzMX0.gAPqWZGukOShIAgkgAadCnTeHeISq7Be-CdblFzqdyg\",\"monetization_model\":\"BLACKBOX\",\"policy\":\"MONETIZE\",\"user\":{\"avatar_url\":\"https://i1.sndcdn.com/avatars-SBGwwERPMyiSuj8W-yMJAGw-large.jpg\",\"city\":\"\",\"comments_count\":0,\"country_code\":null,\"created_at\":null,\"creator_subscriptions\":[{\"product\":{\"id\":\"free\"}}],\"creator_subscription\":{\"product\":{\"id\":\"free\"}},\"description\":\"Banagher, Co.offaly\",\"followers_count\":240,\"followings_count\":66,\"first_name\":\"\",\"full_name\":\"\",\"groups_count\":0,\"id\":910824574,\"kind\":\"user\",\"last_modified\":\"2022-10-12T13:31:30Z\",\"last_name\":\"\",\"likes_count\":1193,\"playlist_likes_count\":11,\"permalink\":\"user-722618400\",\"permalink_url\":\"https://soundcloud.com/user-722618400\",\"playlist_count\":0,\"reposts_count\":null,\"track_count\":11,\"uri\":\"https://api.soundcloud.com/users/soundcloud%3Ausers%3A910824574\",\"urn\":\"soundcloud:users:910824574\",\"username\":\"Korbin Dolan\",\"verified\":false,\"visuals\":{\"urn\":\"soundcloud:users:910824574\",\"enabled\":true,\"visuals\":[{\"urn\":\"soundcloud:visuals:167104191\",\"entry_time\":0,\"visual_url\":\"https://i1.sndcdn.com/visuals-CSbB5vvPqVaPwNHe-gxbM8A-original.jpg\"}],\"tracking\":null},\"badges\":{\"pro\":false,\"creator_mid_tier\":false,\"pro_unlimited\":false,\"verified\":false},\"station_urn\":\"soundcloud:system-playlists:artist-stations:910824574\",\"station_permalink\":\"artist-stations:910824574\",\"date_of_birth\":null}}",
"latestUrl": "https://api-widget.soundcloud.com/resolve?url\u003dhttps%3A%2F%2Fsoundcloud.com%2Fuser-722618400%2Fa-real-playa\u0026format\u003djson\u0026client_id\u003dCkCiIyf14rHi27fhk7HxhPOzc85okfSJ"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"request": {
"httpMethod": "GET",
"url": "https://api-widget.soundcloud.com/resolve?url\u003dhttps%3A%2F%2Fsoundcloud.com%2Fuser-722618400%2Fa-real-playa\u0026format\u003djson\u0026client_id\u003dCkCiIyf14rHi27fhk7HxhPOzc85okfSJ",
"headers": {
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "OK",
"responseHeaders": {
"cache-control": [
"private, max-age\u003d0"
],
"connection": [
"keep-alive"
],
"content-type": [
"application/json; charset\u003dutf-8"
],
"date": [
"Tue, 14 Apr 2026 03:30:31 GMT"
],
"referrer-policy": [
"no-referrer"
],
"server": [
"am/2"
],
"strict-transport-security": [
"max-age\u003d63072000"
],
"vary": [
"Origin"
],
"via": [
"1.1 a21dc4de5833aaa6d917631becb22680.cloudfront.net (CloudFront)"
],
"x-amz-cf-id": [
"qxUO1kM0zTcFksoTmE_TnjMNMHQrd9kdBLkCVWoiNxxuSLETVHEw4A\u003d\u003d"
],
"x-amz-cf-pop": [
"MAD56-P2"
],
"x-cache": [
"Miss from cloudfront"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"DENY"
],
"x-robots-tag": [
"noindex"
]
},
"responseBody": "{\"artwork_url\":\"https://i1.sndcdn.com/artworks-te4SwNsMypkflClB-xRgdyA-large.jpg\",\"caption\":null,\"commentable\":true,\"comment_count\":8,\"created_at\":\"2023-11-20T17:45:43Z\",\"description\":\"\",\"downloadable\":false,\"download_count\":0,\"duration\":205937,\"full_duration\":205923,\"embeddable_by\":\"all\",\"genre\":\"\",\"has_downloads_left\":false,\"id\":1670147625,\"kind\":\"track\",\"label_name\":null,\"last_modified\":\"2023-11-20T17:45:50Z\",\"license\":\"all-rights-reserved\",\"likes_count\":4724,\"permalink\":\"a-real-playa\",\"permalink_url\":\"https://soundcloud.com/user-722618400/a-real-playa\",\"playback_count\":486999,\"public\":true,\"publisher_metadata\":null,\"purchase_title\":null,\"purchase_url\":null,\"release_date\":null,\"reposts_count\":25,\"secret_token\":null,\"sharing\":\"public\",\"state\":\"finished\",\"streamable\":true,\"tag_list\":\"\",\"title\":\"A real playa\",\"uri\":\"https://api.soundcloud.com/tracks/soundcloud%3Atracks%3A1670147625\",\"urn\":\"soundcloud:tracks:1670147625\",\"user_id\":910824574,\"visuals\":null,\"waveform_url\":\"https://wave.sndcdn.com/a2nCRfj9JoLO_m.json\",\"display_date\":\"2023-11-20T17:45:43Z\",\"media\":{\"transcodings\":[{\"url\":\"https://api-widget.soundcloud.com/media/soundcloud:tracks:1670147625/872aed92-cbc3-41bf-b6c2-9cede4bd733d/stream/hls\",\"preset\":\"abr_sq\",\"duration\":205937,\"snipped\":false,\"format\":{\"protocol\":\"hls\",\"mime_type\":\"audio/mpegurl\"},\"quality\":\"sq\",\"is_legacy_transcoding\":false},{\"url\":\"https://api-widget.soundcloud.com/media/soundcloud:tracks:1670147625/3d877120-2536-439d-b511-1162dd39339c/stream/hls\",\"preset\":\"mp3_1_0\",\"duration\":205923,\"snipped\":false,\"format\":{\"protocol\":\"hls\",\"mime_type\":\"audio/mpeg\"},\"quality\":\"sq\",\"is_legacy_transcoding\":true},{\"url\":\"https://api-widget.soundcloud.com/media/soundcloud:tracks:1670147625/3d877120-2536-439d-b511-1162dd39339c/stream/progressive\",\"preset\":\"mp3_1_0\",\"duration\":205923,\"snipped\":false,\"format\":{\"protocol\":\"progressive\",\"mime_type\":\"audio/mpeg\"},\"quality\":\"sq\",\"is_legacy_transcoding\":true}]},\"station_urn\":\"soundcloud:system-playlists:track-stations:1670147625\",\"station_permalink\":\"track-stations:1670147625\",\"track_authorization\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJnZW8iOiJFUyIsInN1YiI6IiIsInJpZCI6IjViMDU5NmQyLTc4NjgtNDU3OS1iYTcxLWNiYjUxNDA4YWVmYyIsImlhdCI6MTc3NjEzNzQzMX0.gAPqWZGukOShIAgkgAadCnTeHeISq7Be-CdblFzqdyg\",\"monetization_model\":\"BLACKBOX\",\"policy\":\"MONETIZE\",\"user\":{\"avatar_url\":\"https://i1.sndcdn.com/avatars-SBGwwERPMyiSuj8W-yMJAGw-large.jpg\",\"city\":\"\",\"comments_count\":0,\"country_code\":null,\"created_at\":null,\"creator_subscriptions\":[{\"product\":{\"id\":\"free\"}}],\"creator_subscription\":{\"product\":{\"id\":\"free\"}},\"description\":\"Banagher, Co.offaly\",\"followers_count\":240,\"followings_count\":66,\"first_name\":\"\",\"full_name\":\"\",\"groups_count\":0,\"id\":910824574,\"kind\":\"user\",\"last_modified\":\"2022-10-12T13:31:30Z\",\"last_name\":\"\",\"likes_count\":1193,\"playlist_likes_count\":11,\"permalink\":\"user-722618400\",\"permalink_url\":\"https://soundcloud.com/user-722618400\",\"playlist_count\":0,\"reposts_count\":null,\"track_count\":11,\"uri\":\"https://api.soundcloud.com/users/soundcloud%3Ausers%3A910824574\",\"urn\":\"soundcloud:users:910824574\",\"username\":\"Korbin Dolan\",\"verified\":false,\"visuals\":{\"urn\":\"soundcloud:users:910824574\",\"enabled\":true,\"visuals\":[{\"urn\":\"soundcloud:visuals:167104191\",\"entry_time\":0,\"visual_url\":\"https://i1.sndcdn.com/visuals-CSbB5vvPqVaPwNHe-gxbM8A-original.jpg\"}],\"tracking\":null},\"badges\":{\"pro\":false,\"creator_mid_tier\":false,\"pro_unlimited\":false,\"verified\":false},\"station_urn\":\"soundcloud:system-playlists:artist-stations:910824574\",\"station_permalink\":\"artist-stations:910824574\",\"date_of_birth\":null}}",
"latestUrl": "https://api-widget.soundcloud.com/resolve?url\u003dhttps%3A%2F%2Fsoundcloud.com%2Fuser-722618400%2Fa-real-playa\u0026format\u003djson\u0026client_id\u003dCkCiIyf14rHi27fhk7HxhPOzc85okfSJ"
}
}
Loading