2017-08-04 16:21:45 +02:00
|
|
|
package org.schabi.newpipe.extractor.services.soundcloud;
|
|
|
|
|
2017-08-16 04:40:03 +02:00
|
|
|
import com.grack.nanojson.JsonObject;
|
|
|
|
import com.grack.nanojson.JsonParser;
|
|
|
|
import com.grack.nanojson.JsonParserException;
|
2017-11-23 11:47:05 +01:00
|
|
|
import org.schabi.newpipe.extractor.*;
|
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;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
2018-07-13 18:02:40 +02:00
|
|
|
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
2017-08-08 17:01:50 +02:00
|
|
|
import org.schabi.newpipe.extractor.stream.*;
|
2017-08-06 22:20:15 +02:00
|
|
|
|
2017-11-25 01:10:04 +01:00
|
|
|
import javax.annotation.Nonnull;
|
2019-04-28 22:03:16 +02:00
|
|
|
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;
|
2019-04-28 22:03:16 +02:00
|
|
|
import java.util.Calendar;
|
2018-03-04 21:30:31 +01:00
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
|
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 {
|
|
|
|
track = SoundcloudParsingHelper.resolveFor(downloader, getOriginalUrl());
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2017-08-16 04:40:03 +02:00
|
|
|
String policy = track.getString("policy", "");
|
2017-08-10 19:50:59 +02:00
|
|
|
if (!policy.equals("ALLOW") && !policy.equals("MONETIZE")) {
|
|
|
|
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() {
|
2017-08-06 22:20:15 +02:00
|
|
|
return track.getInt("id") + "";
|
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
|
2019-04-28 22:03:16 +02:00
|
|
|
public String getTextualUploadDate() {
|
|
|
|
return track.getString("created_at");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
|
|
|
public Calendar getUploadDate() throws ParsingException {
|
|
|
|
return SoundcloudParsingHelper.parseDate(getTextualUploadDate());
|
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() {
|
2019-04-25 23:29:15 +02:00
|
|
|
String artworkUrl = track.getString("artwork_url", "");
|
|
|
|
if (artworkUrl.isEmpty()) {
|
|
|
|
artworkUrl = track.getObject("user").getString("avatar_url", "");
|
|
|
|
}
|
|
|
|
String artworkUrlBetterResolution = artworkUrl.replace("large.jpg", "crop.jpg");
|
|
|
|
return artworkUrlBetterResolution;
|
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 getDescription() {
|
2017-08-16 04:40:03 +02:00
|
|
|
return track.getString("description");
|
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() {
|
2017-08-16 04:40:03 +02:00
|
|
|
return track.getNumber("duration", 0).longValue() / 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() {
|
2017-08-16 04:40:03 +02:00
|
|
|
return track.getNumber("playback_count", 0).longValue();
|
2017-08-04 16:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-08-10 19:50:59 +02:00
|
|
|
public long getLikeCount() {
|
2017-09-16 11:08:08 +02:00
|
|
|
return track.getNumber("favoritings_count", -1).longValue();
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
public String getHlsUrl() throws ParsingException {
|
|
|
|
return "";
|
2017-08-11 03:23:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public List<AudioStream> getAudioStreams() throws IOException, ExtractionException {
|
|
|
|
List<AudioStream> audioStreams = new ArrayList<>();
|
|
|
|
Downloader dl = NewPipe.getDownloader();
|
|
|
|
|
2017-11-25 02:20:16 +01:00
|
|
|
String apiUrl = "https://api.soundcloud.com/i1/tracks/" + urlEncode(getId()) + "/streams"
|
|
|
|
+ "?client_id=" + urlEncode(SoundcloudParsingHelper.clientId());
|
2017-08-11 03:23:09 +02:00
|
|
|
|
2019-04-28 22:03:16 +02:00
|
|
|
String response = dl.get(apiUrl, getExtractorLocalization()).responseBody();
|
2017-08-16 04:40:03 +02:00
|
|
|
JsonObject responseObject;
|
|
|
|
try {
|
|
|
|
responseObject = JsonParser.object().from(response);
|
|
|
|
} catch (JsonParserException e) {
|
|
|
|
throw new ParsingException("Could not parse json response", e);
|
|
|
|
}
|
2017-08-11 03:23:09 +02:00
|
|
|
|
2017-08-16 04:40:03 +02:00
|
|
|
String mp3Url = responseObject.getString("http_mp3_128_url");
|
|
|
|
if (mp3Url != null && !mp3Url.isEmpty()) {
|
2017-11-11 01:21:43 +01:00
|
|
|
audioStreams.add(new AudioStream(mp3Url, MediaFormat.MP3, 128));
|
2017-08-16 04:40:03 +02:00
|
|
|
} else {
|
|
|
|
throw new ExtractionException("Could not get SoundCloud's track audio url");
|
|
|
|
}
|
2017-08-11 03:23:09 +02:00
|
|
|
|
|
|
|
return audioStreams;
|
|
|
|
}
|
|
|
|
|
2017-11-25 02:20:16 +01:00
|
|
|
private static String urlEncode(String value) {
|
|
|
|
try {
|
|
|
|
return URLEncoder.encode(value, "UTF-8");
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
throw new IllegalStateException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-11 03:23:09 +02:00
|
|
|
@Override
|
|
|
|
public List<VideoStream> getVideoStreams() throws IOException, ExtractionException {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public List<VideoStream> getVideoOnlyStreams() throws IOException, ExtractionException {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2017-11-22 18:39:38 +01:00
|
|
|
@Override
|
2018-02-01 22:27:14 +01:00
|
|
|
@Nonnull
|
2018-09-24 21:04:22 +02:00
|
|
|
public List<SubtitlesStream> getSubtitlesDefault() throws IOException, ExtractionException {
|
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
|
2018-09-24 21:04:22 +02:00
|
|
|
public List<SubtitlesStream> getSubtitles(MediaFormat format) throws IOException, ExtractionException {
|
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;
|
|
|
|
}
|
|
|
|
|
2017-08-04 16:21:45 +02:00
|
|
|
@Override
|
2018-11-07 18:28:44 +01:00
|
|
|
public StreamInfoItem getNextStream() throws IOException, ExtractionException {
|
2017-08-04 16:21:45 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2018-11-07 18:28:44 +01:00
|
|
|
public StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException {
|
2018-02-24 22:20:50 +01:00
|
|
|
StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
|
2017-08-04 16:21:45 +02:00
|
|
|
|
2017-11-25 02:20:16 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|