feat: add tab support for Peertube
This commit is contained in:
parent
57865e2195
commit
aed685e58b
|
@ -16,7 +16,9 @@ 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.peertube.extractors.PeertubeAccountExtractor;
|
||||
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeAccountTabExtractor;
|
||||
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;
|
||||
|
@ -108,7 +110,11 @@ public class PeertubeService extends StreamingService {
|
|||
@Override
|
||||
public ChannelTabExtractor getChannelTabExtractor(final ChannelTabHandler linkHandler)
|
||||
throws ExtractionException {
|
||||
return null;
|
||||
if (linkHandler.getUrl().contains("/video-channels/")) {
|
||||
return new PeertubeChannelTabExtractor(this, linkHandler);
|
||||
} else {
|
||||
return new PeertubeAccountTabExtractor(this, linkHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,10 +26,7 @@ import java.io.IOException;
|
|||
import java.util.Collections;
|
||||
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.services.peertube.PeertubeParsingHelper.*;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
public class PeertubeAccountExtractor extends ChannelExtractor {
|
||||
|
@ -125,8 +122,7 @@ public class PeertubeAccountExtractor extends ChannelExtractor {
|
|||
@Nonnull
|
||||
@Override
|
||||
public List<ChannelTabHandler> getTabs() throws ParsingException {
|
||||
// TODO: implement Peertube account channels tab
|
||||
return Collections.emptyList();
|
||||
return Collections.singletonList(new ChannelTabHandler(getLinkHandler(), ChannelTabHandler.Tab.Channels));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
|
@ -1,4 +1,129 @@
|
|||
package org.schabi.newpipe.extractor.services.peertube.extractors;
|
||||
|
||||
public class PeertubeAccountTabExtractor {
|
||||
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.MultiInfoItemsCollector;
|
||||
import org.schabi.newpipe.extractor.Page;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.channel.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.ChannelTabHandler;
|
||||
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 javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.*;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
public class PeertubeAccountTabExtractor extends ChannelTabExtractor {
|
||||
private JsonObject initialJson;
|
||||
private final String baseUrl;
|
||||
private String initialUrl;
|
||||
private static final String ACCOUNTS = "accounts/";
|
||||
|
||||
public PeertubeAccountTabExtractor(final StreamingService service,
|
||||
final ChannelTabHandler linkHandler) throws ParsingException {
|
||||
super(service, linkHandler);
|
||||
baseUrl = getBaseUrl();
|
||||
|
||||
initialUrl = baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT;
|
||||
if (getId().contains(ACCOUNTS)) {
|
||||
initialUrl += getId();
|
||||
} else {
|
||||
initialUrl += ACCOUNTS + getId();
|
||||
}
|
||||
initialUrl += "/video-channels?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||
if (getLinkHandler().getTab() != ChannelTabHandler.Tab.Channels) {
|
||||
throw new ExtractionException("tab " + getLinkHandler().getTab().name() + " not supported");
|
||||
}
|
||||
|
||||
final Response response = downloader.get(initialUrl);
|
||||
if (response != null) {
|
||||
setInitialData(response.responseBody());
|
||||
} else {
|
||||
throw new ExtractionException("Unable to extract PeerTube account channel data");
|
||||
}
|
||||
}
|
||||
|
||||
private void setInitialData(final String responseBody) throws ExtractionException {
|
||||
try {
|
||||
initialJson = JsonParser.object().from(responseBody);
|
||||
} catch (final JsonParserException e) {
|
||||
throw new ExtractionException("Unable to extract PeerTube account channel data", e);
|
||||
}
|
||||
if (initialJson == null) {
|
||||
throw new ExtractionException("Unable to extract PeerTube account channel data");
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() throws ParsingException {
|
||||
return initialJson.getArray("data").getObject(0)
|
||||
.getObject("ownerAccount").getString("displayName", "");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public InfoItemsPage<InfoItem> getInitialPage() throws IOException, ExtractionException {
|
||||
return parsePage(initialJson, initialUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfoItemsPage<InfoItem> getPage(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);
|
||||
}
|
||||
}
|
||||
|
||||
return parsePage(pageJson, page.getUrl());
|
||||
}
|
||||
|
||||
private InfoItemsPage<InfoItem> parsePage(@Nullable JsonObject json, String pageUrl)
|
||||
throws ExtractionException {
|
||||
if (json == null) {
|
||||
throw new ExtractionException("Unable to get account channel list");
|
||||
}
|
||||
|
||||
PeertubeParsingHelper.validate(json);
|
||||
|
||||
final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId());
|
||||
JsonArray contents = json.getArray("data");
|
||||
if (contents == null) {
|
||||
throw new ParsingException("Unable to extract account channel list");
|
||||
}
|
||||
|
||||
for (final Object c : contents) {
|
||||
if (c instanceof JsonObject) {
|
||||
collector.commit(new PeertubeChannelInfoItemExtractor((JsonObject) c, baseUrl));
|
||||
}
|
||||
}
|
||||
|
||||
return new InfoItemsPage<>(
|
||||
collector, PeertubeParsingHelper.getNextPage(pageUrl, json.getLong("total")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,7 @@ import java.io.IOException;
|
|||
import java.util.Collections;
|
||||
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.services.peertube.PeertubeParsingHelper.*;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
public class PeertubeChannelExtractor extends ChannelExtractor {
|
||||
|
@ -104,8 +101,8 @@ public class PeertubeChannelExtractor extends ChannelExtractor {
|
|||
@Nonnull
|
||||
@Override
|
||||
public List<ChannelTabHandler> getTabs() throws ParsingException {
|
||||
// TODO: implement Peertube channel playlists tab
|
||||
return Collections.emptyList();
|
||||
return Collections.singletonList(
|
||||
new ChannelTabHandler(getLinkHandler(), ChannelTabHandler.Tab.Playlists));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package org.schabi.newpipe.extractor.services.peertube.extractors;
|
||||
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||
|
||||
public class PeertubeChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
||||
|
||||
protected final JsonObject item;
|
||||
private final String baseUrl;
|
||||
|
||||
public PeertubeChannelInfoItemExtractor(final JsonObject item, final String baseUrl) {
|
||||
this.item = item;
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() throws ParsingException {
|
||||
return JsonUtils.getString(item, "url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThumbnailUrl() throws ParsingException {
|
||||
final JsonObject avatar = JsonUtils.getObject(item, "avatar");
|
||||
return baseUrl + JsonUtils.getString(avatar, "path");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() throws ParsingException {
|
||||
return JsonUtils.getString(item, "displayName");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() throws ParsingException {
|
||||
return item.getString("description", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSubscriberCount() throws ParsingException {
|
||||
return JsonUtils.getNumber(item, "followersCount").longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStreamCount() throws ParsingException {
|
||||
return ListExtractor.ITEM_COUNT_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVerified() throws ParsingException {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package org.schabi.newpipe.extractor.services.peertube.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.MultiInfoItemsCollector;
|
||||
import org.schabi.newpipe.extractor.Page;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.channel.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.ChannelTabHandler;
|
||||
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 javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.*;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
public class PeertubeChannelTabExtractor extends ChannelTabExtractor {
|
||||
private JsonObject initialJson;
|
||||
private final String baseUrl;
|
||||
private String initialUrl;
|
||||
|
||||
public PeertubeChannelTabExtractor(final StreamingService service,
|
||||
final ChannelTabHandler linkHandler) throws ParsingException {
|
||||
super(service, linkHandler);
|
||||
baseUrl = getBaseUrl();
|
||||
initialUrl = this.baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + getId() + "/video-playlists?"
|
||||
+ START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||
if (getLinkHandler().getTab() != ChannelTabHandler.Tab.Playlists) {
|
||||
throw new ExtractionException("tab " + getLinkHandler().getTab().name() + " not supported");
|
||||
}
|
||||
|
||||
final Response response = downloader.get(initialUrl);
|
||||
if (response != null) {
|
||||
setInitialData(response.responseBody());
|
||||
} else {
|
||||
throw new ExtractionException("Unable to extract PeerTube channel playlist data");
|
||||
}
|
||||
}
|
||||
|
||||
private void setInitialData(final String responseBody) throws ExtractionException {
|
||||
try {
|
||||
initialJson = JsonParser.object().from(responseBody);
|
||||
} catch (final JsonParserException e) {
|
||||
throw new ExtractionException("Unable to extract PeerTube channel playlist data", e);
|
||||
}
|
||||
if (initialJson == null) {
|
||||
throw new ExtractionException("Unable to extract PeerTube channel playlist data");
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() throws ParsingException {
|
||||
return initialJson.getArray("data").getObject(0)
|
||||
.getObject("ownerAccount").getString("displayName", "");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public InfoItemsPage<InfoItem> getInitialPage() throws IOException, ExtractionException {
|
||||
return parsePage(initialJson, initialUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfoItemsPage<InfoItem> getPage(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);
|
||||
}
|
||||
}
|
||||
|
||||
return parsePage(pageJson, page.getUrl());
|
||||
}
|
||||
|
||||
private InfoItemsPage<InfoItem> parsePage(@Nullable JsonObject json, String pageUrl)
|
||||
throws ExtractionException {
|
||||
if (json == null) {
|
||||
throw new ExtractionException("Unable to get channel playlist list");
|
||||
}
|
||||
|
||||
PeertubeParsingHelper.validate(json);
|
||||
|
||||
final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId());
|
||||
JsonArray contents = json.getArray("data");
|
||||
if (contents == null) {
|
||||
throw new ParsingException("Unable to extract channel playlist list");
|
||||
}
|
||||
|
||||
for (final Object c : contents) {
|
||||
if (c instanceof JsonObject) {
|
||||
collector.commit(new PeertubePlaylistInfoItemExtractor((JsonObject) c, baseUrl));
|
||||
}
|
||||
}
|
||||
|
||||
return new InfoItemsPage<>(
|
||||
collector, PeertubeParsingHelper.getNextPage(pageUrl, json.getLong("total")));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package org.schabi.newpipe.extractor.services.peertube.extractors;
|
||||
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
|
||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class PeertubePlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
|
||||
|
||||
protected final JsonObject item;
|
||||
private final String baseUrl;
|
||||
|
||||
public PeertubePlaylistInfoItemExtractor(final JsonObject item, final String baseUrl) {
|
||||
this.item = item;
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() throws ParsingException {
|
||||
final String uuid = JsonUtils.getString(item, "uuid");
|
||||
return ServiceList.PeerTube.getPlaylistLHFactory().fromId(uuid, baseUrl).getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThumbnailUrl() throws ParsingException {
|
||||
return baseUrl + JsonUtils.getString(item, "thumbnailPath");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() throws ParsingException {
|
||||
return JsonUtils.getString(item, "displayName");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUploaderName() throws ParsingException {
|
||||
JsonObject owner = JsonUtils.getObject(item, "ownerAccount");
|
||||
return JsonUtils.getString(owner, "displayName");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStreamCount() throws ParsingException {
|
||||
return JsonUtils.getNumber(item, "videosLength").longValue();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public PlaylistInfo.PlaylistType getPlaylistType() throws ParsingException {
|
||||
return PlaylistInfoItemExtractor.super.getPlaylistType();
|
||||
}
|
||||
}
|
|
@ -26,15 +26,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.ChannelResponseData;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.DISABLE_PRETTY_PRINT_PARAMETER;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.YOUTUBEI_V1_URL;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.addClientInfoHeaders;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getChannelResponse;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getKey;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getValidJsonResponseBody;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.prepareDesktopJsonBuilder;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.resolveChannelId;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
|
||||
|
@ -82,7 +74,7 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
|
|||
ExtractionException {
|
||||
final String params = getParams();
|
||||
if (params == null) {
|
||||
throw new ExtractionException("tab not supported");
|
||||
throw new ExtractionException("tab " + getLinkHandler().getTab().name() + " not supported");
|
||||
}
|
||||
|
||||
final String id = resolveChannelId(super.getId());
|
||||
|
|
Loading…
Reference in New Issue