Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1d7a86e
[Test] Add base classes for stream extractor tests
Stypox Apr 9, 2020
7fb867c
[YouTube] Fix error message obtaining when there is none
Stypox Apr 9, 2020
7cd410f
[YouTube] Return 0 when there is no timestamp, not -2, as per javadoc
Stypox Apr 9, 2020
072bae3
[YouTube] Fix frame extraction for livestreams
Stypox Apr 9, 2020
3b2cfb4
[SoundCloud] Return empty video stream list instead of null
Stypox Apr 9, 2020
4349be1
[PeerTube] Return empty audio stream list instead of null
Stypox Apr 9, 2020
7ae3cb6
[PeerTube] Fix link handler inconsistency providing API links
Stypox Apr 9, 2020
aeeae87
[PeerTube] Parse timestamp from url (previously unimplemented)
Stypox Apr 9, 2020
b461da7
[MediaCCC] Fix link handler inconsistency providing API links
Stypox Apr 9, 2020
3b2a182
[MediaCCC] Extract tags
Stypox Apr 9, 2020
492db83
[MediaCCC] Return null instead of empty items collector
Stypox Apr 9, 2020
d130fd7
[PeerTube] Prepend "accounts/" to channel id for backward compatibility
Stypox Apr 11, 2020
0c980b2
[PeerTube] Improve channel and stream link handler tests
Stypox Apr 11, 2020
07a90d1
[MediaCCC] Use regex to parse stream and conference urls
Stypox Apr 11, 2020
af5b8b1
[MediaCCC] Add tests for stream and conference link handlers
Stypox Apr 11, 2020
fcb9b6f
[MediaCCC] Use final when possible, ide refactorings
Stypox Apr 11, 2020
06430c4
[PeerTube] Use final when possible, ide refactorings
Stypox Apr 11, 2020
55bc01d
[SoundCloud] Use final when possible, ide refactorings
Stypox Apr 11, 2020
3191bd6
[YouTube] Use final when possible
Stypox Apr 11, 2020
68d23de
[YouTube] Do not catch every exception on getErrorMessage
Stypox Apr 11, 2020
8dc3f28
[PeerTube] Test one channel url with api and one without
Stypox Apr 11, 2020
a4097d8
[MediaCCC] Return empty list of video-only streams instead of null
Stypox Apr 11, 2020
a087b09
[Test] Improve code style and add final
Stypox May 16, 2020
6127826
[Test] Add stream metadata tests
Stypox May 16, 2020
8ce711f
[Test] Add sub channel name, url and thumbnail tests
Stypox May 16, 2020
d0b1464
[YouTube/MediaCCC] Consider dates as GMT and not as local
Stypox May 16, 2020
880ff04
[Test] Add stream dash mpd url test
Stypox Jun 14, 2020
3c55ea9
[PeerTube] Change age restricted video in tests
Stypox Jun 14, 2020
f11fe87
[YouTube] Replace outdated PewDiePie video test with another one
Stypox Aug 14, 2020
57e7994
Add some missing finals, nullables and comments
Stypox Oct 24, 2020
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 @@ -13,6 +13,7 @@
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;

