[MediaCCC] Allow obtaining channel tab extractor from scratch
i.e. without needing to pass through the conference/channel extractor This was needed because clients (like NewPipe) might rely on link handlers to hold as little data as possible, since they might be kept around for long or passed around in system transactions, so this commit allows obtaining a standalone link handler that does not hold a JsonObject within itself.
This commit is contained in:
parent
3402cdb666
commit
cc9ade962e
|
@ -19,6 +19,7 @@ import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
|
|||
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
|
||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCChannelTabExtractor;
|
||||
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCConferenceExtractor;
|
||||
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCConferenceKiosk;
|
||||
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCLiveStreamExtractor;
|
||||
|
@ -57,7 +58,9 @@ public class MediaCCCService extends StreamingService {
|
|||
|
||||
@Override
|
||||
public ListLinkHandlerFactory getChannelTabLHFactory() {
|
||||
return null;
|
||||
// there is just one channel tab in MediaCCC, the one containing conferences, so there is
|
||||
// no need for a specific channel tab link handler, but we can just use the channel one
|
||||
return MediaCCCConferenceLinkHandlerFactory.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,17 +89,13 @@ public class MediaCCCService extends StreamingService {
|
|||
@Override
|
||||
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) {
|
||||
if (linkHandler instanceof ReadyChannelTabListLinkHandler) {
|
||||
// conference data has already been fetched, let the ReadyChannelTabListLinkHandler
|
||||
// create a MediaCCCChannelTabExtractor with that data
|
||||
return ((ReadyChannelTabListLinkHandler) linkHandler).getChannelTabExtractor(this);
|
||||
} else {
|
||||
// conference data has not been fetched yet, so pass null instead
|
||||
return new MediaCCCChannelTabExtractor(this, linkHandler, null);
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
|
||||
|
||||
import com.grack.nanojson.JsonObject;
|
||||
|
||||
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.tabs.ChannelTabExtractor;
|
||||
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCStreamInfoItemExtractor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* MediaCCC does not really have channel tabs, but rather a list of videos for each conference,
|
||||
* so this class just acts as a videos channel tab extractor.
|
||||
*/
|
||||
public class MediaCCCChannelTabExtractor extends ChannelTabExtractor {
|
||||
@Nullable
|
||||
private JsonObject conferenceData;
|
||||
|
||||
/**
|
||||
* @param conferenceData will be not-null if conference data has already been fetched by
|
||||
* {@link MediaCCCConferenceExtractor}. Otherwise, if this parameter is
|
||||
* {@code null}, conference data will be fetched anew.
|
||||
*/
|
||||
public MediaCCCChannelTabExtractor(final StreamingService service,
|
||||
final ListLinkHandler linkHandler,
|
||||
@Nullable final JsonObject conferenceData) {
|
||||
super(service, linkHandler);
|
||||
this.conferenceData = conferenceData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFetchPage(@Nonnull final Downloader downloader)
|
||||
throws ExtractionException, IOException {
|
||||
if (conferenceData == null) {
|
||||
// only fetch conference data if we don't have it already
|
||||
conferenceData = MediaCCCConferenceExtractor.fetchConferenceData(downloader, getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ListExtractor.InfoItemsPage<InfoItem> getInitialPage() {
|
||||
final MultiInfoItemsCollector collector =
|
||||
new MultiInfoItemsCollector(getServiceId());
|
||||
Objects.requireNonNull(conferenceData) // will surely be != null after onFetchPage
|
||||
.getArray("events")
|
||||
.stream()
|
||||
.filter(JsonObject.class::isInstance)
|
||||
.map(JsonObject.class::cast)
|
||||
.forEach(event -> collector.commit(new MediaCCCStreamInfoItemExtractor(event)));
|
||||
return new ListExtractor.InfoItemsPage<>(collector, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListExtractor.InfoItemsPage<InfoItem> getPage(final Page page) {
|
||||
return ListExtractor.InfoItemsPage.emptyPage();
|
||||
}
|
||||
}
|
|
@ -1,24 +1,20 @@
|
|||
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
|
||||
|
||||
import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.getImageListFromLogoImageUrl;
|
||||
|
||||
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.Image;
|
||||
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 java.io.IOException;
|
||||
|
@ -27,8 +23,6 @@ import java.util.List;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.getImageListFromLogoImageUrl;
|
||||
|
||||
public class MediaCCCConferenceExtractor extends ChannelExtractor {
|
||||
private JsonObject conferenceData;
|
||||
|
||||
|
@ -37,6 +31,19 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor {
|
|||
super(service, linkHandler);
|
||||
}
|
||||
|
||||
static JsonObject fetchConferenceData(@Nonnull final Downloader downloader,
|
||||
@Nonnull final String conferenceId)
|
||||
throws IOException, ExtractionException {
|
||||
final String conferenceUrl
|
||||
= MediaCCCConferenceLinkHandlerFactory.CONFERENCE_API_ENDPOINT + conferenceId;
|
||||
try {
|
||||
return JsonParser.object().from(downloader.get(conferenceUrl).responseBody());
|
||||
} catch (final JsonParserException jpe) {
|
||||
throw new ExtractionException("Could not parse json returned by URL: " + conferenceUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Image> getAvatars() {
|
||||
|
@ -88,20 +95,15 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor {
|
|||
@Nonnull
|
||||
@Override
|
||||
public List<ListLinkHandler> getTabs() throws ParsingException {
|
||||
return List.of(new ReadyChannelTabListLinkHandler(getUrl(), getId(),
|
||||
ChannelTabs.VIDEOS, new VideosTabExtractorBuilder(conferenceData)));
|
||||
return List.of(new ReadyChannelTabListLinkHandler(getUrl(), getId(), ChannelTabs.VIDEOS,
|
||||
(service, linkHandler) ->
|
||||
new MediaCCCChannelTabExtractor(service, linkHandler, conferenceData)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFetchPage(@Nonnull final Downloader downloader)
|
||||
throws IOException, ExtractionException {
|
||||
final String conferenceUrl
|
||||
= MediaCCCConferenceLinkHandlerFactory.CONFERENCE_API_ENDPOINT + getId();
|
||||
try {
|
||||
conferenceData = JsonParser.object().from(downloader.get(conferenceUrl).responseBody());
|
||||
} catch (final JsonParserException jpe) {
|
||||
throw new ExtractionException("Could not parse json returned by URL: " + conferenceUrl);
|
||||
}
|
||||
conferenceData = fetchConferenceData(downloader, getId());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
@ -109,55 +111,4 @@ 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<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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package org.schabi.newpipe.extractor.services.media_ccc.linkHandler;
|
||||
|
||||
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
|
||||
import org.schabi.newpipe.extractor.utils.Parser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Since MediaCCC does not really have channel tabs (i.e. it only has one single "tab" with videos),
|
||||
* this link handler acts both as the channel link handler and the channel tab link handler. That's
|
||||
* why {@link #getAvailableContentFilter()} has been overridden.
|
||||
*/
|
||||
public final class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory {
|
||||
|
||||
private static final MediaCCCConferenceLinkHandlerFactory INSTANCE
|
||||
|
@ -46,4 +52,15 @@ public final class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerF
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MediaCCCConferenceLinkHandlerFactory
|
||||
* @return MediaCCC's only channel "tab", i.e. {@link ChannelTabs#VIDEOS}
|
||||
*/
|
||||
@Override
|
||||
public String[] getAvailableContentFilter() {
|
||||
return new String[]{
|
||||
ChannelTabs.VIDEOS,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue