From 1e8474b22d387d280b06f174f7ff10ef8baa180b Mon Sep 17 00:00:00 2001 From: AudricV <74829229+AudricV@users.noreply.github.com> Date: Thu, 29 Jun 2023 19:08:34 +0200 Subject: [PATCH] [PeerTube] Add tabs support for accounts and video channels Support of channels and videos has been added for accounts and support of videos and playlists has been added for video channels. The following changes have been also done: - collectStreamsFrom method in PeertubeParsingHelper has been renamed to collectItemsFrom; - PeertubeChannelInfoItemExtractor.getStreamCount method has been fixed due to ChannelExtractor's new inheritance; - the declaration of the UnsupportedOperationException exception thrown has been added to the service's LinkHandlers; - a channel tab LinkHandlerFactory has been added, PeertubeChannelTabLinkHandlerFactory; - all service's LinkHandlers are now using properly the singleton pattern. Co-authored-by: ThetaDev Co-authored-by: Stypox --- .../services/media_ccc/MediaCCCService.java | 44 +++++++--- .../MediaCCCConferenceExtractor.java | 80 +++++++++++++++---- .../MediaCCCRecentKioskExtractor.java | 2 +- .../extractors/MediaCCCSearchExtractor.java | 3 +- .../MediaCCCConferenceLinkHandlerFactory.java | 18 ++++- ...aCCCConferencesListLinkHandlerFactory.java | 21 ++++- .../MediaCCCLiveListLinkHandlerFactory.java | 18 ++++- .../MediaCCCLiveStreamLinkHandlerFactory.java | 32 -------- .../MediaCCCRecentListLinkHandlerFactory.java | 19 ++++- .../MediaCCCSearchQueryHandlerFactory.java | 19 ++++- .../MediaCCCStreamLinkHandlerFactory.java | 17 +++- .../peertube/PeertubeParsingHelper.java | 29 ++++--- .../services/peertube/PeertubeService.java | 23 +++++- .../extractors/PeertubeAccountExtractor.java | 65 +++------------ .../extractors/PeertubeChannelExtractor.java | 55 +++---------- .../PeertubeChannelInfoItemExtractor.java | 4 +- .../PeertubeChannelTabExtractor.java | 80 +++++++++++++++++++ .../extractors/PeertubePlaylistExtractor.java | 4 +- .../extractors/PeertubeSearchExtractor.java | 4 +- .../extractors/PeertubeTrendingExtractor.java | 4 +- .../PeertubeChannelLinkHandlerFactory.java | 7 +- .../PeertubeChannelTabLinkHandlerFactory.java | 71 ++++++++++++++++ .../PeertubeCommentsLinkHandlerFactory.java | 8 +- .../PeertubePlaylistLinkHandlerFactory.java | 8 +- .../PeertubeSearchQueryHandlerFactory.java | 11 ++- .../PeertubeStreamLinkHandlerFactory.java | 4 +- .../PeertubeTrendingLinkHandlerFactory.java | 11 ++- 27 files changed, 440 insertions(+), 221 deletions(-) delete mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveStreamLinkHandlerFactory.java create mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelTabExtractor.java create mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelTabLinkHandlerFactory.java diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCService.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCService.java index ad745b70d..3e3a4726e 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCService.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCService.java @@ -6,6 +6,7 @@ import static java.util.Arrays.asList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelExtractor; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor; import org.schabi.newpipe.extractor.comments.CommentsExtractor; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.kiosk.KioskList; @@ -13,6 +14,7 @@ import org.schabi.newpipe.extractor.linkhandler.LinkHandler; import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; +import org.schabi.newpipe.extractor.linkhandler.ReadyChannelTabListLinkHandler; import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler; import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory; import org.schabi.newpipe.extractor.playlist.PlaylistExtractor; @@ -27,8 +29,6 @@ import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCSearch import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCStreamExtractor; import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory; import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferencesListLinkHandlerFactory; -import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCLiveListLinkHandlerFactory; -import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCRecentListLinkHandlerFactory; import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory; import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory; import org.schabi.newpipe.extractor.stream.StreamExtractor; @@ -47,12 +47,17 @@ public class MediaCCCService extends StreamingService { @Override public LinkHandlerFactory getStreamLHFactory() { - return new MediaCCCStreamLinkHandlerFactory(); + return MediaCCCStreamLinkHandlerFactory.getInstance(); } @Override public ListLinkHandlerFactory getChannelLHFactory() { - return new MediaCCCConferenceLinkHandlerFactory(); + return MediaCCCConferenceLinkHandlerFactory.getInstance(); + } + + @Override + public ListLinkHandlerFactory getChannelTabLHFactory() { + return null; } @Override @@ -62,7 +67,7 @@ public class MediaCCCService extends StreamingService { @Override public SearchQueryHandlerFactory getSearchQHFactory() { - return new MediaCCCSearchQueryHandlerFactory(); + return MediaCCCSearchQueryHandlerFactory.getInstance(); } @Override @@ -78,6 +83,22 @@ public class MediaCCCService extends StreamingService { return new MediaCCCConferenceExtractor(this, linkHandler); } + @Override + public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) { + if (linkHandler instanceof ReadyChannelTabListLinkHandler) { + return ((ReadyChannelTabListLinkHandler) linkHandler).getChannelTabExtractor(this); + } + + /* + Channel tab extractors are only supported in conferences and should only come from a + ReadyChannelTabListLinkHandler instance with a ChannelTabExtractorBuilder instance of the + conferences extractor + + If that's not the case, return null in this case, so no channel tabs support + */ + return null; + } + @Override public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) { return null; @@ -91,36 +112,37 @@ public class MediaCCCService extends StreamingService { @Override public KioskList getKioskList() throws ExtractionException { final KioskList list = new KioskList(this); + final ListLinkHandlerFactory h = MediaCCCConferencesListLinkHandlerFactory.getInstance(); // add kiosks here e.g.: try { list.addKioskEntry( (streamingService, url, kioskId) -> new MediaCCCConferenceKiosk( MediaCCCService.this, - new MediaCCCConferencesListLinkHandlerFactory().fromUrl(url), + h.fromUrl(url), kioskId ), - new MediaCCCConferencesListLinkHandlerFactory(), + h, MediaCCCConferenceKiosk.KIOSK_ID ); list.addKioskEntry( (streamingService, url, kioskId) -> new MediaCCCRecentKiosk( MediaCCCService.this, - new MediaCCCRecentListLinkHandlerFactory().fromUrl(url), + h.fromUrl(url), kioskId ), - new MediaCCCRecentListLinkHandlerFactory(), + h, MediaCCCRecentKiosk.KIOSK_ID ); list.addKioskEntry( (streamingService, url, kioskId) -> new MediaCCCLiveStreamKiosk( MediaCCCService.this, - new MediaCCCLiveListLinkHandlerFactory().fromUrl(url), + h.fromUrl(url), kioskId ), - new MediaCCCLiveListLinkHandlerFactory(), + h, MediaCCCLiveStreamKiosk.KIOSK_ID ); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java index 014affc96..48d85f7ca 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java @@ -1,23 +1,29 @@ package org.schabi.newpipe.extractor.services.media_ccc.extractors; -import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; + +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.ListExtractor; +import org.schabi.newpipe.extractor.MultiInfoItemsCollector; import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelExtractor; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs; import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; +import org.schabi.newpipe.extractor.linkhandler.ReadyChannelTabListLinkHandler; 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; + +import java.io.IOException; +import java.util.List; import javax.annotation.Nonnull; -import java.io.IOException; public class MediaCCCConferenceExtractor extends ChannelExtractor { private JsonObject conferenceData; @@ -74,18 +80,9 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor { @Nonnull @Override - public InfoItemsPage getInitialPage() { - 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))); - } - return new InfoItemsPage<>(collector, null); - } - - @Override - public InfoItemsPage getPage(final Page page) { - return InfoItemsPage.emptyPage(); + public List getTabs() throws ParsingException { + return List.of(new ReadyChannelTabListLinkHandler(getUrl(), getId(), + ChannelTabs.VIDEOS, new VideosTabExtractorBuilder(conferenceData))); } @Override @@ -105,4 +102,55 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor { public String getName() throws ParsingException { return conferenceData.getString("title"); } + + private static final class VideosTabExtractorBuilder + implements ReadyChannelTabListLinkHandler.ChannelTabExtractorBuilder { + + private final JsonObject conferenceData; + + VideosTabExtractorBuilder(final JsonObject conferenceData) { + this.conferenceData = conferenceData; + } + + @Nonnull + @Override + public ChannelTabExtractor build(@Nonnull final StreamingService service, + @Nonnull final ListLinkHandler linkHandler) { + return new VideosChannelTabExtractor(service, linkHandler, conferenceData); + } + } + + private static final class VideosChannelTabExtractor extends ChannelTabExtractor { + private final JsonObject conferenceData; + + VideosChannelTabExtractor(final StreamingService service, + final ListLinkHandler linkHandler, + final JsonObject conferenceData) { + super(service, linkHandler); + this.conferenceData = conferenceData; + } + + @Override + public void onFetchPage(@Nonnull final Downloader downloader) { + // Nothing to do here, as data was already fetched + } + + @Nonnull + @Override + public ListExtractor.InfoItemsPage getInitialPage() { + final MultiInfoItemsCollector collector = + new MultiInfoItemsCollector(getServiceId()); + conferenceData.getArray("events") + .stream() + .filter(JsonObject.class::isInstance) + .map(JsonObject.class::cast) + .forEach(event -> collector.commit(new MediaCCCStreamInfoItemExtractor(event))); + return new InfoItemsPage<>(collector, null); + } + + @Override + public InfoItemsPage getPage(final Page page) { + return InfoItemsPage.emptyPage(); + } + } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCRecentKioskExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCRecentKioskExtractor.java index 1e18f8da1..cef496d9d 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCRecentKioskExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCRecentKioskExtractor.java @@ -65,7 +65,7 @@ public class MediaCCCRecentKioskExtractor implements StreamInfoItemExtractor { @Override public String getUploaderUrl() throws ParsingException { - return new MediaCCCConferenceLinkHandlerFactory() + return MediaCCCConferenceLinkHandlerFactory.getInstance() .fromUrl(event.getString("conference_url")) // API URL .getUrl(); // web URL } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCSearchExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCSearchExtractor.java index e9c300b8a..c4501f5c2 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCSearchExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCSearchExtractor.java @@ -38,7 +38,8 @@ public class MediaCCCSearchExtractor extends SearchExtractor { super(service, linkHandler); try { conferenceKiosk = new MediaCCCConferenceKiosk(service, - new MediaCCCConferencesListLinkHandlerFactory().fromId("conferences"), + MediaCCCConferencesListLinkHandlerFactory.getInstance() + .fromId("conferences"), "conferences"); } catch (final Exception e) { e.printStackTrace(); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java index ddbd2e8e6..b6f88c331 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java @@ -6,7 +6,11 @@ import org.schabi.newpipe.extractor.utils.Parser; import java.util.List; -public class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory { +public final class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory { + + private static final MediaCCCConferenceLinkHandlerFactory INSTANCE + = new MediaCCCConferenceLinkHandlerFactory(); + 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/"; @@ -14,15 +18,23 @@ public class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/conferences/)" + "|(?:media\\.ccc\\.de/[bc]/))([^/?&#]*)"; + private MediaCCCConferenceLinkHandlerFactory() { + } + + public static MediaCCCConferenceLinkHandlerFactory getInstance() { + return INSTANCE; + } + @Override public String getUrl(final String id, final List contentFilter, - final String sortFilter) throws ParsingException { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { return CONFERENCE_PATH + id; } @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return Parser.matchGroup1(ID_PATTERN, url); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferencesListLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferencesListLinkHandlerFactory.java index f5dc8c6cf..f2b1e3b20 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferencesListLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferencesListLinkHandlerFactory.java @@ -5,15 +5,28 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; import java.util.List; -public class MediaCCCConferencesListLinkHandlerFactory extends ListLinkHandlerFactory { +public final class MediaCCCConferencesListLinkHandlerFactory extends ListLinkHandlerFactory { + + private static final MediaCCCConferencesListLinkHandlerFactory INSTANCE = + new MediaCCCConferencesListLinkHandlerFactory(); + + private MediaCCCConferencesListLinkHandlerFactory() { + } + + public static MediaCCCConferencesListLinkHandlerFactory getInstance() { + return INSTANCE; + } + @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return "conferences"; } @Override - public String getUrl(final String id, final List contentFilter, - final String sortFilter) throws ParsingException { + public String getUrl(final String id, + final List contentFilter, + final String sortFilter) + throws ParsingException, UnsupportedOperationException { return "https://media.ccc.de/public/conferences"; } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveListLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveListLinkHandlerFactory.java index f66e5c808..e92d2dfef 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveListLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveListLinkHandlerFactory.java @@ -6,11 +6,22 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; import java.util.List; import java.util.regex.Pattern; -public class MediaCCCLiveListLinkHandlerFactory extends ListLinkHandlerFactory { +public final class MediaCCCLiveListLinkHandlerFactory extends ListLinkHandlerFactory { + + private static final MediaCCCLiveListLinkHandlerFactory INSTANCE = + new MediaCCCLiveListLinkHandlerFactory(); + private static final String STREAM_PATTERN = "^(?:https?://)?media\\.ccc\\.de/live$"; + private MediaCCCLiveListLinkHandlerFactory() { + } + + public static MediaCCCLiveListLinkHandlerFactory getInstance() { + return INSTANCE; + } + @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return "live"; } @@ -22,7 +33,8 @@ public class MediaCCCLiveListLinkHandlerFactory extends ListLinkHandlerFactory { @Override public String getUrl(final String id, final List contentFilter, - final String sortFilter) throws ParsingException { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { // FIXME: wrong URL; should be https://streaming.media.ccc.de/{conference_slug}/{room_slug} return "https://media.ccc.de/live"; } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveStreamLinkHandlerFactory.java deleted file mode 100644 index f7b0c1f18..000000000 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCLiveStreamLinkHandlerFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.schabi.newpipe.extractor.services.media_ccc.linkHandler; - -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory; -import org.schabi.newpipe.extractor.utils.Parser; - -public class MediaCCCLiveStreamLinkHandlerFactory extends LinkHandlerFactory { - public static final String VIDEO_API_ENDPOINT = "https://api.media.ccc.de/public/events/"; - private static final String VIDEO_PATH = "https://streaming.media.ccc.de/v/"; - private static final String ID_PATTERN - = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/events/)" - + "|(?:media\\.ccc\\.de/v/))([^/?&#]*)"; - - @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 VIDEO_PATH + id; - } - - @Override - public boolean onAcceptUrl(final String url) { - try { - return getId(url) != null; - } catch (final ParsingException e) { - return false; - } - } -} diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCRecentListLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCRecentListLinkHandlerFactory.java index be2b10044..15b5ecf7d 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCRecentListLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCRecentListLinkHandlerFactory.java @@ -1,15 +1,27 @@ package org.schabi.newpipe.extractor.services.media_ccc.linkHandler; +import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; import java.util.List; import java.util.regex.Pattern; -public class MediaCCCRecentListLinkHandlerFactory extends ListLinkHandlerFactory { +public final class MediaCCCRecentListLinkHandlerFactory extends ListLinkHandlerFactory { + + private static final MediaCCCRecentListLinkHandlerFactory INSTANCE = + new MediaCCCRecentListLinkHandlerFactory(); + private static final String PATTERN = "^(https?://)?media\\.ccc\\.de/recent/?$"; + private MediaCCCRecentListLinkHandlerFactory() { + } + + public static MediaCCCRecentListLinkHandlerFactory getInstance() { + return INSTANCE; + } + @Override - public String getId(final String url) { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return "recent"; } @@ -21,7 +33,8 @@ public class MediaCCCRecentListLinkHandlerFactory extends ListLinkHandlerFactory @Override public String getUrl(final String id, final List contentFilter, - final String sortFilter) { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { return "https://media.ccc.de/recent"; } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCSearchQueryHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCSearchQueryHandlerFactory.java index 5a395dae6..3d9e76bfb 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCSearchQueryHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCSearchQueryHandlerFactory.java @@ -7,11 +7,22 @@ import org.schabi.newpipe.extractor.utils.Utils; import java.io.UnsupportedEncodingException; import java.util.List; -public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory { +public final class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory { + + private static final MediaCCCSearchQueryHandlerFactory INSTANCE = + new MediaCCCSearchQueryHandlerFactory(); + public static final String ALL = "all"; public static final String CONFERENCES = "conferences"; public static final String EVENTS = "events"; + private MediaCCCSearchQueryHandlerFactory() { + } + + public static MediaCCCSearchQueryHandlerFactory getInstance() { + return INSTANCE; + } + @Override public String[] getAvailableContentFilter() { return new String[]{ @@ -27,8 +38,10 @@ public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory } @Override - public String getUrl(final String query, final List contentFilter, - final String sortFilter) throws ParsingException { + public String getUrl(final String query, + final List contentFilter, + final String sortFilter) + throws ParsingException, UnsupportedOperationException { try { return "https://media.ccc.de/public/events/search?q=" + Utils.encodeUrlUtf8(query); } catch (final UnsupportedEncodingException e) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java index 3ae9c37d1..d433e69b5 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java @@ -5,7 +5,11 @@ import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory; import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper; import org.schabi.newpipe.extractor.utils.Parser; -public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { +public final class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { + + private static final MediaCCCStreamLinkHandlerFactory INSTANCE = + new MediaCCCStreamLinkHandlerFactory(); + 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 RECORDING_ID_PATTERN @@ -15,8 +19,15 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { private static final String LIVE_STREAM_ID_PATTERN = "streaming\\.media\\.ccc\\.de\\/(\\w+\\/\\w+)"; + private MediaCCCStreamLinkHandlerFactory() { + } + + public static MediaCCCStreamLinkHandlerFactory getInstance() { + return INSTANCE; + } + @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { String streamId = null; try { streamId = Parser.matchGroup1(LIVE_STREAM_ID_PATTERN, url); @@ -30,7 +41,7 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { } @Override - public String getUrl(final String id) throws ParsingException { + public String getUrl(final String id) throws ParsingException, UnsupportedOperationException { if (MediaCCCParsingHelper.isLiveStreamId(id)) { return LIVE_STREAM_PATH + id; } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java index 260c3409a..b57aa6b88 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java @@ -72,24 +72,29 @@ public final class PeertubeParsingHelper { } } - public static void collectStreamsFrom(final InfoItemsCollector collector, - final JsonObject json, - final String baseUrl) throws ParsingException { - collectStreamsFrom(collector, json, baseUrl, false); + public static void collectItemsFrom(final InfoItemsCollector collector, + final JsonObject json, + final String baseUrl) throws ParsingException { + collectItemsFrom(collector, json, baseUrl, false); } /** - * Collect stream from json with collector + * Collect items from the given JSON object with the given collector. + * + *

+ * Supported info item types are streams with their Sepia variant, channels and playlists. + *

* * @param collector the collector used to collect information - * @param json the file to retrieve data from - * @param baseUrl the base Url of the instance - * @param sepia if we should use PeertubeSepiaStreamInfoItemExtractor + * @param json the JSOn response to retrieve data from + * @param baseUrl the base URL of the instance + * @param sepia if we should use {@code PeertubeSepiaStreamInfoItemExtractor} to extract + * streams or {@code PeertubeStreamInfoItemExtractor} otherwise */ - public static void collectStreamsFrom(final InfoItemsCollector collector, - final JsonObject json, - final String baseUrl, - final boolean sepia) throws ParsingException { + public static void collectItemsFrom(final InfoItemsCollector collector, + final JsonObject json, + final String baseUrl, + final boolean sepia) throws ParsingException { final JsonArray contents; try { contents = (JsonArray) JsonUtils.getValue(json, "data"); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeService.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeService.java index de25e2799..ddd9d5395 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeService.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeService.java @@ -6,6 +6,7 @@ import static java.util.Arrays.asList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelExtractor; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor; import org.schabi.newpipe.extractor.comments.CommentsExtractor; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.kiosk.KioskList; @@ -19,6 +20,7 @@ import org.schabi.newpipe.extractor.playlist.PlaylistExtractor; import org.schabi.newpipe.extractor.search.SearchExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeAccountExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeChannelExtractor; +import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeChannelTabExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeCommentsExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubePlaylistExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeSearchExtractor; @@ -26,6 +28,7 @@ import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeStreamE import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeSuggestionExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeTrendingExtractor; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory; +import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeCommentsLinkHandlerFactory; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubePlaylistLinkHandlerFactory; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory; @@ -60,6 +63,11 @@ public class PeertubeService extends StreamingService { return PeertubeChannelLinkHandlerFactory.getInstance(); } + @Override + public ListLinkHandlerFactory getChannelTabLHFactory() { + return PeertubeChannelTabLinkHandlerFactory.getInstance(); + } + @Override public ListLinkHandlerFactory getPlaylistLHFactory() { return PeertubePlaylistLinkHandlerFactory.getInstance(); @@ -103,6 +111,12 @@ public class PeertubeService extends StreamingService { } } + @Override + public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) + throws ExtractionException { + return new PeertubeChannelTabExtractor(this, linkHandler); + } + @Override public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) throws ExtractionException { @@ -136,17 +150,20 @@ public class PeertubeService extends StreamingService { @Override public KioskList getKioskList() throws ExtractionException { + final PeertubeTrendingLinkHandlerFactory h = + PeertubeTrendingLinkHandlerFactory.getInstance(); + final KioskList.KioskExtractorFactory kioskFactory = (streamingService, url, id) -> new PeertubeTrendingExtractor( PeertubeService.this, - new PeertubeTrendingLinkHandlerFactory().fromId(id), + h.fromId(id), id ); final KioskList list = new KioskList(this); // add kiosks here e.g.: - final PeertubeTrendingLinkHandlerFactory h = new PeertubeTrendingLinkHandlerFactory(); + try { list.addKioskEntry(kioskFactory, h, PeertubeTrendingLinkHandlerFactory.KIOSK_TRENDING); list.addKioskEntry(kioskFactory, h, @@ -160,6 +177,4 @@ public class PeertubeService extends StreamingService { return list; } - - } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java index 6a8c2dcf2..eb95dcbe9 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java @@ -4,31 +4,23 @@ import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; -import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelExtractor; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs; import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Response; 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.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.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory; import org.schabi.newpipe.extractor.utils.JsonUtils; -import org.schabi.newpipe.extractor.utils.Utils; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; - -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; -import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectStreamsFrom; -import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; +import java.util.List; public class PeertubeAccountExtractor extends ChannelExtractor { private JsonObject json; @@ -119,54 +111,19 @@ public class PeertubeAccountExtractor extends ChannelExtractor { @Nonnull @Override - public InfoItemsPage getInitialPage() throws IOException, ExtractionException { - return getPage(new Page(baseUrl + "/api/v1/" + getId() + "/videos?" + START_KEY + "=0&" - + COUNT_KEY + "=" + ITEMS_PER_PAGE)); - } - - @Override - public InfoItemsPage getPage(final Page page) - throws IOException, ExtractionException { - if (page == null || isNullOrEmpty(page.getUrl())) { - throw new IllegalArgumentException("Page doesn't contain an URL"); - } - - final Response response = getDownloader().get(page.getUrl()); - - JsonObject pageJson = null; - if (response != null && !Utils.isBlank(response.responseBody())) { - try { - pageJson = JsonParser.object().from(response.responseBody()); - } catch (final Exception e) { - throw new ParsingException("Could not parse json data for account info", e); - } - } - - if (pageJson != null) { - PeertubeParsingHelper.validate(pageJson); - final long total = pageJson.getLong("total"); - - final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); - collectStreamsFrom(collector, pageJson, getBaseUrl()); - - return new InfoItemsPage<>(collector, - PeertubeParsingHelper.getNextPage(page.getUrl(), total)); - } else { - throw new ExtractionException("Unable to get PeerTube account info"); - } + public List getTabs() throws ParsingException { + return List.of( + PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(), + List.of(ChannelTabs.VIDEOS), "", getBaseUrl()), + PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(), + List.of(ChannelTabs.CHANNELS), "", getBaseUrl())); } @Override 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); + final Response response = downloader.get(baseUrl + + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + getId()); if (response != null) { setInitialData(response.responseBody()); } else { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java index f2a7b07e2..e7de3f061 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java @@ -3,30 +3,22 @@ package org.schabi.newpipe.extractor.services.peertube.extractors; import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; -import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelExtractor; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs; import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.exceptions.ExtractionException; 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.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory; import org.schabi.newpipe.extractor.utils.JsonUtils; -import org.schabi.newpipe.extractor.utils.Utils; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; - -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; -import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectStreamsFrom; -import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; +import java.util.List; public class PeertubeChannelExtractor extends ChannelExtractor { private JsonObject json; @@ -98,41 +90,12 @@ public class PeertubeChannelExtractor extends ChannelExtractor { @Nonnull @Override - public InfoItemsPage getInitialPage() throws IOException, ExtractionException { - return getPage(new Page(baseUrl + "/api/v1/" + getId() + "/videos?" + START_KEY + "=0&" - + COUNT_KEY + "=" + ITEMS_PER_PAGE)); - } - - @Override - public InfoItemsPage getPage(final Page page) - throws IOException, ExtractionException { - if (page == null || isNullOrEmpty(page.getUrl())) { - throw new IllegalArgumentException("Page doesn't contain an URL"); - } - - final Response response = getDownloader().get(page.getUrl()); - - JsonObject pageJson = null; - if (response != null && !Utils.isBlank(response.responseBody())) { - try { - pageJson = JsonParser.object().from(response.responseBody()); - } catch (final Exception e) { - throw new ParsingException("Could not parse json data for channel info", e); - } - } - - if (pageJson != null) { - PeertubeParsingHelper.validate(pageJson); - final long total = pageJson.getLong("total"); - - final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); - collectStreamsFrom(collector, pageJson, getBaseUrl()); - - return new InfoItemsPage<>(collector, - PeertubeParsingHelper.getNextPage(page.getUrl(), total)); - } else { - throw new ExtractionException("Unable to get PeerTube channel info"); - } + public List getTabs() throws ParsingException { + return List.of( + PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(), + List.of(ChannelTabs.VIDEOS), "", getBaseUrl()), + PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(), + List.of(ChannelTabs.PLAYLISTS), "", getBaseUrl())); } @Override diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelInfoItemExtractor.java index 3ab1be539..0faa25ea8 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelInfoItemExtractor.java @@ -1,7 +1,7 @@ package org.schabi.newpipe.extractor.services.peertube.extractors; import com.grack.nanojson.JsonObject; -import org.schabi.newpipe.extractor.channel.ChannelExtractor; +import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor; import org.schabi.newpipe.extractor.exceptions.ParsingException; @@ -52,7 +52,7 @@ public class PeertubeChannelInfoItemExtractor implements ChannelInfoItemExtracto @Override public long getStreamCount() throws ParsingException { - return ChannelExtractor.ITEM_COUNT_UNKNOWN; + return ListExtractor.ITEM_COUNT_UNKNOWN; } @Override diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelTabExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelTabExtractor.java new file mode 100644 index 000000000..fe8462bf8 --- /dev/null +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelTabExtractor.java @@ -0,0 +1,80 @@ +package org.schabi.newpipe.extractor.services.peertube.extractors; + +import com.grack.nanojson.JsonObject; +import com.grack.nanojson.JsonParser; +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.MultiInfoItemsCollector; +import org.schabi.newpipe.extractor.Page; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor; +import org.schabi.newpipe.extractor.downloader.Downloader; +import org.schabi.newpipe.extractor.downloader.Response; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +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.utils.Utils; + +import javax.annotation.Nonnull; +import java.io.IOException; + +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; +import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectItemsFrom; +import static org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory.getUrlSuffix; +import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; + +public class PeertubeChannelTabExtractor extends ChannelTabExtractor { + private final String baseUrl; + + public PeertubeChannelTabExtractor(final StreamingService service, + final ListLinkHandler linkHandler) + throws ParsingException { + super(service, linkHandler); + baseUrl = getBaseUrl(); + } + + @Override + public void onFetchPage(@Nonnull final Downloader downloader) { + } + + @Nonnull + @Override + public InfoItemsPage getInitialPage() throws IOException, ExtractionException { + return getPage(new Page(baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + + getId() + getUrlSuffix(getName()) + "?" + START_KEY + "=0&" + COUNT_KEY + "=" + + ITEMS_PER_PAGE)); + } + + @Override + public InfoItemsPage getPage(final Page page) + throws IOException, ExtractionException { + if (page == null || isNullOrEmpty(page.getUrl())) { + throw new IllegalArgumentException("Page doesn't contain an URL"); + } + + final Response response = getDownloader().get(page.getUrl()); + + JsonObject pageJson = null; + if (response != null && !Utils.isBlank(response.responseBody())) { + try { + pageJson = JsonParser.object().from(response.responseBody()); + } catch (final Exception e) { + throw new ParsingException("Could not parse json data for account info", e); + } + } + + if (pageJson == null) { + throw new ExtractionException("Unable to get account channel list"); + } + PeertubeParsingHelper.validate(pageJson); + + final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId()); + collectItemsFrom(collector, pageJson, getBaseUrl()); + + return new InfoItemsPage<>(collector, + PeertubeParsingHelper.getNextPage(page.getUrl(), pageJson.getLong("total"))); + } +} diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubePlaylistExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubePlaylistExtractor.java index 3d4ff9d19..a950375f0 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubePlaylistExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubePlaylistExtractor.java @@ -23,7 +23,7 @@ import java.io.IOException; 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; -import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectStreamsFrom; +import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectItemsFrom; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; public class PeertubePlaylistExtractor extends PlaylistExtractor { @@ -125,7 +125,7 @@ public class PeertubePlaylistExtractor extends PlaylistExtractor { final long total = json.getLong("total"); final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); - collectStreamsFrom(collector, json, getBaseUrl()); + collectItemsFrom(collector, json, getBaseUrl()); return new InfoItemsPage<>(collector, PeertubeParsingHelper.getNextPage(page.getUrl(), total)); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeSearchExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeSearchExtractor.java index 8be07855d..5f7ac45d4 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeSearchExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeSearchExtractor.java @@ -26,7 +26,7 @@ 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; -import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectStreamsFrom; +import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectItemsFrom; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; public class PeertubeSearchExtractor extends SearchExtractor { @@ -93,7 +93,7 @@ public class PeertubeSearchExtractor extends SearchExtractor { final long total = json.getLong("total"); final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId()); - collectStreamsFrom(collector, json, getBaseUrl(), sepia); + collectItemsFrom(collector, json, getBaseUrl(), sepia); return new InfoItemsPage<>(collector, PeertubeParsingHelper.getNextPage(page.getUrl(), total)); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeTrendingExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeTrendingExtractor.java index 2baca78ad..df4e4b7ea 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeTrendingExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeTrendingExtractor.java @@ -23,7 +23,7 @@ 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; -import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectStreamsFrom; +import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.collectItemsFrom; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; public class PeertubeTrendingExtractor extends KioskExtractor { @@ -69,7 +69,7 @@ public class PeertubeTrendingExtractor extends KioskExtractor { final long total = json.getLong("total"); final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); - collectStreamsFrom(collector, json, getBaseUrl()); + collectItemsFrom(collector, json, getBaseUrl()); return new InfoItemsPage<>(collector, PeertubeParsingHelper.getNextPage(page.getUrl(), total)); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java index 57a15d16d..8d858f89d 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java @@ -22,14 +22,15 @@ public final class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFact } @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return fixId(Parser.matchGroup(ID_PATTERN, url, 0)); } @Override public String getUrl(final String id, final List contentFilters, - final String searchFilter) throws ParsingException { + final String searchFilter) + throws ParsingException, UnsupportedOperationException { return getUrl(id, contentFilters, searchFilter, ServiceList.PeerTube.getBaseUrl()); } @@ -38,7 +39,7 @@ public final class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFact final List contentFilter, final String sortFilter, final String baseUrl) - throws ParsingException { + throws ParsingException, UnsupportedOperationException { if (id.matches(ID_PATTERN)) { return baseUrl + "/" + fixId(id); } else { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelTabLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelTabLinkHandlerFactory.java new file mode 100644 index 000000000..b924e1ac7 --- /dev/null +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelTabLinkHandlerFactory.java @@ -0,0 +1,71 @@ +package org.schabi.newpipe.extractor.services.peertube.linkHandler; + +import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.exceptions.UnsupportedTabException; +import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; + +import javax.annotation.Nonnull; +import java.util.List; + +public final class PeertubeChannelTabLinkHandlerFactory extends ListLinkHandlerFactory { + private static final PeertubeChannelTabLinkHandlerFactory INSTANCE + = new PeertubeChannelTabLinkHandlerFactory(); + + private PeertubeChannelTabLinkHandlerFactory() { + } + + public static PeertubeChannelTabLinkHandlerFactory getInstance() { + return INSTANCE; + } + + @Nonnull + public static String getUrlSuffix(@Nonnull final String tab) + throws UnsupportedTabException { + switch (tab) { + case ChannelTabs.VIDEOS: + return "/videos"; + case ChannelTabs.CHANNELS: // only available on accounts + return "/video-channels"; + case ChannelTabs.PLAYLISTS: // only available on channels + return "/video-playlists"; + } + throw new UnsupportedTabException(tab); + } + + @Override + public String getId(final String url) throws ParsingException, UnsupportedOperationException { + return PeertubeChannelLinkHandlerFactory.getInstance().getId(url); + } + + @Override + public String getUrl(final String id, final List contentFilter, final String sortFilter) + throws ParsingException, UnsupportedOperationException { + return PeertubeChannelLinkHandlerFactory.getInstance().getUrl(id) + + getUrlSuffix(contentFilter.get(0)); + } + + @Override + public String getUrl(final String id, + final List contentFilter, + final String sortFilter, + final String baseUrl) + throws ParsingException, UnsupportedOperationException { + return PeertubeChannelLinkHandlerFactory.getInstance().getUrl(id, null, null, baseUrl) + + getUrlSuffix(contentFilter.get(0)); + } + + @Override + public boolean onAcceptUrl(final String url) throws ParsingException { + return PeertubeChannelLinkHandlerFactory.getInstance().onAcceptUrl(url); + } + + @Override + public String[] getAvailableContentFilter() { + return new String[] { + ChannelTabs.VIDEOS, + ChannelTabs.CHANNELS, + ChannelTabs.PLAYLISTS, + }; + } +} diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeCommentsLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeCommentsLinkHandlerFactory.java index 366b0a159..816bcb183 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeCommentsLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeCommentsLinkHandlerFactory.java @@ -21,7 +21,7 @@ public final class PeertubeCommentsLinkHandlerFactory extends ListLinkHandlerFac } @Override - public String getId(final String url) throws ParsingException, IllegalArgumentException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return PeertubeStreamLinkHandlerFactory.getInstance().getId(url); // the same id is needed } @@ -33,7 +33,8 @@ public final class PeertubeCommentsLinkHandlerFactory extends ListLinkHandlerFac @Override public String getUrl(final String id, final List contentFilter, - final String sortFilter) throws ParsingException { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { return getUrl(id, contentFilter, sortFilter, ServiceList.PeerTube.getBaseUrl()); } @@ -41,7 +42,8 @@ public final class PeertubeCommentsLinkHandlerFactory extends ListLinkHandlerFac public String getUrl(final String id, final List contentFilter, final String sortFilter, - final String baseUrl) throws ParsingException { + final String baseUrl) + throws ParsingException, UnsupportedOperationException { return baseUrl + String.format(COMMENTS_ENDPOINT, id); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubePlaylistLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubePlaylistLinkHandlerFactory.java index a5318e581..c6183b140 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubePlaylistLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubePlaylistLinkHandlerFactory.java @@ -25,7 +25,8 @@ public final class PeertubePlaylistLinkHandlerFactory extends ListLinkHandlerFac @Override public String getUrl(final String id, final List contentFilters, - final String sortFilter) { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { return getUrl(id, contentFilters, sortFilter, ServiceList.PeerTube.getBaseUrl()); } @@ -33,12 +34,13 @@ public final class PeertubePlaylistLinkHandlerFactory extends ListLinkHandlerFac public String getUrl(final String id, final List contentFilters, final String sortFilter, - final String baseUrl) { + final String baseUrl) + throws ParsingException, UnsupportedOperationException { return baseUrl + "/api/v1/video-playlists/" + id; } @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { try { return Parser.matchGroup(ID_PATTERN, url, 2); } catch (final ParsingException ignored) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeSearchQueryHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeSearchQueryHandlerFactory.java index db9dfe38c..6e1354665 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeSearchQueryHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeSearchQueryHandlerFactory.java @@ -10,6 +10,9 @@ import java.util.List; public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory { + private static final PeertubeSearchQueryHandlerFactory INSTANCE = + new PeertubeSearchQueryHandlerFactory(); + public static final String VIDEOS = "videos"; public static final String SEPIA_VIDEOS = "sepia_videos"; // sepia is the global index public static final String PLAYLISTS = "playlists"; @@ -23,13 +26,14 @@ public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerF } public static PeertubeSearchQueryHandlerFactory getInstance() { - return new PeertubeSearchQueryHandlerFactory(); + return INSTANCE; } @Override public String getUrl(final String searchString, final List contentFilters, - final String sortFilter) throws ParsingException { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { final String baseUrl; if (!contentFilters.isEmpty() && contentFilters.get(0).startsWith("sepia_")) { baseUrl = SEPIA_BASE_URL; @@ -43,7 +47,8 @@ public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerF public String getUrl(final String searchString, final List contentFilters, final String sortFilter, - final String baseUrl) throws ParsingException { + final String baseUrl) + throws ParsingException, UnsupportedOperationException { try { final String endpoint; if (contentFilters.isEmpty() diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java index aee042a03..6bc2ffa12 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java @@ -27,7 +27,7 @@ public final class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory { } @Override - public String getUrl(final String id) { + public String getUrl(final String id) throws ParsingException, UnsupportedOperationException { return getUrl(id, ServiceList.PeerTube.getBaseUrl()); } @@ -37,7 +37,7 @@ public final class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory { } @Override - public String getId(final String url) throws ParsingException, IllegalArgumentException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { return Parser.matchGroup(ID_PATTERN, url, 4); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeTrendingLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeTrendingLinkHandlerFactory.java index bded13ff2..cb58af4ed 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeTrendingLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeTrendingLinkHandlerFactory.java @@ -23,6 +23,9 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac KIOSK_RECENT, "%s/api/v1/videos?sort=-publishedAt", KIOSK_LOCAL, "%s/api/v1/videos?sort=-publishedAt&filter=local"); + private PeertubeTrendingLinkHandlerFactory() { + } + public static PeertubeTrendingLinkHandlerFactory getInstance() { return INSTANCE; } @@ -30,7 +33,8 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac @Override public String getUrl(final String id, final List contentFilters, - final String sortFilter) { + final String sortFilter) + throws ParsingException, UnsupportedOperationException { return getUrl(id, contentFilters, sortFilter, ServiceList.PeerTube.getBaseUrl()); } @@ -38,12 +42,13 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac public String getUrl(final String id, final List contentFilters, final String sortFilter, - final String baseUrl) { + final String baseUrl) + throws ParsingException, UnsupportedOperationException { return String.format(KIOSK_MAP.get(id), baseUrl); } @Override - public String getId(final String url) throws ParsingException { + public String getId(final String url) throws ParsingException, UnsupportedOperationException { final String cleanUrl = url.replace(ServiceList.PeerTube.getBaseUrl(), "%s"); if (cleanUrl.contains("/videos/trending")) { return KIOSK_TRENDING;