2018-10-11 21:10:22 +02:00
|
|
|
package org.schabi.newpipe.extractor.services.peertube.extractors;
|
|
|
|
|
2022-08-15 05:49:40 +02:00
|
|
|
import static org.schabi.newpipe.extractor.stream.AudioStream.UNKNOWN_BITRATE;
|
2022-03-18 10:25:16 +01:00
|
|
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|
|
|
|
2020-02-08 23:58:46 +01:00
|
|
|
import com.grack.nanojson.JsonArray;
|
|
|
|
import com.grack.nanojson.JsonObject;
|
|
|
|
import com.grack.nanojson.JsonParser;
|
|
|
|
import com.grack.nanojson.JsonParserException;
|
2022-03-18 10:25:16 +01:00
|
|
|
|
2018-10-11 21:10:22 +02:00
|
|
|
import org.schabi.newpipe.extractor.MediaFormat;
|
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
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
2018-10-11 21:10:22 +02:00
|
|
|
import org.schabi.newpipe.extractor.StreamingService;
|
2019-11-19 22:38:17 +01:00
|
|
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
|
|
|
import org.schabi.newpipe.extractor.downloader.Response;
|
2018-10-11 21:10:22 +02:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
|
|
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
2019-11-19 22:38:17 +01:00
|
|
|
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
2018-10-11 21:10:22 +02:00
|
|
|
import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper;
|
2018-12-26 09:59:23 +01:00
|
|
|
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
|
2020-04-09 19:46:20 +02:00
|
|
|
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeStreamLinkHandlerFactory;
|
2022-03-18 10:25:16 +01:00
|
|
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
2022-03-03 20:46:53 +01:00
|
|
|
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
|
2022-03-18 10:25:16 +01:00
|
|
|
import org.schabi.newpipe.extractor.stream.Description;
|
|
|
|
import org.schabi.newpipe.extractor.stream.Stream;
|
|
|
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
|
|
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
|
|
|
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
|
|
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
2018-10-11 21:10:22 +02:00
|
|
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
2020-05-02 08:21:47 +02:00
|
|
|
import org.schabi.newpipe.extractor.utils.Utils;
|
2018-10-11 21:10:22 +02:00
|
|
|
|
2020-02-08 23:58:46 +01:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
import java.net.URLEncoder;
|
2022-07-28 04:19:21 +02:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2020-02-08 23:58:46 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Locale;
|
2022-03-03 20:46:53 +01:00
|
|
|
import java.util.stream.Collectors;
|
2020-01-23 14:19:22 +01:00
|
|
|
|
2022-03-18 10:25:16 +01:00
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
import javax.annotation.Nullable;
|
2021-02-07 22:12:22 +01:00
|
|
|
|
2018-10-11 21:10:22 +02:00
|
|
|
public class PeertubeStreamExtractor extends StreamExtractor {
|
2022-03-03 20:46:53 +01:00
|
|
|
private static final String ACCOUNT_HOST = "account.host";
|
|
|
|
private static final String ACCOUNT_NAME = "account.name";
|
|
|
|
private static final String FILES = "files";
|
|
|
|
private static final String FILE_DOWNLOAD_URL = "fileDownloadUrl";
|
|
|
|
private static final String FILE_URL = "fileUrl";
|
|
|
|
private static final String PLAYLIST_URL = "playlistUrl";
|
|
|
|
private static final String RESOLUTION_ID = "resolution.id";
|
|
|
|
private static final String STREAMING_PLAYLISTS = "streamingPlaylists";
|
|
|
|
|
2020-01-24 20:16:24 +01:00
|
|
|
private final String baseUrl;
|
2018-10-11 21:10:22 +02:00
|
|
|
private JsonObject json;
|
2022-03-03 20:46:53 +01:00
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
private final List<SubtitlesStream> subtitles = new ArrayList<>();
|
2022-03-03 20:46:53 +01:00
|
|
|
private final List<AudioStream> audioStreams = new ArrayList<>();
|
|
|
|
private final List<VideoStream> videoStreams = new ArrayList<>();
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2022-03-18 10:25:16 +01:00
|
|
|
public PeertubeStreamExtractor(final StreamingService service, final LinkHandler linkHandler)
|
|
|
|
throws ParsingException {
|
2019-11-19 22:38:17 +01:00
|
|
|
super(service, linkHandler);
|
2019-11-22 19:35:49 +01:00
|
|
|
this.baseUrl = getBaseUrl();
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2019-11-19 22:38:17 +01:00
|
|
|
public String getTextualUploadDate() throws ParsingException {
|
|
|
|
return JsonUtils.getString(json, "publishedAt");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2019-11-19 22:38:17 +01:00
|
|
|
@Override
|
|
|
|
public DateWrapper getUploadDate() throws ParsingException {
|
|
|
|
final String textualUploadDate = getTextualUploadDate();
|
|
|
|
|
|
|
|
if (textualUploadDate == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new DateWrapper(PeertubeParsingHelper.parseDateFrom(textualUploadDate));
|
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
|
|
|
public String getThumbnailUrl() throws ParsingException {
|
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 baseUrl + JsonUtils.getString(json, "previewPath");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2020-02-06 23:35:46 +01:00
|
|
|
public Description getDescription() throws ParsingException {
|
|
|
|
String text;
|
2018-10-11 22:29:13 +02:00
|
|
|
try {
|
2020-02-06 23:35:46 +01:00
|
|
|
text = JsonUtils.getString(json, "description");
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final ParsingException e) {
|
2022-03-17 14:47:08 +01:00
|
|
|
return Description.EMPTY_DESCRIPTION;
|
2018-10-11 22:29:13 +02:00
|
|
|
}
|
2020-02-06 23:35:46 +01:00
|
|
|
if (text.length() == 250 && text.substring(247).equals("...")) {
|
2022-03-03 20:46:53 +01:00
|
|
|
// If description is shortened, get full description
|
2020-04-10 10:25:53 +02:00
|
|
|
final Downloader dl = NewPipe.getDownloader();
|
2020-01-20 14:36:12 +01:00
|
|
|
try {
|
2020-04-09 19:46:20 +02:00
|
|
|
final Response response = dl.get(baseUrl
|
|
|
|
+ PeertubeStreamLinkHandlerFactory.VIDEO_API_ENDPOINT
|
|
|
|
+ getId() + "/description");
|
2020-04-10 10:25:53 +02:00
|
|
|
final JsonObject jsonObject = JsonParser.object().from(response.responseBody());
|
2020-02-06 23:35:46 +01:00
|
|
|
text = JsonUtils.getString(jsonObject, "description");
|
2022-03-03 20:46:53 +01:00
|
|
|
} catch (final IOException | ReCaptchaException | JsonParserException ignored) {
|
|
|
|
// Something went wrong when getting the full description, use the shortened one
|
2020-01-20 14:36:12 +01:00
|
|
|
}
|
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-02-07 13:28:27 +01:00
|
|
|
return new Description(text, Description.MARKDOWN);
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getAgeLimit() throws ParsingException {
|
2020-04-10 10:25:53 +02:00
|
|
|
final boolean isNSFW = JsonUtils.getBoolean(json, "nsfw");
|
2020-01-23 04:42:54 +01:00
|
|
|
if (isNSFW) {
|
|
|
|
return 18;
|
|
|
|
} else {
|
|
|
|
return NO_AGE_LIMIT;
|
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-06-13 20:25:38 +02:00
|
|
|
public long getLength() {
|
|
|
|
return json.getLong("duration");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-09 20:02:41 +02:00
|
|
|
public long getTimeStamp() throws ParsingException {
|
2022-03-03 20:46:53 +01:00
|
|
|
final long timestamp = getTimestampSeconds(
|
|
|
|
"((#|&|\\?)start=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)");
|
2020-04-09 20:02:41 +02:00
|
|
|
|
|
|
|
if (timestamp == -2) {
|
|
|
|
// regex for timestamp was not found
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return timestamp;
|
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-06-13 20:25:38 +02:00
|
|
|
public long getViewCount() {
|
|
|
|
return json.getLong("views");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-06-13 20:25:38 +02:00
|
|
|
public long getLikeCount() {
|
|
|
|
return json.getLong("likes");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-06-13 20:25:38 +02:00
|
|
|
public long getDislikeCount() {
|
|
|
|
return json.getLong("dislikes");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
|
|
|
public String getUploaderUrl() throws ParsingException {
|
2022-03-03 20:46:53 +01:00
|
|
|
final String name = JsonUtils.getString(json, ACCOUNT_NAME);
|
|
|
|
final String host = JsonUtils.getString(json, ACCOUNT_HOST);
|
|
|
|
return getService().getChannelLHFactory().fromId("accounts/" + name + "@" + host, baseUrl)
|
|
|
|
.getUrl();
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
|
|
|
public String getUploaderName() throws ParsingException {
|
|
|
|
return JsonUtils.getString(json, "account.displayName");
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public String getUploaderAvatarUrl() {
|
2018-10-11 22:29:13 +02:00
|
|
|
String value;
|
|
|
|
try {
|
|
|
|
value = JsonUtils.getString(json, "account.avatar.path");
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final Exception e) {
|
2018-10-11 22:29:13 +02:00
|
|
|
value = "/client/assets/images/default-avatar.png";
|
|
|
|
}
|
2019-11-21 01:05:22 +01:00
|
|
|
return baseUrl + value;
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2020-04-13 22:34:20 +02:00
|
|
|
@Override
|
2020-04-16 14:19:36 +02:00
|
|
|
public String getSubChannelUrl() throws ParsingException {
|
2020-04-13 22:34:20 +02:00
|
|
|
return JsonUtils.getString(json, "channel.url");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-16 14:19:36 +02:00
|
|
|
public String getSubChannelName() throws ParsingException {
|
2020-04-13 22:34:20 +02:00
|
|
|
return JsonUtils.getString(json, "channel.displayName");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public String getSubChannelAvatarUrl() {
|
2020-04-13 22:34:20 +02:00
|
|
|
String value;
|
|
|
|
try {
|
|
|
|
value = JsonUtils.getString(json, "channel.avatar.path");
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final Exception e) {
|
2020-04-13 22:34:20 +02:00
|
|
|
value = "/client/assets/images/default-avatar.png";
|
|
|
|
}
|
|
|
|
return baseUrl + value;
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public String getHlsUrl() {
|
2022-03-03 20:46:53 +01:00
|
|
|
assertPageFetched();
|
2018-10-11 21:10:22 +02:00
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
if (getStreamType() == StreamType.VIDEO_STREAM
|
|
|
|
&& !isNullOrEmpty(json.getObject(FILES))) {
|
2022-08-15 05:49:40 +02:00
|
|
|
return json.getObject(FILES).getString(PLAYLIST_URL, "");
|
2022-03-03 20:46:53 +01:00
|
|
|
}
|
2022-03-15 11:19:13 +01:00
|
|
|
|
2022-08-15 05:49:40 +02:00
|
|
|
return json.getArray(STREAMING_PLAYLISTS).getObject(0).getString(PLAYLIST_URL, "");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-03-03 20:46:53 +01:00
|
|
|
public List<AudioStream> getAudioStreams() throws ParsingException {
|
2018-10-11 21:10:22 +02:00
|
|
|
assertPageFetched();
|
2022-03-18 10:25:16 +01:00
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
/*
|
2022-03-15 11:19:13 +01:00
|
|
|
Some videos have audio streams; others don't.
|
2022-03-03 20:46:53 +01:00
|
|
|
So an audio stream may be available if a video stream is available.
|
|
|
|
Audio streams are also not returned as separated streams for livestreams.
|
|
|
|
That's why the extraction of audio streams is only run when there are video streams
|
|
|
|
extracted and when the content is not a livestream.
|
|
|
|
*/
|
|
|
|
if (audioStreams.isEmpty() && videoStreams.isEmpty()
|
|
|
|
&& getStreamType() == StreamType.VIDEO_STREAM) {
|
|
|
|
getStreams();
|
2021-05-15 12:39:23 +02:00
|
|
|
}
|
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
return audioStreams;
|
2021-05-15 12:39:23 +02:00
|
|
|
}
|
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
@Override
|
|
|
|
public List<VideoStream> getVideoStreams() throws ExtractionException {
|
|
|
|
assertPageFetched();
|
|
|
|
|
|
|
|
if (videoStreams.isEmpty()) {
|
|
|
|
if (getStreamType() == StreamType.VIDEO_STREAM) {
|
|
|
|
getStreams();
|
|
|
|
} else {
|
|
|
|
extractLiveVideoStreams();
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
return videoStreams;
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public List<VideoStream> getVideoOnlyStreams() {
|
2020-06-13 20:25:38 +02:00
|
|
|
return Collections.emptyList();
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public List<SubtitlesStream> getSubtitlesDefault() {
|
2019-11-16 00:00:13 +01:00
|
|
|
return subtitles;
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public List<SubtitlesStream> getSubtitles(final MediaFormat format) {
|
2022-03-03 20:46:53 +01:00
|
|
|
return subtitles.stream()
|
|
|
|
.filter(sub -> sub.getFormat() == format)
|
|
|
|
.collect(Collectors.toList());
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public StreamType getStreamType() {
|
2021-06-18 16:25:10 +02:00
|
|
|
return json.getBoolean("isLive") ? StreamType.LIVE_STREAM : StreamType.VIDEO_STREAM;
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-10-24 21:17:58 +02:00
|
|
|
@Nullable
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2021-03-31 20:21:49 +02:00
|
|
|
public StreamInfoItemsCollector getRelatedItems() throws IOException, ExtractionException {
|
2020-04-10 10:25:53 +02:00
|
|
|
final List<String> tags = getTags();
|
|
|
|
final String apiUrl;
|
2020-10-24 21:17:58 +02:00
|
|
|
if (tags.isEmpty()) {
|
2022-03-03 20:46:53 +01:00
|
|
|
apiUrl = baseUrl + "/api/v1/accounts/" + JsonUtils.getString(json, ACCOUNT_NAME)
|
|
|
|
+ "@" + JsonUtils.getString(json, ACCOUNT_HOST)
|
2022-03-18 10:25:16 +01:00
|
|
|
+ "/videos?start=0&count=8";
|
2020-10-24 21:17:58 +02:00
|
|
|
} else {
|
2021-03-31 20:21:49 +02:00
|
|
|
apiUrl = getRelatedItemsUrl(tags);
|
2020-10-24 21:17:58 +02:00
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2020-10-24 21:17:58 +02:00
|
|
|
if (Utils.isBlank(apiUrl)) {
|
|
|
|
return null;
|
2020-01-24 20:16:24 +01:00
|
|
|
} else {
|
2022-03-03 20:46:53 +01:00
|
|
|
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(
|
|
|
|
getServiceId());
|
2020-10-24 21:17:58 +02:00
|
|
|
getStreamsFromApi(collector, apiUrl);
|
|
|
|
return collector;
|
2018-12-26 09:59:23 +01:00
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
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-09 18:18:43 +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-01-24 20:16:24 +01:00
|
|
|
public List<String> getTags() {
|
2020-02-09 11:59:23 +01:00
|
|
|
return JsonUtils.getStringListFromJsonArray(json.getArray("tags"));
|
2018-12-26 09:59:23 +01:00
|
|
|
}
|
2020-01-23 14:19:22 +01:00
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public String getSupportInfo() {
|
2020-01-23 14:37:14 +01:00
|
|
|
try {
|
|
|
|
return JsonUtils.getString(json, "support");
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final ParsingException e) {
|
2022-08-15 05:49:40 +02:00
|
|
|
return "";
|
2020-01-23 14:37:14 +01:00
|
|
|
}
|
2020-01-23 14:19:22 +01:00
|
|
|
}
|
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
@Nonnull
|
|
|
|
private String getRelatedItemsUrl(@Nonnull final List<String> tags)
|
|
|
|
throws UnsupportedEncodingException {
|
2020-04-10 10:25:53 +02:00
|
|
|
final String url = baseUrl + PeertubeSearchQueryHandlerFactory.SEARCH_ENDPOINT;
|
|
|
|
final StringBuilder params = new StringBuilder();
|
2018-12-26 09:59:23 +01:00
|
|
|
params.append("start=0&count=8&sort=-createdAt");
|
2020-04-10 10:25:53 +02:00
|
|
|
for (final String tag : tags) {
|
2018-12-26 09:59:23 +01:00
|
|
|
params.append("&tagsOneOf=");
|
2022-07-28 04:19:21 +02:00
|
|
|
params.append(URLEncoder.encode(tag, StandardCharsets.UTF_8.name()));
|
2018-12-26 09:59:23 +01:00
|
|
|
}
|
2022-03-18 10:25:16 +01:00
|
|
|
return url + "?" + params;
|
2018-12-26 09:59:23 +01:00
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
|
2022-03-18 10:25:16 +01:00
|
|
|
private void getStreamsFromApi(final StreamInfoItemsCollector collector, final String apiUrl)
|
2022-03-03 20:46:53 +01:00
|
|
|
throws IOException, ReCaptchaException, ParsingException {
|
2020-04-10 10:25:53 +02:00
|
|
|
final Response response = getDownloader().get(apiUrl);
|
2018-10-11 21:10:22 +02:00
|
|
|
JsonObject relatedVideosJson = null;
|
2020-04-10 10:25:53 +02:00
|
|
|
if (response != null && !Utils.isBlank(response.responseBody())) {
|
2018-10-11 21:10:22 +02:00
|
|
|
try {
|
2019-11-19 22:38:17 +01:00
|
|
|
relatedVideosJson = JsonParser.object().from(response.responseBody());
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final JsonParserException e) {
|
2018-10-11 21:10:22 +02:00
|
|
|
throw new ParsingException("Could not parse json data for related videos", e);
|
|
|
|
}
|
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
|
|
|
if (relatedVideosJson != null) {
|
2018-10-11 21:10:22 +02:00
|
|
|
collectStreamsFrom(collector, relatedVideosJson);
|
|
|
|
}
|
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2022-03-18 10:25:16 +01:00
|
|
|
private void collectStreamsFrom(final StreamInfoItemsCollector collector,
|
2022-03-03 20:46:53 +01:00
|
|
|
final JsonObject jsonObject) throws ParsingException {
|
2020-04-10 10:25:53 +02:00
|
|
|
final JsonArray contents;
|
2018-10-11 21:10:22 +02:00
|
|
|
try {
|
2022-03-18 10:25:16 +01:00
|
|
|
contents = (JsonArray) JsonUtils.getValue(jsonObject, "data");
|
|
|
|
} catch (final Exception e) {
|
2022-03-03 20:46:53 +01:00
|
|
|
throw new ParsingException("Could not extract related videos", e);
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2020-04-10 10:25:53 +02:00
|
|
|
for (final Object c : contents) {
|
2020-01-24 20:16:24 +01:00
|
|
|
if (c instanceof JsonObject) {
|
2018-10-11 21:10:22 +02:00
|
|
|
final JsonObject item = (JsonObject) c;
|
2022-03-03 20:46:53 +01:00
|
|
|
final PeertubeStreamInfoItemExtractor extractor =
|
|
|
|
new PeertubeStreamInfoItemExtractor(item, baseUrl);
|
|
|
|
// Do not add the same stream in related streams
|
2022-03-18 10:25:16 +01:00
|
|
|
if (!extractor.getUrl().equals(getUrl())) {
|
|
|
|
collector.commit(extractor);
|
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
2022-03-17 16:25:49 +01:00
|
|
|
public void onFetchPage(@Nonnull final Downloader downloader)
|
|
|
|
throws IOException, ExtractionException {
|
2022-03-18 10:25:16 +01:00
|
|
|
final Response response = downloader.get(
|
|
|
|
baseUrl + PeertubeStreamLinkHandlerFactory.VIDEO_API_ENDPOINT + getId());
|
2021-03-14 00:45:44 +01:00
|
|
|
if (response != null) {
|
2019-11-19 22:38:17 +01:00
|
|
|
setInitialData(response.responseBody());
|
2020-01-24 20:16:24 +01:00
|
|
|
} else {
|
2022-03-03 20:46:53 +01:00
|
|
|
throw new ExtractionException("Could not extract PeerTube channel data");
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2019-11-16 00:00:13 +01:00
|
|
|
loadSubtitles();
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
|
|
|
|
2020-04-10 10:25:53 +02:00
|
|
|
private void setInitialData(final String responseBody) throws ExtractionException {
|
2018-10-11 21:10:22 +02:00
|
|
|
try {
|
|
|
|
json = JsonParser.object().from(responseBody);
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final JsonParserException e) {
|
2022-03-03 20:46:53 +01:00
|
|
|
throw new ExtractionException("Could not extract PeerTube stream data", e);
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
2020-04-09 19:46:20 +02:00
|
|
|
if (json == null) {
|
2022-03-03 20:46:53 +01:00
|
|
|
throw new ExtractionException("Could not extract PeerTube stream data");
|
2020-04-09 19:46:20 +02:00
|
|
|
}
|
2019-03-09 19:03:51 +01:00
|
|
|
PeertubeParsingHelper.validate(json);
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|
2020-01-24 20:16:24 +01:00
|
|
|
|
2019-11-16 00:00:13 +01:00
|
|
|
private void loadSubtitles() {
|
|
|
|
if (subtitles.isEmpty()) {
|
|
|
|
try {
|
2020-04-09 19:46:20 +02:00
|
|
|
final Response response = getDownloader().get(baseUrl
|
|
|
|
+ PeertubeStreamLinkHandlerFactory.VIDEO_API_ENDPOINT
|
|
|
|
+ getId() + "/captions");
|
2020-04-10 10:25:53 +02:00
|
|
|
final JsonObject captionsJson = JsonParser.object().from(response.responseBody());
|
|
|
|
final JsonArray captions = JsonUtils.getArray(captionsJson, "data");
|
|
|
|
for (final Object c : captions) {
|
2020-01-24 20:16:24 +01:00
|
|
|
if (c instanceof JsonObject) {
|
2020-04-10 10:25:53 +02:00
|
|
|
final JsonObject caption = (JsonObject) c;
|
|
|
|
final String url = baseUrl + JsonUtils.getString(caption, "captionPath");
|
|
|
|
final String languageCode = JsonUtils.getString(caption, "language.id");
|
|
|
|
final String ext = url.substring(url.lastIndexOf(".") + 1);
|
|
|
|
final MediaFormat fmt = MediaFormat.getFromSuffix(ext);
|
2022-03-18 10:25:16 +01:00
|
|
|
if (fmt != null && !isNullOrEmpty(languageCode)) {
|
2022-03-03 20:46:53 +01:00
|
|
|
subtitles.add(new SubtitlesStream.Builder()
|
|
|
|
.setContent(url, true)
|
|
|
|
.setMediaFormat(fmt)
|
|
|
|
.setLanguageCode(languageCode)
|
|
|
|
.setAutoGenerated(false)
|
|
|
|
.build());
|
2022-03-18 10:25:16 +01:00
|
|
|
}
|
2019-11-16 00:00:13 +01:00
|
|
|
}
|
|
|
|
}
|
2022-03-03 20:46:53 +01:00
|
|
|
} catch (final Exception ignored) {
|
|
|
|
// Ignore all exceptions
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void extractLiveVideoStreams() throws ParsingException {
|
|
|
|
try {
|
|
|
|
final JsonArray streamingPlaylists = json.getArray(STREAMING_PLAYLISTS);
|
2022-03-15 11:19:13 +01:00
|
|
|
streamingPlaylists.stream()
|
|
|
|
.filter(JsonObject.class::isInstance)
|
|
|
|
.map(JsonObject.class::cast)
|
|
|
|
.map(stream -> new VideoStream.Builder()
|
|
|
|
.setId(String.valueOf(stream.getInt("id", -1)))
|
2022-08-15 05:49:40 +02:00
|
|
|
.setContent(stream.getString(PLAYLIST_URL, ""), true)
|
2022-03-15 11:19:13 +01:00
|
|
|
.setIsVideoOnly(false)
|
2022-08-15 05:49:40 +02:00
|
|
|
.setResolution("")
|
2022-03-15 11:19:13 +01:00
|
|
|
.setMediaFormat(MediaFormat.MPEG_4)
|
|
|
|
.setDeliveryMethod(DeliveryMethod.HLS)
|
|
|
|
.build())
|
|
|
|
// Don't use the containsSimilarStream method because it will always return
|
|
|
|
// false so if there are multiples HLS URLs returned, only the first will be
|
|
|
|
// extracted in this case.
|
|
|
|
.forEachOrdered(videoStreams::add);
|
2022-03-03 20:46:53 +01:00
|
|
|
} catch (final Exception e) {
|
|
|
|
throw new ParsingException("Could not get video streams", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void getStreams() throws ParsingException {
|
|
|
|
// Progressive streams
|
2022-08-15 05:49:40 +02:00
|
|
|
getStreamsFromArray(json.getArray(FILES), "");
|
2022-03-03 20:46:53 +01:00
|
|
|
|
|
|
|
// HLS streams
|
|
|
|
try {
|
2022-03-15 11:19:13 +01:00
|
|
|
for (final JsonObject playlist : json.getArray(STREAMING_PLAYLISTS).stream()
|
|
|
|
.filter(JsonObject.class::isInstance)
|
|
|
|
.map(JsonObject.class::cast)
|
|
|
|
.collect(Collectors.toList())) {
|
|
|
|
getStreamsFromArray(playlist.getArray(FILES), playlist.getString(PLAYLIST_URL));
|
2022-03-03 20:46:53 +01:00
|
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
|
|
throw new ParsingException("Could not get streams", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void getStreamsFromArray(@Nonnull final JsonArray streams,
|
|
|
|
final String playlistUrl) throws ParsingException {
|
|
|
|
try {
|
|
|
|
/*
|
2022-03-15 11:19:13 +01:00
|
|
|
Starting with version 3.4.0 of PeerTube, the HLS playlist of stream resolutions
|
|
|
|
contains the UUID of the streams, so we can't use the same method to get the URL of
|
|
|
|
the HLS playlist without fetching the master playlist.
|
|
|
|
These UUIDs are the same as the ones returned into the fileUrl and fileDownloadUrl
|
2022-03-03 20:46:53 +01:00
|
|
|
strings.
|
|
|
|
*/
|
|
|
|
final boolean isInstanceUsingRandomUuidsForHlsStreams = !isNullOrEmpty(playlistUrl)
|
|
|
|
&& playlistUrl.endsWith("-master.m3u8");
|
|
|
|
|
2022-03-15 11:19:13 +01:00
|
|
|
for (final JsonObject stream : streams.stream()
|
|
|
|
.filter(JsonObject.class::isInstance)
|
|
|
|
.map(JsonObject.class::cast)
|
|
|
|
.collect(Collectors.toList())) {
|
2022-03-03 20:46:53 +01:00
|
|
|
|
|
|
|
// Extract stream version of streams first
|
2022-03-15 11:19:13 +01:00
|
|
|
final String url = JsonUtils.getString(stream,
|
|
|
|
stream.has(FILE_URL) ? FILE_URL : FILE_DOWNLOAD_URL);
|
2022-03-03 20:46:53 +01:00
|
|
|
if (isNullOrEmpty(url)) {
|
|
|
|
// Not a valid stream URL
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-15 11:19:13 +01:00
|
|
|
final String resolution = JsonUtils.getString(stream, "resolution.label");
|
|
|
|
final String idSuffix = stream.has(FILE_URL) ? FILE_URL : FILE_DOWNLOAD_URL;
|
|
|
|
|
2022-03-03 20:46:53 +01:00
|
|
|
if (resolution.toLowerCase().contains("audio")) {
|
|
|
|
// An audio stream
|
|
|
|
addNewAudioStream(stream, isInstanceUsingRandomUuidsForHlsStreams, resolution,
|
|
|
|
idSuffix, url, playlistUrl);
|
|
|
|
} else {
|
|
|
|
// A video stream
|
|
|
|
addNewVideoStream(stream, isInstanceUsingRandomUuidsForHlsStreams, resolution,
|
|
|
|
idSuffix, url, playlistUrl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
|
|
throw new ParsingException("Could not get streams from array", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
private String getHlsPlaylistUrlFromFragmentedFileUrl(
|
|
|
|
@Nonnull final JsonObject streamJsonObject,
|
|
|
|
@Nonnull final String idSuffix,
|
|
|
|
@Nonnull final String format,
|
|
|
|
@Nonnull final String url) throws ParsingException {
|
2022-03-15 11:19:13 +01:00
|
|
|
final String streamUrl = FILE_DOWNLOAD_URL.equals(idSuffix)
|
|
|
|
? JsonUtils.getString(streamJsonObject, FILE_URL)
|
|
|
|
: url;
|
2022-03-03 20:46:53 +01:00
|
|
|
return streamUrl.replace("-fragmented." + format, ".m3u8");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
private String getHlsPlaylistUrlFromMasterPlaylist(@Nonnull final JsonObject streamJsonObject,
|
|
|
|
@Nonnull final String playlistUrl)
|
|
|
|
throws ParsingException {
|
|
|
|
return playlistUrl.replace("master", JsonUtils.getNumber(streamJsonObject,
|
|
|
|
RESOLUTION_ID).toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void addNewAudioStream(@Nonnull final JsonObject streamJsonObject,
|
|
|
|
final boolean isInstanceUsingRandomUuidsForHlsStreams,
|
|
|
|
@Nonnull final String resolution,
|
|
|
|
@Nonnull final String idSuffix,
|
|
|
|
@Nonnull final String url,
|
|
|
|
@Nullable final String playlistUrl) throws ParsingException {
|
|
|
|
final String extension = url.substring(url.lastIndexOf(".") + 1);
|
|
|
|
final MediaFormat format = MediaFormat.getFromSuffix(extension);
|
|
|
|
final String id = resolution + "-" + extension;
|
|
|
|
|
|
|
|
// Add progressive HTTP streams first
|
|
|
|
audioStreams.add(new AudioStream.Builder()
|
|
|
|
.setId(id + "-" + idSuffix + "-" + DeliveryMethod.PROGRESSIVE_HTTP)
|
|
|
|
.setContent(url, true)
|
|
|
|
.setMediaFormat(format)
|
|
|
|
.setAverageBitrate(UNKNOWN_BITRATE)
|
|
|
|
.build());
|
|
|
|
|
|
|
|
// Then add HLS streams
|
|
|
|
if (!isNullOrEmpty(playlistUrl)) {
|
|
|
|
final String hlsStreamUrl;
|
|
|
|
if (isInstanceUsingRandomUuidsForHlsStreams) {
|
|
|
|
hlsStreamUrl = getHlsPlaylistUrlFromFragmentedFileUrl(streamJsonObject, idSuffix,
|
|
|
|
extension, url);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
hlsStreamUrl = getHlsPlaylistUrlFromMasterPlaylist(streamJsonObject, playlistUrl);
|
|
|
|
}
|
|
|
|
final AudioStream audioStream = new AudioStream.Builder()
|
|
|
|
.setId(id + "-" + DeliveryMethod.HLS)
|
|
|
|
.setContent(hlsStreamUrl, true)
|
|
|
|
.setDeliveryMethod(DeliveryMethod.HLS)
|
|
|
|
.setMediaFormat(format)
|
|
|
|
.setAverageBitrate(UNKNOWN_BITRATE)
|
2022-05-01 20:57:51 +02:00
|
|
|
.setManifestUrl(playlistUrl)
|
2022-03-03 20:46:53 +01:00
|
|
|
.build();
|
|
|
|
if (!Stream.containSimilarStream(audioStream, audioStreams)) {
|
|
|
|
audioStreams.add(audioStream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-15 11:19:13 +01:00
|
|
|
// Finally, add torrent URLs
|
2022-03-03 20:46:53 +01:00
|
|
|
final String torrentUrl = JsonUtils.getString(streamJsonObject, "torrentUrl");
|
|
|
|
if (!isNullOrEmpty(torrentUrl)) {
|
|
|
|
audioStreams.add(new AudioStream.Builder()
|
|
|
|
.setId(id + "-" + idSuffix + "-" + DeliveryMethod.TORRENT)
|
|
|
|
.setContent(torrentUrl, true)
|
|
|
|
.setDeliveryMethod(DeliveryMethod.TORRENT)
|
|
|
|
.setMediaFormat(format)
|
|
|
|
.setAverageBitrate(UNKNOWN_BITRATE)
|
|
|
|
.build());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void addNewVideoStream(@Nonnull final JsonObject streamJsonObject,
|
|
|
|
final boolean isInstanceUsingRandomUuidsForHlsStreams,
|
|
|
|
@Nonnull final String resolution,
|
|
|
|
@Nonnull final String idSuffix,
|
|
|
|
@Nonnull final String url,
|
|
|
|
@Nullable final String playlistUrl) throws ParsingException {
|
|
|
|
final String extension = url.substring(url.lastIndexOf(".") + 1);
|
|
|
|
final MediaFormat format = MediaFormat.getFromSuffix(extension);
|
|
|
|
final String id = resolution + "-" + extension;
|
|
|
|
|
|
|
|
// Add progressive HTTP streams first
|
|
|
|
videoStreams.add(new VideoStream.Builder()
|
|
|
|
.setId(id + "-" + idSuffix + "-" + DeliveryMethod.PROGRESSIVE_HTTP)
|
|
|
|
.setContent(url, true)
|
|
|
|
.setIsVideoOnly(false)
|
|
|
|
.setResolution(resolution)
|
|
|
|
.setMediaFormat(format)
|
|
|
|
.build());
|
|
|
|
|
|
|
|
// Then add HLS streams
|
|
|
|
if (!isNullOrEmpty(playlistUrl)) {
|
2022-03-15 11:19:13 +01:00
|
|
|
final String hlsStreamUrl = isInstanceUsingRandomUuidsForHlsStreams
|
|
|
|
? getHlsPlaylistUrlFromFragmentedFileUrl(streamJsonObject, idSuffix, extension,
|
|
|
|
url)
|
|
|
|
: getHlsPlaylistUrlFromMasterPlaylist(streamJsonObject, playlistUrl);
|
2022-03-03 20:46:53 +01:00
|
|
|
|
|
|
|
final VideoStream videoStream = new VideoStream.Builder()
|
|
|
|
.setId(id + "-" + DeliveryMethod.HLS)
|
|
|
|
.setContent(hlsStreamUrl, true)
|
|
|
|
.setIsVideoOnly(false)
|
|
|
|
.setDeliveryMethod(DeliveryMethod.HLS)
|
|
|
|
.setResolution(resolution)
|
|
|
|
.setMediaFormat(format)
|
2022-05-01 20:57:51 +02:00
|
|
|
.setManifestUrl(playlistUrl)
|
2022-03-03 20:46:53 +01:00
|
|
|
.build();
|
|
|
|
if (!Stream.containSimilarStream(videoStream, videoStreams)) {
|
|
|
|
videoStreams.add(videoStream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add finally torrent URLs
|
|
|
|
final String torrentUrl = JsonUtils.getString(streamJsonObject, "torrentUrl");
|
|
|
|
if (!isNullOrEmpty(torrentUrl)) {
|
|
|
|
videoStreams.add(new VideoStream.Builder()
|
|
|
|
.setId(id + "-" + idSuffix + "-" + DeliveryMethod.TORRENT)
|
|
|
|
.setContent(torrentUrl, true)
|
|
|
|
.setIsVideoOnly(false)
|
|
|
|
.setDeliveryMethod(DeliveryMethod.TORRENT)
|
|
|
|
.setResolution(resolution)
|
|
|
|
.setMediaFormat(format)
|
|
|
|
.build());
|
2019-11-16 00:00:13 +01:00
|
|
|
}
|
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
|
2020-04-09 18:18:43 +02:00
|
|
|
@Nonnull
|
2018-10-11 21:10:22 +02:00
|
|
|
@Override
|
|
|
|
public String getName() throws ParsingException {
|
|
|
|
return JsonUtils.getString(json, "name");
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +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
|
|
|
|
public String getHost() throws ParsingException {
|
2022-03-03 20:46:53 +01:00
|
|
|
return JsonUtils.getString(json, ACCOUNT_HOST);
|
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-09 18:18:43 +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-02-09 11:59:23 +01:00
|
|
|
public Privacy getPrivacy() {
|
|
|
|
switch (json.getObject("privacy").getInt("id")) {
|
|
|
|
case 1:
|
|
|
|
return Privacy.PUBLIC;
|
|
|
|
case 2:
|
|
|
|
return Privacy.UNLISTED;
|
|
|
|
case 3:
|
|
|
|
return Privacy.PRIVATE;
|
|
|
|
case 4:
|
|
|
|
return Privacy.INTERNAL;
|
|
|
|
default:
|
2021-02-12 20:34:46 +01:00
|
|
|
return Privacy.OTHER;
|
2020-02-09 11:59:23 +01:00
|
|
|
}
|
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-09 18:18:43 +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
|
|
|
|
public String getCategory() throws ParsingException {
|
|
|
|
return JsonUtils.getString(json, "category.label");
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:18:43 +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
|
|
|
|
public String getLicence() throws ParsingException {
|
|
|
|
return JsonUtils.getString(json, "licence.label");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-10 10:25:53 +02:00
|
|
|
public Locale getLanguageInfo() {
|
2020-01-25 13:16:42 +01:00
|
|
|
try {
|
|
|
|
return new Locale(JsonUtils.getString(json, "language.id"));
|
2022-03-18 10:25:16 +01:00
|
|
|
} catch (final ParsingException e) {
|
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
|
|
|
}
|
2018-10-11 21:10:22 +02:00
|
|
|
}
|