Expand Down Expand Up @@ -71,8 +72,8 @@ public String getParentChannelAvatarUrl() throws ParsingException {
@Nonnull
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() {
StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
JsonArray events = conferenceData.getArray("events");
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
final JsonArray events = conferenceData.getArray("events");
for (int i = 0; i < events.size(); i++) {
collector.commit(new MediaCCCStreamInfoItemExtractor(events.getObject(i)));
}
Expand All @@ -87,10 +88,11 @@ public InfoItemsPage<StreamInfoItem> getPage(final Page page) {
@Override
public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException {
final String conferenceUrl = MediaCCCConferenceLinkHandlerFactory.CONFERENCE_API_ENDPOINT + getId();
try {
conferenceData = JsonParser.object().from(downloader.get(getUrl()).responseBody());
conferenceData = JsonParser.object().from(downloader.get(conferenceUrl).responseBody());
} catch (JsonParserException jpe) {
throw new ExtractionException("Could not parse json returnd by url: " + getUrl());
throw new ExtractionException("Could not parse json returnd by url: " + conferenceUrl);
}
}

Expand All @@ -99,10 +101,4 @@ public void onFetchPage(@Nonnull final Downloader downloader)
public String getName() throws ParsingException {
return conferenceData.getString("title");
}

@Nonnull
@Override
public String getOriginalUrl() {
return "https://media.ccc.de/c/" + conferenceData.getString("acronym");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public final class MediaCCCParsingHelper {
private MediaCCCParsingHelper() { }

public static Calendar parseDateFrom(final String textualUploadDate) throws ParsingException {
Date date;
final Date date;
try {
date = new SimpleDateFormat("yyyy-MM-dd").parse(textualUploadDate);
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
date = sdf.parse(textualUploadDate);
} catch (ParseException e) {
throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class MediaCCCStreamExtractor extends StreamExtractor {
private JsonObject data;
Expand Down Expand Up @@ -93,7 +97,7 @@ public long getDislikeCount() {
@Nonnull
@Override
public String getUploaderUrl() {
return data.getString("conference_url");
return MediaCCCConferenceLinkHandlerFactory.CONFERENCE_PATH + getUploaderName();
}

@Nonnull
Expand All @@ -111,25 +115,25 @@ public String getUploaderAvatarUrl() {

@Nonnull
@Override
public String getSubChannelUrl() throws ParsingException {
public String getSubChannelUrl() {
return "";
}

@Nonnull
@Override
public String getSubChannelName() throws ParsingException {
public String getSubChannelName() {
return "";
}

@Nonnull
@Override
public String getSubChannelAvatarUrl() throws ParsingException {
public String getSubChannelAvatarUrl() {
return "";
}

@Nonnull
@Override
public String getDashMpdUrl() throws ParsingException {
public String getDashMpdUrl() {
return "";
}

Expand Down Expand Up @@ -194,7 +198,7 @@ public List<VideoStream> getVideoStreams() throws ExtractionException {

@Override
public List<VideoStream> getVideoOnlyStreams() {
return null;
return Collections.emptyList();
}

@Nonnull
Expand All @@ -214,9 +218,10 @@ public StreamType getStreamType() {
return StreamType.VIDEO_STREAM;
}

@Nullable
@Override
public StreamInfoItemsCollector getRelatedStreams() {
return new StreamInfoItemsCollector(getServiceId());
return null;
}

@Override
Expand All @@ -227,14 +232,13 @@ public String getErrorMessage() {
@Override
public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException {
final String videoUrl = MediaCCCStreamLinkHandlerFactory.VIDEO_API_ENDPOINT + getId();
try {
data = JsonParser.object().from(
downloader.get(getLinkHandler().getUrl()).responseBody());
data = JsonParser.object().from(downloader.get(videoUrl).responseBody());
conferenceData = JsonParser.object()
.from(downloader.get(getUploaderUrl()).responseBody());
.from(downloader.get(data.getString("conference_url")).responseBody());
} catch (JsonParserException jpe) {
throw new ExtractionException("Could not parse json returned by url: "
+ getLinkHandler().getUrl(), jpe);
throw new ExtractionException("Could not parse json returned by url: " + videoUrl, jpe);
}
}

Expand All @@ -250,21 +254,25 @@ public String getOriginalUrl() {
return data.getString("frontend_link");
}

@Nonnull
@Override
public String getHost() {
return "";
}

@Nonnull
@Override
public String getPrivacy() {
return "";
}

@Nonnull
@Override
public String getCategory() {
return "";
}

@Nonnull
@Override
public String getLicence() {
return "";
Expand All @@ -278,7 +286,7 @@ public Locale getLanguageInfo() {
@Nonnull
@Override
public List<String> getTags() {
return new ArrayList<>();
return Arrays.asList(data.getArray("tags").toArray(new String[0]));
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,26 @@
import java.util.List;

public class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory {
public static final String CONFERENCE_API_ENDPOINT = "https://api.media.ccc.de/public/conferences/";
public static final String CONFERENCE_PATH = "https://media.ccc.de/c/";
private static final String ID_PATTERN = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/conferences/)|(?:media\\.ccc\\.de/[bc]/))([^/?&#]*)";

@Override
public String getUrl(final String id, final List<String> contentFilter, final String sortFilter)
throws ParsingException {
return "https://media.ccc.de/public/conferences/" + id;
public String getUrl(final String id,
final List<String> contentFilter,
final String sortFilter) throws ParsingException {
return CONFERENCE_PATH + id;
}

@Override
public String getId(final String url) throws ParsingException {
if (url.startsWith("https://media.ccc.de/public/conferences/")
|| url.startsWith("https://api.media.ccc.de/public/conferences/")) {
return url.replaceFirst("https://(api\\.)?media\\.ccc\\.de/public/conferences/", "");
} else if (url.startsWith("https://media.ccc.de/c/")) {
return Parser.matchGroup1("https://media.ccc.de/c/([^?#]*)", url);
} else if (url.startsWith("https://media.ccc.de/b/")) {
return Parser.matchGroup1("https://media.ccc.de/b/([^?#]*)", url);
}
throw new ParsingException("Could not get id from url: " + url);
return Parser.matchGroup1(ID_PATTERN, url);
}

@Override
public boolean onAcceptUrl(final String url) {
try {
getId(url);
return true;
return getId(url) != null;
} catch (ParsingException e) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,27 @@

import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;

import java.net.MalformedURLException;
import java.net.URL;
import org.schabi.newpipe.extractor.utils.Parser;

public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory {
@Override
public String getId(final String urlString) throws ParsingException {
if (urlString.startsWith("https://media.ccc.de/public/events/")
&& !urlString.contains("?q=")) {
return urlString.substring(35); //remove …/public/events part
}
public static final String VIDEO_API_ENDPOINT = "https://api.media.ccc.de/public/events/";
private static final String VIDEO_PATH = "https://media.ccc.de/v/";
private static final String ID_PATTERN = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/events/)|(?:media\\.ccc\\.de/v/))([^/?&#]*)";

if (urlString.startsWith("https://api.media.ccc.de/public/events/")
&& !urlString.contains("?q=")) {
return urlString.substring(39); //remove api…/public/events part
}

URL url;
try {
url = Utils.stringToURL(urlString);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("The given URL is not valid");
}

String path = url.getPath();
// remove leading "/" of URL-path if URL-path is given
if (!path.isEmpty()) {
path = path.substring(1);
}

if (path.startsWith("v/")) {
return path.substring(2);
}

throw new ParsingException("Could not get id from url: " + url);
@Override
public String getId(final String url) throws ParsingException {
return Parser.matchGroup1(ID_PATTERN, url);
}

@Override
public String getUrl(final String id) throws ParsingException {
return "https://media.ccc.de/public/events/" + id;
return VIDEO_PATH + id;
}

@Override
public boolean onAcceptUrl(final String url) {
try {
getId(url);
return true;
return getId(url) != null;
} catch (ParsingException e) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Utils;

import java.io.IOException;

import javax.annotation.Nonnull;

import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.COUNT_KEY;
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.ITEMS_PER_PAGE;
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.START_KEY;
Expand Down Expand Up @@ -85,14 +88,16 @@ public String getParentChannelAvatarUrl() {
return "";
}

@Nonnull
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException {
final String pageUrl = getUrl() + "/videos?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE;
return getPage(new Page(pageUrl));
return getPage(new Page(
getUrl() + "/videos?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE));
}

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

@Override
public void onFetchPage(final Downloader downloader) throws IOException, ExtractionException {
final Response response = downloader.get(getUrl());
public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException {
String accountUrl = baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT;
if (getId().contains("accounts/")) {
accountUrl += getId();
} else {
accountUrl += "accounts/" + getId();
}

final Response response = downloader.get(accountUrl);
if (response != null && response.responseBody() != null) {
setInitialData(response.responseBody());
} else {
Expand All @@ -140,13 +153,9 @@ private void setInitialData(final String responseBody) throws ExtractionExceptio
if (json == null) throw new ExtractionException("Unable to extract PeerTube account data");
}

@Nonnull
@Override
public String getName() throws ParsingException {
return JsonUtils.getString(json, "displayName");
}

@Override
public String getOriginalUrl() throws ParsingException {
return baseUrl + "/" + getId();
}
}
Loading