[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 <t.testboy@gmail.com>
Co-authored-by: Stypox <stypox@pm.me>
This commit is contained in:
AudricV 2023-06-29 19:08:34 +02:00 committed by Stypox
parent 652c2c8408
commit 1e8474b22d
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
27 changed files with 440 additions and 221 deletions

View File

@ -6,6 +6,7 @@ import static java.util.Arrays.asList;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor; 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.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskList; 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.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; 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.SearchQueryHandler;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory; import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor; 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.extractors.MediaCCCStreamExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory; 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.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.MediaCCCSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory; import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamExtractor; import org.schabi.newpipe.extractor.stream.StreamExtractor;
@ -47,12 +47,17 @@ public class MediaCCCService extends StreamingService {
@Override @Override
public LinkHandlerFactory getStreamLHFactory() { public LinkHandlerFactory getStreamLHFactory() {
return new MediaCCCStreamLinkHandlerFactory(); return MediaCCCStreamLinkHandlerFactory.getInstance();
} }
@Override @Override
public ListLinkHandlerFactory getChannelLHFactory() { public ListLinkHandlerFactory getChannelLHFactory() {
return new MediaCCCConferenceLinkHandlerFactory(); return MediaCCCConferenceLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return null;
} }
@Override @Override
@ -62,7 +67,7 @@ public class MediaCCCService extends StreamingService {
@Override @Override
public SearchQueryHandlerFactory getSearchQHFactory() { public SearchQueryHandlerFactory getSearchQHFactory() {
return new MediaCCCSearchQueryHandlerFactory(); return MediaCCCSearchQueryHandlerFactory.getInstance();
} }
@Override @Override
@ -78,6 +83,22 @@ public class MediaCCCService extends StreamingService {
return new MediaCCCConferenceExtractor(this, linkHandler); 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 @Override
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) { public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
return null; return null;
@ -91,36 +112,37 @@ public class MediaCCCService extends StreamingService {
@Override @Override
public KioskList getKioskList() throws ExtractionException { public KioskList getKioskList() throws ExtractionException {
final KioskList list = new KioskList(this); final KioskList list = new KioskList(this);
final ListLinkHandlerFactory h = MediaCCCConferencesListLinkHandlerFactory.getInstance();
// add kiosks here e.g.: // add kiosks here e.g.:
try { try {
list.addKioskEntry( list.addKioskEntry(
(streamingService, url, kioskId) -> new MediaCCCConferenceKiosk( (streamingService, url, kioskId) -> new MediaCCCConferenceKiosk(
MediaCCCService.this, MediaCCCService.this,
new MediaCCCConferencesListLinkHandlerFactory().fromUrl(url), h.fromUrl(url),
kioskId kioskId
), ),
new MediaCCCConferencesListLinkHandlerFactory(), h,
MediaCCCConferenceKiosk.KIOSK_ID MediaCCCConferenceKiosk.KIOSK_ID
); );
list.addKioskEntry( list.addKioskEntry(
(streamingService, url, kioskId) -> new MediaCCCRecentKiosk( (streamingService, url, kioskId) -> new MediaCCCRecentKiosk(
MediaCCCService.this, MediaCCCService.this,
new MediaCCCRecentListLinkHandlerFactory().fromUrl(url), h.fromUrl(url),
kioskId kioskId
), ),
new MediaCCCRecentListLinkHandlerFactory(), h,
MediaCCCRecentKiosk.KIOSK_ID MediaCCCRecentKiosk.KIOSK_ID
); );
list.addKioskEntry( list.addKioskEntry(
(streamingService, url, kioskId) -> new MediaCCCLiveStreamKiosk( (streamingService, url, kioskId) -> new MediaCCCLiveStreamKiosk(
MediaCCCService.this, MediaCCCService.this,
new MediaCCCLiveListLinkHandlerFactory().fromUrl(url), h.fromUrl(url),
kioskId kioskId
), ),
new MediaCCCLiveListLinkHandlerFactory(), h,
MediaCCCLiveStreamKiosk.KIOSK_ID MediaCCCLiveStreamKiosk.KIOSK_ID
); );

View File

@ -1,23 +1,29 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors; package org.schabi.newpipe.extractor.services.media_ccc.extractors;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException; 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.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor; 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.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; 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.extractors.infoItems.MediaCCCStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory; 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 javax.annotation.Nonnull;
import java.io.IOException;
public class MediaCCCConferenceExtractor extends ChannelExtractor { public class MediaCCCConferenceExtractor extends ChannelExtractor {
private JsonObject conferenceData; private JsonObject conferenceData;
@ -74,18 +80,9 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor {
@Nonnull @Nonnull
@Override @Override
public InfoItemsPage<StreamInfoItem> getInitialPage() { public List<ListLinkHandler> getTabs() throws ParsingException {
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); return List.of(new ReadyChannelTabListLinkHandler(getUrl(), getId(),
final JsonArray events = conferenceData.getArray("events"); ChannelTabs.VIDEOS, new VideosTabExtractorBuilder(conferenceData)));
for (int i = 0; i < events.size(); i++) {
collector.commit(new MediaCCCStreamInfoItemExtractor(events.getObject(i)));
}
return new InfoItemsPage<>(collector, null);
}
@Override
public InfoItemsPage<StreamInfoItem> getPage(final Page page) {
return InfoItemsPage.emptyPage();
} }
@Override @Override
@ -105,4 +102,55 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor {
public String getName() throws ParsingException { public String getName() throws ParsingException {
return conferenceData.getString("title"); 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<InfoItem> 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<InfoItem> getPage(final Page page) {
return InfoItemsPage.emptyPage();
}
}
} }

View File

@ -65,7 +65,7 @@ public class MediaCCCRecentKioskExtractor implements StreamInfoItemExtractor {
@Override @Override
public String getUploaderUrl() throws ParsingException { public String getUploaderUrl() throws ParsingException {
return new MediaCCCConferenceLinkHandlerFactory() return MediaCCCConferenceLinkHandlerFactory.getInstance()
.fromUrl(event.getString("conference_url")) // API URL .fromUrl(event.getString("conference_url")) // API URL
.getUrl(); // web URL .getUrl(); // web URL
} }

View File

@ -38,7 +38,8 @@ public class MediaCCCSearchExtractor extends SearchExtractor {
super(service, linkHandler); super(service, linkHandler);
try { try {
conferenceKiosk = new MediaCCCConferenceKiosk(service, conferenceKiosk = new MediaCCCConferenceKiosk(service,
new MediaCCCConferencesListLinkHandlerFactory().fromId("conferences"), MediaCCCConferencesListLinkHandlerFactory.getInstance()
.fromId("conferences"),
"conferences"); "conferences");
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -6,7 +6,11 @@ import org.schabi.newpipe.extractor.utils.Parser;
import java.util.List; 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 public static final String CONFERENCE_API_ENDPOINT
= "https://api.media.ccc.de/public/conferences/"; = "https://api.media.ccc.de/public/conferences/";
public static final String CONFERENCE_PATH = "https://media.ccc.de/c/"; 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/)" = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/conferences/)"
+ "|(?:media\\.ccc\\.de/[bc]/))([^/?&#]*)"; + "|(?:media\\.ccc\\.de/[bc]/))([^/?&#]*)";
private MediaCCCConferenceLinkHandlerFactory() {
}
public static MediaCCCConferenceLinkHandlerFactory getInstance() {
return INSTANCE;
}
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilter, final List<String> contentFilter,
final String sortFilter) throws ParsingException { final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return CONFERENCE_PATH + id; return CONFERENCE_PATH + id;
} }
@Override @Override
public String getId(final String url) throws ParsingException { public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return Parser.matchGroup1(ID_PATTERN, url); return Parser.matchGroup1(ID_PATTERN, url);
} }

View File

@ -5,15 +5,28 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List; 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 @Override
public String getId(final String url) throws ParsingException { public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return "conferences"; return "conferences";
} }
@Override @Override
public String getUrl(final String id, final List<String> contentFilter, public String getUrl(final String id,
final String sortFilter) throws ParsingException { final List<String> contentFilter,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://media.ccc.de/public/conferences"; return "https://media.ccc.de/public/conferences";
} }

View File

@ -6,11 +6,22 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; 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 static final String STREAM_PATTERN = "^(?:https?://)?media\\.ccc\\.de/live$";
private MediaCCCLiveListLinkHandlerFactory() {
}
public static MediaCCCLiveListLinkHandlerFactory getInstance() {
return INSTANCE;
}
@Override @Override
public String getId(final String url) throws ParsingException { public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return "live"; return "live";
} }
@ -22,7 +33,8 @@ public class MediaCCCLiveListLinkHandlerFactory extends ListLinkHandlerFactory {
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilter, final List<String> 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} // FIXME: wrong URL; should be https://streaming.media.ccc.de/{conference_slug}/{room_slug}
return "https://media.ccc.de/live"; return "https://media.ccc.de/live";
} }

View File

@ -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;
}
}
}

View File

@ -1,15 +1,27 @@
package org.schabi.newpipe.extractor.services.media_ccc.linkHandler; package org.schabi.newpipe.extractor.services.media_ccc.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; 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 static final String PATTERN = "^(https?://)?media\\.ccc\\.de/recent/?$";
private MediaCCCRecentListLinkHandlerFactory() {
}
public static MediaCCCRecentListLinkHandlerFactory getInstance() {
return INSTANCE;
}
@Override @Override
public String getId(final String url) { public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return "recent"; return "recent";
} }
@ -21,7 +33,8 @@ public class MediaCCCRecentListLinkHandlerFactory extends ListLinkHandlerFactory
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilter, final List<String> contentFilter,
final String sortFilter) { final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://media.ccc.de/recent"; return "https://media.ccc.de/recent";
} }
} }

