2020-04-10 10:51:05 +02:00
|
|
|
package org.schabi.newpipe.extractor.services.soundcloud.extractors;
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2019-12-22 00:40:32 +01:00
|
|
|
import com.grack.nanojson.JsonArray;
|
2017-08-16 04:40:03 +02:00
|
|
|
import com.grack.nanojson.JsonObject;
|
|
|
|
import com.grack.nanojson.JsonParser;
|
|
|
|
import com.grack.nanojson.JsonParserException;
|
2020-02-08 23:58:46 +01:00
|
|
|
import org.schabi.newpipe.extractor.MediaFormat;
|
2020-12-20 19:54:12 +01:00
|
|
|
import org.schabi.newpipe.extractor.MetaInfo;
|
2020-02-08 23:58:46 +01:00
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
|
|
|
import org.schabi.newpipe.extractor.StreamingService;
|
2019-04-28 22:03:16 +02:00
|
|
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
2017-08-04 16:21:45 +02:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
2021-01-10 19:03:20 +01:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException;
|
2017-08-04 16:21:45 +02:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
2021-02-20 15:59:05 +01:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
2021-02-20 14:53:57 +01:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException;
|
2018-07-13 18:02:40 +02:00
|
|
|
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
2019-11-03 19:45:25 +01:00
|
|
|
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
2020-04-10 10:51:05 +02:00
|
|
|
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
2021-02-07 22:12:22 +01:00
|
|
|
import org.schabi.newpipe.extractor.stream.*;
|
2017-08-06 22:20:15 +02:00
|
|
|
|
2021-02-07 22:12:22 +01:00
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
import javax.annotation.Nullable;
|
2017-08-06 22:20:15 +02:00
|
|
|
import java.io.IOException;
|
2017-11-25 02:20:16 +01:00
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
import java.net.URLEncoder;
|
2018-03-04 21:30:31 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
2020-01-25 13:16:42 +01:00
|
|
|
import java.util.Locale;
|
2021-01-23 18:17:35 +01:00
|
|
|
import java.util.regex.Matcher;
|
|
|
|
import java.util.regex.Pattern;
|
2018-03-04 21:30:31 +01:00
|
|
|
|
2021-01-23 18:17:35 +01:00
|
|
|
import static org.schabi.newpipe.extractor.utils.Utils.HTTPS;
|
2021-02-07 22:42:21 +01:00
|
|
|
import static org.schabi.newpipe.extractor.utils.Utils.*;
|
2020-04-16 16:08:14 +02:00
|
|
|
|
2017-08-04 16:21:45 +02:00
|
|
|
public class SoundcloudStreamExtractor extends StreamExtractor {
|
2017-08-16 04:40:03 +02:00
|
|
|
private JsonObject track;
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2019-04-28 22:03:16 +02:00
|
|
|
public SoundcloudStreamExtractor(StreamingService service, LinkHandler linkHandler) {
|
|
|
|
super(service, linkHandler);
|
2017-08-06 22:20:15 +02:00
|
|
|
}
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2017-08-06 22:20:15 +02:00
|
|
|
@Override
|
2017-11-28 13:37:01 +01:00
|
|
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
2020-10-16 04:39:58 +02:00
|
|
|
track = SoundcloudParsingHelper.resolveFor(downloader, getUrl());
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2021-02-20 15:59:05 +01:00
|
|
|
final String policy = track.getString("policy", EMPTY_STRING);
|
2017-08-10 19:50:59 +02:00
|
|
|
if (!policy.equals("ALLOW") && !policy.equals("MONETIZE")) {
|
2021-01-10 19:03:20 +01:00
|
|
|
if (policy.equals("SNIP")) {
|
2021-02-20 14:53:57 +01:00
|
|
|
throw new SoundCloudGoPlusContentException();
|
2021-01-10 19:03:20 +01:00
|
|
|
}
|
|
|
|
if (policy.equals("BLOCK")) {
|
|
|
|
throw new GeographicRestrictionException("This track is not available in user's country");
|
|
|
|
}
|
2017-08-10 19:50:59 +02:00
|
|
|
throw new ContentNotAvailableException("Content not available: policy " + policy);
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-04 16:21:45 +02:00
|
|
|
@Override
|
|
|
|
public String getId() {
|
2021-02-07 22:42:21 +01:00
|
|
|
return track.getInt("id") + EMPTY_STRING;
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-04 16:21:45 +02:00
|
|
|
@Override
|
2017-08-11 03:23:09 +02:00
|
|
|
public String getName() {
|
2017-08-16 04:40:03 +02:00
|
|
|
return track.getString("title");
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-10 19:50:59 +02:00
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getTextualUploadDate() {
|
|
|
|
return track.getString("created_at")
|
2021-02-07 22:12:22 +01:00
|
|
|
.replace("T", " ")
|
2021-02-07 22:42:21 +01:00
|
|
|
.replace("Z", EMPTY_STRING);
|
2019-04-28 22:03:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2019-11-03 19:45:25 +01:00
|
|
|
public DateWrapper getUploadDate() throws ParsingException {
|
2020-04-10 14:48:11 +02:00
|
|
|
return new DateWrapper(SoundcloudParsingHelper.parseDateFrom(track.getString("created_at")));
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-04 16:21:45 +02:00
|
|
|
@Override
|
2017-08-11 03:23:09 +02:00
|
|
|
public String getThumbnailUrl() {
|
2020-04-16 16:08:14 +02:00
|
|
|
String artworkUrl = track.getString("artwork_url", EMPTY_STRING);
|
2019-04-25 23:29:15 +02:00
|
|
|
if (artworkUrl.isEmpty()) {
|
2020-04-16 16:08:14 +02:00
|
|
|
artworkUrl = track.getObject("user").getString("avatar_url", EMPTY_STRING);
|
2019-04-25 23:29:15 +02:00
|
|
|
}
|
2020-04-11 17:18:05 +02:00
|
|
|
return artworkUrl.replace("large.jpg", "crop.jpg");
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
2020-04-11 17:18:05 +02:00
|
|
|
@Nonnull
|
2017-08-04 16:21:45 +02:00
|
|
|
@Override
|
2020-02-06 23:35:46 +01:00
|
|
|
public Description getDescription() {
|
2020-02-07 13:28:27 +01:00
|
|
|
return new Description(track.getString("description"), Description.PLAIN_TEXT);
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-11 03:23:09 +02:00
|
|
|
public int getAgeLimit() {
|
2017-11-25 02:03:30 +01:00
|
|
|
return NO_AGE_LIMIT;
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-11 03:23:09 +02:00
|
|
|
public long getLength() {
|
2020-06-13 20:25:38 +02:00
|
|
|
return track.getLong("duration") / 1000L;
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-11 03:23:09 +02:00
|
|
|
public long getTimeStamp() throws ParsingException {
|
2017-11-22 18:45:49 +01:00
|
|
|
return getTimestampSeconds("(#t=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)");
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-11 03:23:09 +02:00
|
|
|
public long getViewCount() {
|
2020-06-13 20:25:38 +02:00
|
|
|
return track.getLong("playback_count");
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-10 19:50:59 +02:00
|
|
|
public long getLikeCount() {
|
2020-06-13 20:25:38 +02:00
|
|
|
return track.getLong("favoritings_count", -1);
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-10 19:50:59 +02:00
|
|
|
public long getDislikeCount() {
|
2017-09-15 19:35:43 +02:00
|
|
|
return -1;
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
|
|
|
public String getUploaderUrl() {
|
2018-02-21 09:23:57 +01:00
|
|
|
return SoundcloudParsingHelper.getUploaderUrl(track);
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
|
|
|
public String getUploaderName() {
|
2018-02-21 09:23:57 +01:00
|
|
|
return SoundcloudParsingHelper.getUploaderName(track);
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
2021-01-22 01:44:58 +01:00
|
|
|
@Override
|
|
|
|
public boolean isUploaderVerified() throws ParsingException {
|
|
|
|
return track.getObject("user").getBoolean("verified");
|
|
|
|
}
|
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
@Nonnull
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
|
|
|
public String getUploaderAvatarUrl() {
|
2018-02-21 09:23:57 +01:00
|
|
|
return SoundcloudParsingHelper.getAvatarUrl(track);
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
2020-04-13 22:34:20 +02:00
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getSubChannelUrl() {
|
2020-04-13 22:34:20 +02:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getSubChannelName() {
|
2020-04-13 22:34:20 +02:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getSubChannelAvatarUrl() {
|
2020-04-13 22:34:20 +02:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2018-02-25 22:03:32 +01:00
|
|
|
@Nonnull
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
|
|
|
public String getDashMpdUrl() {
|
2018-02-25 22:03:32 +01:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getHlsUrl() {
|
2018-02-25 22:03:32 +01:00
|
|
|
return "";
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-03-13 15:26:05 +01:00
|
|
|
public List<AudioStream> getAudioStreams() throws ExtractionException {
|
2021-01-23 18:17:35 +01:00
|
|
|
final List<AudioStream> audioStreams = new ArrayList<>();
|
2017-08-11 03:23:09 +02:00
|
|
|
|
2019-12-22 00:40:32 +01:00
|
|
|
// Streams can be streamable and downloadable - or explicitly not.
|
|
|
|
// For playing the track, it is only necessary to have a streamable track.
|
|
|
|
// If this is not the case, this track might not be published yet.
|
2020-03-18 11:01:46 +01:00
|
|
|
if (!track.getBoolean("streamable")) return audioStreams;
|
2019-12-22 00:40:32 +01:00
|
|
|
|
|
|
|
try {
|
2020-04-11 17:18:05 +02:00
|
|
|
final JsonArray transcodings = track.getObject("media").getArray("transcodings");
|
2021-03-13 15:26:05 +01:00
|
|
|
if (transcodings != null) {
|
|
|
|
// Get information about what stream formats are available
|
|
|
|
setUpAudioStreams(transcodings, checkMp3ProgressivePresence(transcodings),
|
|
|
|
audioStreams);
|
2021-01-25 20:42:08 +01:00
|
|
|
}
|
2021-03-13 15:26:05 +01:00
|
|
|
} catch (final NullPointerException e) {
|
|
|
|
throw new ExtractionException("Could not get SoundCloud's tracks audio URL", e);
|
|
|
|
}
|
2021-01-25 20:42:08 +01:00
|
|
|
|
2021-03-13 15:26:05 +01:00
|
|
|
return audioStreams;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean checkMp3ProgressivePresence(final JsonArray transcodings) {
|
|
|
|
boolean presence = false;
|
|
|
|
for (final Object transcoding : transcodings) {
|
|
|
|
final JsonObject transcodingJsonObject = (JsonObject) transcoding;
|
|
|
|
if (transcodingJsonObject.getString("preset").contains("mp3") &&
|
|
|
|
transcodingJsonObject.getObject("format").getString("protocol")
|
|
|
|
.equals("progressive")) {
|
|
|
|
presence = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return presence;
|
|
|
|
}
|
2021-01-23 18:17:35 +01:00
|
|
|
|
2021-03-13 15:26:05 +01:00
|
|
|
@Nonnull
|
|
|
|
private static String getTranscodingUrl(final String endpointUrl, final String protocol) throws IOException, ExtractionException {
|
|
|
|
final Downloader downloader = NewPipe.getDownloader();
|
|
|
|
final String apiStreamUrl = endpointUrl + "?client_id=" + SoundcloudParsingHelper.clientId();
|
|
|
|
final String response = downloader.get(apiStreamUrl).responseBody();
|
|
|
|
final JsonObject urlObject;
|
|
|
|
try {
|
|
|
|
urlObject = JsonParser.object().from(response);
|
|
|
|
} catch (final JsonParserException e) {
|
|
|
|
throw new ParsingException("Could not parse streamable url", e);
|
|
|
|
}
|
|
|
|
final String urlString = urlObject.getString("url");
|
|
|
|
|
|
|
|
if (protocol.equals("progressive")) {
|
|
|
|
return urlString;
|
|
|
|
} else if (protocol.equals("hls")) {
|
|
|
|
return getSingleUrlFromHlsManifest(urlString);
|
|
|
|
}
|
|
|
|
// else, unknown protocol
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void setUpAudioStreams(final JsonArray transcodings,
|
|
|
|
final boolean mp3ProgressiveInStreams,
|
|
|
|
final List<AudioStream> audioStreams) {
|
|
|
|
for (final Object transcoding : transcodings) {
|
|
|
|
final JsonObject transcodingJsonObject = (JsonObject) transcoding;
|
|
|
|
final String mediaUrl;
|
|
|
|
final String preset = transcodingJsonObject.getString("preset");
|
|
|
|
final String protocol = transcodingJsonObject.getObject("format").getString("protocol");
|
|
|
|
final String url = transcodingJsonObject.getString("url");
|
|
|
|
final MediaFormat mediaFormat;
|
|
|
|
final int bitrate;
|
|
|
|
|
|
|
|
if (!isNullOrEmpty(url)) {
|
|
|
|
if (preset.contains("mp3")) {
|
|
|
|
// Don't add the MP3 HLS stream if there is a progressive stream present
|
|
|
|
// because the two have the same bitrate
|
|
|
|
if (mp3ProgressiveInStreams && protocol.equals("hls")) {
|
2021-01-23 18:17:35 +01:00
|
|
|
continue;
|
2019-12-22 00:40:32 +01:00
|
|
|
}
|
2021-03-13 15:26:05 +01:00
|
|
|
mediaFormat = MediaFormat.MP3;
|
|
|
|
bitrate = 128;
|
|
|
|
} else if (preset.contains("opus")) {
|
|
|
|
mediaFormat = MediaFormat.OPUS;
|
|
|
|
bitrate = 64;
|
|
|
|
} else {
|
|
|
|
// Unknown format
|
|
|
|
continue;
|
|
|
|
}
|
2021-01-23 18:17:35 +01:00
|
|
|
|
2021-03-13 15:26:05 +01:00
|
|
|
try {
|
|
|
|
mediaUrl = getTranscodingUrl(url, protocol);
|
|
|
|
} catch (final Exception e) {
|
|
|
|
// something went wrong when parsing this transcoding
|
|
|
|
continue;
|
2019-12-22 00:40:32 +01:00
|
|
|
}
|
2021-03-13 15:26:05 +01:00
|
|
|
audioStreams.add(new AudioStream(mediaUrl, mediaFormat, bitrate));
|
2019-12-22 00:40:32 +01:00
|
|
|
}
|
2017-08-16 04:40:03 +02:00
|
|
|
}
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
2021-03-13 15:26:05 +01:00
|
|
|
private final static Pattern PATTERN_HTTPS_URLS_IN_HLS_MANIFESTS = Pattern.compile("((https?):((//)|(\\\\))+[\\w\\d:#@%/;$()~_?+-=\\\\.&]*)");
|
2021-02-20 15:59:05 +01:00
|
|
|
|
|
|
|
/** Parses a SoundCloud HLS manifest to get a single URL of HLS streams.
|
|
|
|
* <p>
|
|
|
|
* This method downloads the provided manifest URL, find all web occurrences using a regex, get
|
2021-03-13 15:26:05 +01:00
|
|
|
* the last segment URL, changes its segment range to {@code 0/track-length} and return this
|
|
|
|
* string.
|
2021-02-20 15:59:05 +01:00
|
|
|
* @param hlsManifestUrl the URL of the manifest to be parsed
|
|
|
|
* @return a single URL that contains a range equal to the length of the track
|
|
|
|
*/
|
|
|
|
private static String getSingleUrlFromHlsManifest(final String hlsManifestUrl) throws ParsingException {
|
|
|
|
final Downloader dl = NewPipe.getDownloader();
|
|
|
|
final String hlsManifestResponse;
|
|
|
|
|
|
|
|
try {
|
|
|
|
hlsManifestResponse = dl.get(hlsManifestUrl).responseBody();
|
|
|
|
} catch (final IOException | ReCaptchaException e) {
|
2021-03-13 15:26:05 +01:00
|
|
|
throw new ParsingException("Could not get SoundCloud HLS manifest");
|
2021-02-20 15:59:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
final List<String> hlsRangesList = new ArrayList<>();
|
2021-03-13 15:26:05 +01:00
|
|
|
final Matcher pattern_matches = PATTERN_HTTPS_URLS_IN_HLS_MANIFESTS
|
|
|
|
.matcher(hlsManifestResponse);
|
2021-02-20 15:59:05 +01:00
|
|
|
|
|
|
|
while (pattern_matches.find()) {
|
|
|
|
hlsRangesList.add(hlsManifestResponse.substring(pattern_matches.start(0),
|
|
|
|
pattern_matches.end(0)));
|
|
|
|
}
|
|
|
|
|
|
|
|
final String hlsLastRangeUrl = hlsRangesList.get(hlsRangesList.size() - 1);
|
|
|
|
final String[] hlsLastRangeUrlArray = hlsLastRangeUrl.split("/");
|
|
|
|
|
2021-03-13 15:26:05 +01:00
|
|
|
return HTTPS + hlsLastRangeUrlArray[2] + "/media/0/" + hlsLastRangeUrlArray[5] + "/"
|
|
|
|
+ hlsLastRangeUrlArray[6];
|
2021-02-20 15:59:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private static String urlEncode(final String value) {
|
2017-11-25 02:20:16 +01:00
|
|
|
try {
|
2021-02-07 22:12:22 +01:00
|
|
|
return URLEncoder.encode(value, UTF_8);
|
2021-02-20 15:59:05 +01:00
|
|
|
} catch (final UnsupportedEncodingException e) {
|
2017-11-25 02:20:16 +01:00
|
|
|
throw new IllegalStateException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public List<VideoStream> getVideoStreams() {
|
2020-04-09 18:15:34 +02:00
|
|
|
return Collections.emptyList();
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public List<VideoStream> getVideoOnlyStreams() {
|
2020-04-09 18:15:34 +02:00
|
|
|
return Collections.emptyList();
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
2017-11-22 18:39:38 +01:00
|
|
|
@Override
|
2018-02-01 22:27:14 +01:00
|
|
|
@Nonnull
|
2020-04-11 17:18:05 +02:00
|
|
|
public List<SubtitlesStream> getSubtitlesDefault() {
|
2018-02-01 22:27:14 +01:00
|
|
|
return Collections.emptyList();
|
2017-11-23 16:33:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2018-02-01 22:27:14 +01:00
|
|
|
@Nonnull
|
2020-04-11 17:18:05 +02:00
|
|
|
public List<SubtitlesStream> getSubtitles(MediaFormat format) {
|
2018-02-01 22:27:14 +01:00
|
|
|
return Collections.emptyList();
|
2017-11-23 00:10:12 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
|
|
|
public StreamType getStreamType() {
|
|
|
|
return StreamType.AUDIO_STREAM;
|
|
|
|
}
|
|
|
|
|
2020-10-24 21:17:58 +02:00
|
|
|
@Nullable
|
2017-08-04 16:21:45 +02:00
|
|
|
@Override
|
2018-11-07 18:28:44 +01:00
|
|
|
public StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException {
|
2020-04-11 17:18:05 +02:00
|
|
|
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2020-04-11 17:18:05 +02:00
|
|
|
final String apiUrl = "https://api-v2.soundcloud.com/tracks/" + urlEncode(getId())
|
|
|
|
+ "/related?client_id=" + urlEncode(SoundcloudParsingHelper.clientId());
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2017-08-10 19:50:59 +02:00
|
|
|
SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl);
|
2017-08-04 16:21:45 +02:00
|
|
|
return collector;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getErrorMessage() {
|
|
|
|
return null;
|
|
|
|
}
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
|
2020-04-11 17:18:05 +02:00
|
|
|
@Nonnull
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getHost() {
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2020-04-11 17:18:05 +02:00
|
|
|
@Nonnull
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getPrivacy() {
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2020-04-11 17:18:05 +02:00
|
|
|
@Nonnull
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getCategory() {
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2020-04-11 17:18:05 +02:00
|
|
|
@Nonnull
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getLicence() {
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public Locale getLanguageInfo() {
|
2020-01-25 13:16:42 +01:00
|
|
|
return null;
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public List<String> getTags() {
|
2020-04-09 18:15:34 +02:00
|
|
|
return Collections.emptyList();
|
added metadata, fix descriptions, fix thumbnail, update tests
thumbnail: quality before: https://peertube.cpy.re/static/thumbnails/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
quality after: https://peertube.cpy.re/static/previews/d2a5ec78-5f85-4090-8ec5-dc1102e022ea.jpg
description: we were getting about the first 260 characters, we now get full description (with fallback to first 260 chars if the get request for full description fails)
test: updated tests to match description, also changed some test: it was assertEquals(extracted, expected), but the proper way to do it is assertEquals(expected, extracted)
metadata: got host, privacy (public, private, unlisted), licence, language, tags
2020-01-19 12:45:52 +01:00
|
|
|
}
|
2020-01-23 14:19:22 +01:00
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-11 17:18:05 +02:00
|
|
|
public String getSupportInfo() {
|
2020-01-23 14:19:22 +01:00
|
|
|
return "";
|
|
|
|
}
|
2020-12-12 10:24:29 +01:00
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
|
|
|
public List<StreamSegment> getStreamSegments() {
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
2020-12-20 19:54:12 +01:00
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
|
|
|
public List<MetaInfo> getMetaInfo() {
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|