View File

@ -7,11 +7,22 @@ import org.schabi.newpipe.extractor.utils.Utils;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.List; 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 ALL = "all";
public static final String CONFERENCES = "conferences"; public static final String CONFERENCES = "conferences";
public static final String EVENTS = "events"; public static final String EVENTS = "events";
private MediaCCCSearchQueryHandlerFactory() {
}
public static MediaCCCSearchQueryHandlerFactory getInstance() {
return INSTANCE;
}
@Override @Override
public String[] getAvailableContentFilter() { public String[] getAvailableContentFilter() {
return new String[]{ return new String[]{
@ -27,8 +38,10 @@ public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory
} }
@Override @Override
public String getUrl(final String query, final List<String> contentFilter, public String getUrl(final String query,
final String sortFilter) throws ParsingException { final List<String> contentFilter,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
try { try {
return "https://media.ccc.de/public/events/search?q=" + Utils.encodeUrlUtf8(query); return "https://media.ccc.de/public/events/search?q=" + Utils.encodeUrlUtf8(query);
} catch (final UnsupportedEncodingException e) { } catch (final UnsupportedEncodingException e) {

View File

@ -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.services.media_ccc.extractors.MediaCCCParsingHelper;
import org.schabi.newpipe.extractor.utils.Parser; 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/"; 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 VIDEO_PATH = "https://media.ccc.de/v/";
private static final String RECORDING_ID_PATTERN private static final String RECORDING_ID_PATTERN
@ -15,8 +19,15 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory {
private static final String LIVE_STREAM_ID_PATTERN private static final String LIVE_STREAM_ID_PATTERN
= "streaming\\.media\\.ccc\\.de\\/(\\w+\\/\\w+)"; = "streaming\\.media\\.ccc\\.de\\/(\\w+\\/\\w+)";
private MediaCCCStreamLinkHandlerFactory() {
}
public static MediaCCCStreamLinkHandlerFactory getInstance() {
return INSTANCE;
}
@Override @Override
public String getId(final String url) throws ParsingException { public String getId(final String url) throws ParsingException, UnsupportedOperationException {
String streamId = null; String streamId = null;
try { try {
streamId = Parser.matchGroup1(LIVE_STREAM_ID_PATTERN, url); streamId = Parser.matchGroup1(LIVE_STREAM_ID_PATTERN, url);
@ -30,7 +41,7 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory {
} }
@Override @Override
public String getUrl(final String id) throws ParsingException { public String getUrl(final String id) throws ParsingException, UnsupportedOperationException {
if (MediaCCCParsingHelper.isLiveStreamId(id)) { if (MediaCCCParsingHelper.isLiveStreamId(id)) {
return LIVE_STREAM_PATH + id; return LIVE_STREAM_PATH + id;
} }

View File

@ -72,24 +72,29 @@ public final class PeertubeParsingHelper {
} }
} }
public static void collectStreamsFrom(final InfoItemsCollector collector, public static void collectItemsFrom(final InfoItemsCollector collector,
final JsonObject json, final JsonObject json,
final String baseUrl) throws ParsingException { final String baseUrl) throws ParsingException {
collectStreamsFrom(collector, json, baseUrl, false); collectItemsFrom(collector, json, baseUrl, false);
} }
/** /**
* Collect stream from json with collector * Collect items from the given JSON object with the given collector.
*
* <p>
* Supported info item types are streams with their Sepia variant, channels and playlists.
* </p>
* *
* @param collector the collector used to collect information * @param collector the collector used to collect information
* @param json the file to retrieve data from * @param json the JSOn response to retrieve data from
* @param baseUrl the base Url of the instance * @param baseUrl the base URL of the instance
* @param sepia if we should use PeertubeSepiaStreamInfoItemExtractor * @param sepia if we should use {@code PeertubeSepiaStreamInfoItemExtractor} to extract
* streams or {@code PeertubeStreamInfoItemExtractor} otherwise
*/ */
public static void collectStreamsFrom(final InfoItemsCollector collector, public static void collectItemsFrom(final InfoItemsCollector collector,
final JsonObject json, final JsonObject json,
final String baseUrl, final String baseUrl,
final boolean sepia) throws ParsingException { final boolean sepia) throws ParsingException {
final JsonArray contents; final JsonArray contents;
try { try {
contents = (JsonArray) JsonUtils.getValue(json, "data"); contents = (JsonArray) JsonUtils.getValue(json, "data");

View File

@ -6,6 +6,7 @@ import static java.util.Arrays.asList;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor; 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.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskList; 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.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeAccountExtractor; 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.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.PeertubeCommentsExtractor;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubePlaylistExtractor; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubePlaylistExtractor;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeSearchExtractor; 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.PeertubeSuggestionExtractor;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeTrendingExtractor; 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.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.PeertubeCommentsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubePlaylistLinkHandlerFactory; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubePlaylistLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
@ -60,6 +63,11 @@ public class PeertubeService extends StreamingService {
return PeertubeChannelLinkHandlerFactory.getInstance(); return PeertubeChannelLinkHandlerFactory.getInstance();
} }
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return PeertubeChannelTabLinkHandlerFactory.getInstance();
}
@Override @Override
public ListLinkHandlerFactory getPlaylistLHFactory() { public ListLinkHandlerFactory getPlaylistLHFactory() {
return PeertubePlaylistLinkHandlerFactory.getInstance(); 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 @Override
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler)
throws ExtractionException { throws ExtractionException {
@ -136,17 +150,20 @@ public class PeertubeService extends StreamingService {
@Override @Override
public KioskList getKioskList() throws ExtractionException { public KioskList getKioskList() throws ExtractionException {
final PeertubeTrendingLinkHandlerFactory h =
PeertubeTrendingLinkHandlerFactory.getInstance();
final KioskList.KioskExtractorFactory kioskFactory = (streamingService, url, id) -> final KioskList.KioskExtractorFactory kioskFactory = (streamingService, url, id) ->
new PeertubeTrendingExtractor( new PeertubeTrendingExtractor(
PeertubeService.this, PeertubeService.this,
new PeertubeTrendingLinkHandlerFactory().fromId(id), h.fromId(id),
id id
); );
final KioskList list = new KioskList(this); final KioskList list = new KioskList(this);
// add kiosks here e.g.: // add kiosks here e.g.:
final PeertubeTrendingLinkHandlerFactory h = new PeertubeTrendingLinkHandlerFactory();
try { try {
list.addKioskEntry(kioskFactory, h, PeertubeTrendingLinkHandlerFactory.KIOSK_TRENDING); list.addKioskEntry(kioskFactory, h, PeertubeTrendingLinkHandlerFactory.KIOSK_TRENDING);
list.addKioskEntry(kioskFactory, h, list.addKioskEntry(kioskFactory, h,
@ -160,6 +177,4 @@ public class PeertubeService extends StreamingService {
return list; return list;
} }
} }

View File

@ -4,31 +4,23 @@ import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException; import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor; 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.Downloader;
import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; 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.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.utils.JsonUtils; import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.List;
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;
public class PeertubeAccountExtractor extends ChannelExtractor { public class PeertubeAccountExtractor extends ChannelExtractor {
private JsonObject json; private JsonObject json;
@ -119,54 +111,19 @@ public class PeertubeAccountExtractor extends ChannelExtractor {
@Nonnull @Nonnull
@Override @Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException { public List<ListLinkHandler> getTabs() throws ParsingException {
return getPage(new Page(baseUrl + "/api/v1/" + getId() + "/videos?" + START_KEY + "=0&" return List.of(
+ COUNT_KEY + "=" + ITEMS_PER_PAGE)); PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(),
} List.of(ChannelTabs.VIDEOS), "", getBaseUrl()),
PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(),
@Override List.of(ChannelTabs.CHANNELS), "", getBaseUrl()));
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");
}
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");
}
} }
@Override @Override
public void onFetchPage(@Nonnull final Downloader downloader) public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException { throws IOException, ExtractionException {
String accountUrl = baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT; final Response response = downloader.get(baseUrl
if (getId().contains(ACCOUNTS)) { + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + getId());
accountUrl += getId();
} else {
accountUrl += ACCOUNTS + getId();
}
final Response response = downloader.get(accountUrl);
if (response != null) { if (response != null) {
setInitialData(response.responseBody()); setInitialData(response.responseBody());
} else { } else {

View File

@ -3,30 +3,22 @@ package org.schabi.newpipe.extractor.services.peertube.extractors;
import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException; import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor; 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.Downloader;
import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; 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.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.utils.JsonUtils; import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.List;
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;
public class PeertubeChannelExtractor extends ChannelExtractor { public class PeertubeChannelExtractor extends ChannelExtractor {
private JsonObject json; private JsonObject json;
@ -98,41 +90,12 @@ public class PeertubeChannelExtractor extends ChannelExtractor {
@Nonnull @Nonnull
@Override @Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException { public List<ListLinkHandler> getTabs() throws ParsingException {
return getPage(new Page(baseUrl + "/api/v1/" + getId() + "/videos?" + START_KEY + "=0&" return List.of(
+ COUNT_KEY + "=" + ITEMS_PER_PAGE)); PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(),
} List.of(ChannelTabs.VIDEOS), "", getBaseUrl()),
PeertubeChannelTabLinkHandlerFactory.getInstance().fromQuery(getId(),
@Override List.of(ChannelTabs.PLAYLISTS), "", getBaseUrl()));
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");
}
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");
}
} }
@Override @Override

View File

@ -1,7 +1,7 @@
package org.schabi.newpipe.extractor.services.peertube.extractors; package org.schabi.newpipe.extractor.services.peertube.extractors;
import com.grack.nanojson.JsonObject; 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.channel.ChannelInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
@ -52,7 +52,7 @@ public class PeertubeChannelInfoItemExtractor implements ChannelInfoItemExtracto
@Override @Override
public long getStreamCount() throws ParsingException { public long getStreamCount() throws ParsingException {
return ChannelExtractor.ITEM_COUNT_UNKNOWN; return ListExtractor.ITEM_COUNT_UNKNOWN;
} }
@Override @Override

View File

@ -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<InfoItem> 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<InfoItem> 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")));
}
}

View File

@ -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.COUNT_KEY;
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.ITEMS_PER_PAGE; 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.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; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
public class PeertubePlaylistExtractor extends PlaylistExtractor { public class PeertubePlaylistExtractor extends PlaylistExtractor {
@ -125,7 +125,7 @@ public class PeertubePlaylistExtractor extends PlaylistExtractor {
final long total = json.getLong("total"); final long total = json.getLong("total");
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
collectStreamsFrom(collector, json, getBaseUrl()); collectItemsFrom(collector, json, getBaseUrl());
return new InfoItemsPage<>(collector, return new InfoItemsPage<>(collector,
PeertubeParsingHelper.getNextPage(page.getUrl(), total)); PeertubeParsingHelper.getNextPage(page.getUrl(), total));

View File

@ -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.COUNT_KEY;
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.ITEMS_PER_PAGE; 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.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; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
public class PeertubeSearchExtractor extends SearchExtractor { public class PeertubeSearchExtractor extends SearchExtractor {
@ -93,7 +93,7 @@ public class PeertubeSearchExtractor extends SearchExtractor {
final long total = json.getLong("total"); final long total = json.getLong("total");
final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId()); final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId());
collectStreamsFrom(collector, json, getBaseUrl(), sepia); collectItemsFrom(collector, json, getBaseUrl(), sepia);
return new InfoItemsPage<>(collector, return new InfoItemsPage<>(collector,
PeertubeParsingHelper.getNextPage(page.getUrl(), total)); PeertubeParsingHelper.getNextPage(page.getUrl(), total));

View File

@ -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.COUNT_KEY;
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.ITEMS_PER_PAGE; 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.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; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
public class PeertubeTrendingExtractor extends KioskExtractor<StreamInfoItem> { public class PeertubeTrendingExtractor extends KioskExtractor<StreamInfoItem> {
@ -69,7 +69,7 @@ public class PeertubeTrendingExtractor extends KioskExtractor<StreamInfoItem> {
final long total = json.getLong("total"); final long total = json.getLong("total");
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
collectStreamsFrom(collector, json, getBaseUrl()); collectItemsFrom(collector, json, getBaseUrl());
return new InfoItemsPage<>(collector, return new InfoItemsPage<>(collector,
PeertubeParsingHelper.getNextPage(page.getUrl(), total)); PeertubeParsingHelper.getNextPage(page.getUrl(), total));

View File

@ -22,14 +22,15 @@ public final class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFact
} }
@Override @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)); return fixId(Parser.matchGroup(ID_PATTERN, url, 0));
} }
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilters, final List<String> contentFilters,
final String searchFilter) throws ParsingException { final String searchFilter)
throws ParsingException, UnsupportedOperationException {
return getUrl(id, contentFilters, searchFilter, ServiceList.PeerTube.getBaseUrl()); return getUrl(id, contentFilters, searchFilter, ServiceList.PeerTube.getBaseUrl());
} }
@ -38,7 +39,7 @@ public final class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFact
final List<String> contentFilter, final List<String> contentFilter,
final String sortFilter, final String sortFilter,
final String baseUrl) final String baseUrl)
throws ParsingException { throws ParsingException, UnsupportedOperationException {
if (id.matches(ID_PATTERN)) { if (id.matches(ID_PATTERN)) {
return baseUrl + "/" + fixId(id); return baseUrl + "/" + fixId(id);
} else { } else {

View File

@ -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<String> 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<String> 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,
};
}
}

View File

@ -21,7 +21,7 @@ public final class PeertubeCommentsLinkHandlerFactory extends ListLinkHandlerFac
} }
@Override @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 return PeertubeStreamLinkHandlerFactory.getInstance().getId(url); // the same id is needed
} }
@ -33,7 +33,8 @@ public final class PeertubeCommentsLinkHandlerFactory extends ListLinkHandlerFac
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilter, final List<String> contentFilter,
final String sortFilter) throws ParsingException { final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return getUrl(id, contentFilter, sortFilter, ServiceList.PeerTube.getBaseUrl()); return getUrl(id, contentFilter, sortFilter, ServiceList.PeerTube.getBaseUrl());
} }
@ -41,7 +42,8 @@ public final class PeertubeCommentsLinkHandlerFactory extends ListLinkHandlerFac
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilter, final List<String> contentFilter,
final String sortFilter, final String sortFilter,
final String baseUrl) throws ParsingException { final String baseUrl)
throws ParsingException, UnsupportedOperationException {
return baseUrl + String.format(COMMENTS_ENDPOINT, id); return baseUrl + String.format(COMMENTS_ENDPOINT, id);
} }

View File

@ -25,7 +25,8 @@ public final class PeertubePlaylistLinkHandlerFactory extends ListLinkHandlerFac
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilters, final List<String> contentFilters,
final String sortFilter) { final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return getUrl(id, contentFilters, sortFilter, ServiceList.PeerTube.getBaseUrl()); return getUrl(id, contentFilters, sortFilter, ServiceList.PeerTube.getBaseUrl());
} }
@ -33,12 +34,13 @@ public final class PeertubePlaylistLinkHandlerFactory extends ListLinkHandlerFac
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilters, final List<String> contentFilters,
final String sortFilter, final String sortFilter,
final String baseUrl) { final String baseUrl)
throws ParsingException, UnsupportedOperationException {
return baseUrl + "/api/v1/video-playlists/" + id; return baseUrl + "/api/v1/video-playlists/" + id;
} }
@Override @Override
public String getId(final String url) throws ParsingException { public String getId(final String url) throws ParsingException, UnsupportedOperationException {
try { try {
return Parser.matchGroup(ID_PATTERN, url, 2); return Parser.matchGroup(ID_PATTERN, url, 2);
} catch (final ParsingException ignored) { } catch (final ParsingException ignored) {

View File

@ -10,6 +10,9 @@ import java.util.List;
public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory { public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
private static final PeertubeSearchQueryHandlerFactory INSTANCE =
new PeertubeSearchQueryHandlerFactory();
public static final String VIDEOS = "videos"; public static final String VIDEOS = "videos";
public static final String SEPIA_VIDEOS = "sepia_videos"; // sepia is the global index public static final String SEPIA_VIDEOS = "sepia_videos"; // sepia is the global index
public static final String PLAYLISTS = "playlists"; public static final String PLAYLISTS = "playlists";
@ -23,13 +26,14 @@ public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerF
} }
public static PeertubeSearchQueryHandlerFactory getInstance() { public static PeertubeSearchQueryHandlerFactory getInstance() {
return new PeertubeSearchQueryHandlerFactory(); return INSTANCE;
} }
@Override @Override
public String getUrl(final String searchString, public String getUrl(final String searchString,
final List<String> contentFilters, final List<String> contentFilters,
final String sortFilter) throws ParsingException { final String sortFilter)
throws ParsingException, UnsupportedOperationException {
final String baseUrl; final String baseUrl;
if (!contentFilters.isEmpty() && contentFilters.get(0).startsWith("sepia_")) { if (!contentFilters.isEmpty() && contentFilters.get(0).startsWith("sepia_")) {
baseUrl = SEPIA_BASE_URL; baseUrl = SEPIA_BASE_URL;
@ -43,7 +47,8 @@ public final class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerF
public String getUrl(final String searchString, public String getUrl(final String searchString,
final List<String> contentFilters, final List<String> contentFilters,
final String sortFilter, final String sortFilter,
final String baseUrl) throws ParsingException { final String baseUrl)
throws ParsingException, UnsupportedOperationException {
try { try {
final String endpoint; final String endpoint;
if (contentFilters.isEmpty() if (contentFilters.isEmpty()

View File

@ -27,7 +27,7 @@ public final class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory {
} }
@Override @Override
public String getUrl(final String id) { public String getUrl(final String id) throws ParsingException, UnsupportedOperationException {
return getUrl(id, ServiceList.PeerTube.getBaseUrl()); return getUrl(id, ServiceList.PeerTube.getBaseUrl());
} }
@ -37,7 +37,7 @@ public final class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory {
} }
@Override @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); return Parser.matchGroup(ID_PATTERN, url, 4);
} }

View File

@ -23,6 +23,9 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac
KIOSK_RECENT, "%s/api/v1/videos?sort=-publishedAt", KIOSK_RECENT, "%s/api/v1/videos?sort=-publishedAt",
KIOSK_LOCAL, "%s/api/v1/videos?sort=-publishedAt&filter=local"); KIOSK_LOCAL, "%s/api/v1/videos?sort=-publishedAt&filter=local");
private PeertubeTrendingLinkHandlerFactory() {
}
public static PeertubeTrendingLinkHandlerFactory getInstance() { public static PeertubeTrendingLinkHandlerFactory getInstance() {
return INSTANCE; return INSTANCE;
} }
@ -30,7 +33,8 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilters, final List<String> contentFilters,
final String sortFilter) { final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return getUrl(id, contentFilters, sortFilter, ServiceList.PeerTube.getBaseUrl()); return getUrl(id, contentFilters, sortFilter, ServiceList.PeerTube.getBaseUrl());
} }
@ -38,12 +42,13 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac
public String getUrl(final String id, public String getUrl(final String id,
final List<String> contentFilters, final List<String> contentFilters,
final String sortFilter, final String sortFilter,
final String baseUrl) { final String baseUrl)
throws ParsingException, UnsupportedOperationException {
return String.format(KIOSK_MAP.get(id), baseUrl); return String.format(KIOSK_MAP.get(id), baseUrl);
} }
@Override @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"); final String cleanUrl = url.replace(ServiceList.PeerTube.getBaseUrl(), "%s");
if (cleanUrl.contains("/videos/trending")) { if (cleanUrl.contains("/videos/trending")) {
return KIOSK_TRENDING; return KIOSK_TRENDING;