refactor: API changes

This commit is contained in:
ThetaDev 2022-11-04 23:47:44 +01:00
parent 7ec6a44926
commit f71fdac166
37 changed files with 608 additions and 415 deletions

View File

@ -7,7 +7,6 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.feed.FeedExtractor;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@ -146,6 +145,14 @@ public abstract class StreamingService {
*/
public abstract ListLinkHandlerFactory getChannelLHFactory();
/**
* Must return a new instance of an implementation of ListLinkHandlerFactory for channel tabs.
* If support for channel tabs is not given null must be returned.
*
* @return an instance of a ListLinkHandlerFactory for channels or null
*/
public abstract ListLinkHandlerFactory getChannelTabLHFactory();
/**
* Must return a new instance of an implementation of ListLinkHandlerFactory for playlists.
* If support for playlists is not given null must be returned.
@ -218,7 +225,13 @@ public abstract class StreamingService {
public abstract ChannelExtractor getChannelExtractor(ListLinkHandler linkHandler)
throws ExtractionException;
public abstract ChannelTabExtractor getChannelTabExtractor(ChannelTabHandler linkHandler)
/**
* Must create a new instance of a ChannelTabExtractor implementation.
*
* @param linkHandler is pointing to the channel which should be handled by this new instance.
* @return a new ChannelTabExtractor
*/
public abstract ChannelTabExtractor getChannelTabExtractor(ListLinkHandler linkHandler)
throws ExtractionException;
/**
@ -261,17 +274,17 @@ public abstract class StreamingService {
.fromQuery(id, contentFilter, sortFilter));
}
public ChannelTabExtractor getChannelTabExtractorFromUrl(final String url,
final ChannelTabHandler.Tab tab)
public ChannelTabExtractor getChannelTabExtractorFromId(final String id, final String tab)
throws ExtractionException {
return getChannelTabExtractor(
new ChannelTabHandler(getChannelLHFactory().fromUrl(url), tab));
return getChannelTabExtractor(getChannelTabLHFactory().fromQuery(
id, Collections.singletonList(tab), ""));
}
public ChannelTabExtractor getChannelTabExtractorFromId(final String id,
final ChannelTabHandler.Tab tab)
public ChannelTabExtractor getChannelTabExtractorFromId(final String id, final String tab,
final String baseUrl)
throws ExtractionException {
return getChannelTabExtractor(new ChannelTabHandler(getChannelLHFactory().fromId(id), tab));
return getChannelTabExtractor(getChannelTabLHFactory().fromQuery(
id, Collections.singletonList(tab), "", baseUrl));
}
public PlaylistExtractor getPlaylistExtractor(final String id,

View File

@ -3,7 +3,6 @@ package org.schabi.newpipe.extractor.channel;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
@ -49,7 +48,7 @@ public abstract class ChannelExtractor extends ListExtractor<StreamInfoItem> {
public abstract String getParentChannelAvatarUrl() throws ParsingException;
public abstract boolean isVerified() throws ParsingException;
@Nonnull
public List<ChannelTabHandler> getTabs() throws ParsingException {
public List<ListLinkHandler> getTabs() throws ParsingException {
return Collections.emptyList();
}
@Nonnull

View File

@ -6,7 +6,6 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.utils.ExtractorHelper;
@ -159,7 +158,7 @@ public class ChannelInfo extends ListInfo<StreamInfoItem> {
private String[] donationLinks;
private boolean verified;
private List<ChannelTabHandler> tabs = Collections.emptyList();
private List<ListLinkHandler> tabs = Collections.emptyList();
private List<String> tags = Collections.emptyList();
@ -244,11 +243,11 @@ public class ChannelInfo extends ListInfo<StreamInfoItem> {
}
@Nonnull
public List<ChannelTabHandler> getTabs() {
public List<ListLinkHandler> getTabs() {
return tabs;
}
public void setTabs(@Nonnull final List<ChannelTabHandler> tabs) {
public void setTabs(@Nonnull final List<ListLinkHandler> tabs) {
this.tabs = tabs;
}

View File

@ -4,31 +4,24 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import javax.annotation.Nonnull;
public abstract class ChannelTabExtractor extends ListExtractor<InfoItem> {
public ChannelTabExtractor(final StreamingService service,
final ChannelTabHandler linkHandler) {
final ListLinkHandler linkHandler) {
super(service, linkHandler);
}
@Nonnull
@Override
public ChannelTabHandler getLinkHandler() {
return (ChannelTabHandler) super.getLinkHandler();
}
@Nonnull
public ChannelTabHandler.Tab getTab() {
return getLinkHandler().getTab();
public String getTab() {
return getLinkHandler().getContentFilters().get(0);
}
@Nonnull
@Override
public String getName() throws ParsingException {
return getTab().name();
return getTab();
}
}

View File

@ -6,18 +6,18 @@ import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.utils.ExtractorHelper;
import java.io.IOException;
public class ChannelTabInfo extends ListInfo<InfoItem> {
public ChannelTabInfo(final int serviceId, final ChannelTabHandler linkHandler) {
super(serviceId, linkHandler, linkHandler.getTab().name());
public ChannelTabInfo(final int serviceId, final ListLinkHandler linkHandler) {
super(serviceId, linkHandler, linkHandler.getContentFilters().get(0));
}
public static ChannelTabInfo getInfo(final StreamingService service,
final ChannelTabHandler linkHandler)
final ListLinkHandler linkHandler)
throws ExtractionException, IOException {
final ChannelTabExtractor extractor = service.getChannelTabExtractor(linkHandler);
extractor.fetchPage();
@ -43,7 +43,7 @@ public class ChannelTabInfo extends ListInfo<InfoItem> {
}
public static ListExtractor.InfoItemsPage<InfoItem> getMoreItems(
final StreamingService service, final ChannelTabHandler linkHandler, final Page page)
final StreamingService service, final ListLinkHandler linkHandler, final Page page)
throws ExtractionException, IOException {
return service.getChannelTabExtractor(linkHandler).getPage(page);
}

View File

@ -1,22 +0,0 @@
package org.schabi.newpipe.extractor.linkhandler;
public class ChannelTabHandler extends ListLinkHandler {
public enum Tab {
Playlists,
Livestreams,
Shorts,
Channels,
Albums,
}
private final Tab tab;
public ChannelTabHandler(final ListLinkHandler linkHandler, final Tab tab) {
super(linkHandler);
this.tab = tab;
}
public Tab getTab() {
return tab;
}
}

View File

@ -0,0 +1,12 @@
package org.schabi.newpipe.extractor.linkhandler;
public final class ChannelTabs {
public static final String SHORTS = "shorts";
public static final String LIVE = "live";
public static final String CHANNELS = "channels";
public static final String PLAYLISTS = "playlists";
public static final String ALBUMS = "albums";
private ChannelTabs() {
}
}

View File

@ -8,7 +8,6 @@ import org.schabi.newpipe.extractor.channel.ChannelTabExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@ -29,6 +28,7 @@ import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampSearchE
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampStreamExtractor;
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampSuggestionExtractor;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampCommentsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampFeaturedLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampPlaylistLinkHandlerFactory;
@ -66,7 +66,12 @@ public class BandcampService extends StreamingService {
@Override
public ListLinkHandlerFactory getChannelLHFactory() {
return new BandcampChannelLinkHandlerFactory();
return BandcampChannelLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return BandcampChannelTabLinkHandlerFactory.getInstance();
}
@Override
@ -140,7 +145,7 @@ public class BandcampService extends StreamingService {
}
@Override
public ChannelTabExtractor getChannelTabExtractor(final ChannelTabHandler linkHandler) {
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) {
return new BandcampChannelTabExtractor(this, linkHandler);
}

View File

@ -12,7 +12,7 @@ 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.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.bandcamp.extractors.streaminfoitem.BandcampDiscographStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelTabHandler;
@ -109,14 +109,15 @@ public class BandcampChannelExtractor extends ChannelExtractor {
@Nonnull
@Override
public List<ChannelTabHandler> getTabs() throws ParsingException {
public List<ListLinkHandler> getTabs() throws ParsingException {
final JsonArray discography = channelInfo.getArray("discography");
if (discography.stream().anyMatch(o -> (
(JsonObject) o).getString("item_type").equals("album"))) {
final ListLinkHandler lh = getLinkHandler();
return Collections.singletonList(
new BandcampChannelTabHandler(getLinkHandler(),
ChannelTabHandler.Tab.Albums, discography));
new BandcampChannelTabHandler(lh.getUrl(), lh.getId(),
ChannelTabs.ALBUMS, discography));
}
return Collections.emptyList();
}

View File

@ -9,7 +9,8 @@ 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.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelTabHandler;
import javax.annotation.Nonnull;
@ -17,13 +18,13 @@ import java.io.IOException;
public class BandcampChannelTabExtractor extends ChannelTabExtractor {
public BandcampChannelTabExtractor(final StreamingService service,
final ChannelTabHandler linkHandler) {
final ListLinkHandler linkHandler) {
super(service, linkHandler);
}
@Nonnull
private JsonArray getDiscographs() throws ExtractionException {
final ChannelTabHandler tabHandler = getLinkHandler();
final ListLinkHandler tabHandler = getLinkHandler();
if (tabHandler instanceof BandcampChannelTabHandler) {
return ((BandcampChannelTabHandler) tabHandler).getDiscographs();
} else {
@ -34,9 +35,8 @@ public class BandcampChannelTabExtractor extends ChannelTabExtractor {
@Override
public void onFetchPage(@Nonnull final Downloader downloader) {
if (getLinkHandler().getTab() != ChannelTabHandler.Tab.Albums) {
throw new IllegalArgumentException(
"tab " + getLinkHandler().getTab().name() + " not supported");
if (!getTab().equals(ChannelTabs.ALBUMS)) {
throw new IllegalArgumentException("tab " + getTab() + " not supported");
}
}

View File

@ -17,8 +17,16 @@ import java.util.List;
/**
* Artist do have IDs that are useful
*/
public class BandcampChannelLinkHandlerFactory extends ListLinkHandlerFactory {
public final class BandcampChannelLinkHandlerFactory extends ListLinkHandlerFactory {
private static final BandcampChannelLinkHandlerFactory INSTANCE
= new BandcampChannelLinkHandlerFactory();
private BandcampChannelLinkHandlerFactory() {
}
public static BandcampChannelLinkHandlerFactory getInstance() {
return INSTANCE;
}
@Override
public String getId(final String url) throws ParsingException {
@ -31,7 +39,7 @@ public class BandcampChannelLinkHandlerFactory extends ListLinkHandlerFactory {
return String.valueOf(bandData.getLong("id"));
} catch (final IOException | ReCaptchaException | ArrayIndexOutOfBoundsException
| JsonParserException e) {
| JsonParserException e) {
throw new ParsingException("Download failed", e);
}
}
@ -73,6 +81,7 @@ public class BandcampChannelLinkHandlerFactory extends ListLinkHandlerFactory {
// Must have "releases" or "music" as segment after url or none at all
if (splitUrl.length > 3 && !(
splitUrl[3].equals("releases") || splitUrl[3].equals("music")
|| (splitUrl[3].equals("album") && splitUrl.length == 4)
)) {
return false;

View File

@ -1,15 +1,16 @@
package org.schabi.newpipe.extractor.services.bandcamp.linkHandler;
import com.grack.nanojson.JsonArray;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
public class BandcampChannelTabHandler extends ChannelTabHandler {
import java.util.Collections;
public class BandcampChannelTabHandler extends ListLinkHandler {
private final JsonArray discographs;
public BandcampChannelTabHandler(final ListLinkHandler linkHandler, final Tab tab,
public BandcampChannelTabHandler(final String url, final String id, final String tab,
final JsonArray discographs) {
super(linkHandler, tab);
super(url, url, id, Collections.singletonList(tab), "");
this.discographs = discographs;
}

View File

@ -0,0 +1,49 @@
package org.schabi.newpipe.extractor.services.bandcamp.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List;
public final class BandcampChannelTabLinkHandlerFactory extends ListLinkHandlerFactory {
private static final BandcampChannelTabLinkHandlerFactory INSTANCE
= new BandcampChannelTabLinkHandlerFactory();
private BandcampChannelTabLinkHandlerFactory() {
}
public static BandcampChannelTabLinkHandlerFactory getInstance() {
return INSTANCE;
}
@Override
public String getId(final String url) throws ParsingException {
return BandcampChannelLinkHandlerFactory.getInstance().getId(url);
}
@Override
public String getUrl(final String id, final List<String> contentFilter, final String sortFilter)
throws ParsingException {
final String tab = contentFilter.get(0);
if (!tab.equals(ChannelTabs.ALBUMS)) {
throw new ParsingException("tab " + tab + " not supported");
}
// This is not an actual page on the Bandcamp website, but it auto-redirects
// to the main page and we need a unique URL for the album tab
return BandcampChannelLinkHandlerFactory.getInstance().getUrl(id) + "/album";
}
@Override
public boolean onAcceptUrl(final String url) throws ParsingException {
return BandcampChannelLinkHandlerFactory.getInstance().onAcceptUrl(url);
}
@Override
public String[] getAvailableContentFilter() {
return new String[] {
ChannelTabs.ALBUMS,
};
}
}

View File

@ -6,7 +6,6 @@ import org.schabi.newpipe.extractor.channel.ChannelTabExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@ -57,6 +56,11 @@ public class MediaCCCService extends StreamingService {
return new MediaCCCConferenceLinkHandlerFactory();
}
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return null;
}
@Override
public ListLinkHandlerFactory getPlaylistLHFactory() {
return null;
@ -81,7 +85,7 @@ public class MediaCCCService extends StreamingService {
}
@Override
public ChannelTabExtractor getChannelTabExtractor(final ChannelTabHandler linkHandler)
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler)
throws ExtractionException {
return null;
}

View File

@ -10,7 +10,6 @@ import org.schabi.newpipe.extractor.channel.ChannelExtractor;
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.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory;
@ -77,7 +76,7 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor {
@Nonnull
@Override
public List<ChannelTabHandler> getTabs() {
public List<ListLinkHandler> getTabs() {
return Collections.emptyList();
}

View File

@ -5,8 +5,9 @@ import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.channel.ChannelTabExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@ -26,6 +27,7 @@ import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeStreamE
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeSuggestionExtractor;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeTrendingExtractor;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeCommentsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubePlaylistLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
@ -64,6 +66,11 @@ public class PeertubeService extends StreamingService {
return PeertubeChannelLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return PeertubeChannelTabLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getPlaylistLHFactory() {
return PeertubePlaylistLinkHandlerFactory.getInstance();
@ -108,13 +115,16 @@ public class PeertubeService extends StreamingService {
}
@Override
public ChannelTabExtractor getChannelTabExtractor(final ChannelTabHandler linkHandler)
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler)
throws ExtractionException {
if (linkHandler.getUrl().contains("/video-channels/")) {
return new PeertubeChannelTabExtractor(this, linkHandler);
} else {
return new PeertubeAccountTabExtractor(this, linkHandler);
final String tab = linkHandler.getContentFilters().get(0);
switch (tab) {
case ChannelTabs.CHANNELS:
return new PeertubeAccountTabExtractor(this, linkHandler);
case ChannelTabs.PLAYLISTS:
return new PeertubeChannelTabExtractor(this, linkHandler);
}
throw new ParsingException("tab " + tab + " not supported");
}
@Override

View File

@ -12,7 +12,7 @@ import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory;
@ -124,9 +124,11 @@ public class PeertubeAccountExtractor extends ChannelExtractor {
@Nonnull
@Override
public List<ChannelTabHandler> getTabs() {
public List<ListLinkHandler> getTabs() throws ParsingException {
return Collections.singletonList(
new ChannelTabHandler(getLinkHandler(), ChannelTabHandler.Tab.Channels));
new ListLinkHandler(getOriginalUrl(), getUrl(), getId(),
Collections.singletonList(ChannelTabs.CHANNELS), "")
);
}
@Nonnull

View File

@ -12,7 +12,8 @@ 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.linkhandler.ChannelTabs;
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;
@ -30,17 +31,16 @@ public class PeertubeAccountTabExtractor extends ChannelTabExtractor {
private static final String ACCOUNTS = "accounts/";
public PeertubeAccountTabExtractor(final StreamingService service,
final ChannelTabHandler linkHandler)
final ListLinkHandler linkHandler)
throws ParsingException {
super(service, linkHandler);
baseUrl = getBaseUrl();
}
@Override
public void onFetchPage(final @Nonnull Downloader downloader) {
if (getLinkHandler().getTab() != ChannelTabHandler.Tab.Channels) {
throw new IllegalArgumentException(
"tab " + getLinkHandler().getTab().name() + " not supported");
public void onFetchPage(final @Nonnull Downloader downloader) throws ParsingException {
if (!getTab().equals(ChannelTabs.CHANNELS)) {
throw new ParsingException("tab " + getTab() + " not supported");
}
}

View File

@ -10,7 +10,7 @@ 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.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory;
@ -103,9 +103,11 @@ public class PeertubeChannelExtractor extends ChannelExtractor {
@Nonnull
@Override
public List<ChannelTabHandler> getTabs() {
public List<ListLinkHandler> getTabs() throws ParsingException {
return Collections.singletonList(
new ChannelTabHandler(getLinkHandler(), ChannelTabHandler.Tab.Playlists));
new ListLinkHandler(getOriginalUrl(), getUrl(), getId(),
Collections.singletonList(ChannelTabs.PLAYLISTS), "")
);
}
@Nonnull

View File

@ -12,7 +12,8 @@ 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.linkhandler.ChannelTabs;
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;
@ -29,17 +30,16 @@ public class PeertubeChannelTabExtractor extends ChannelTabExtractor {
private final String baseUrl;
public PeertubeChannelTabExtractor(final StreamingService service,
final ChannelTabHandler linkHandler)
final ListLinkHandler linkHandler)
throws ParsingException {
super(service, linkHandler);
baseUrl = getBaseUrl();
}
@Override
public void onFetchPage(final @Nonnull Downloader downloader) {
if (getLinkHandler().getTab() != ChannelTabHandler.Tab.Playlists) {
throw new IllegalArgumentException(
"tab " + getLinkHandler().getTab().name() + " not supported");
public void onFetchPage(final @Nonnull Downloader downloader) throws ParsingException {
if (!getTab().equals(ChannelTabs.PLAYLISTS)) {
throw new ParsingException("tab " + getTab() + " not supported");
}
}

View File

@ -0,0 +1,61 @@
package org.schabi.newpipe.extractor.services.peertube.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
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;
}
private static String getUrlSuffix(final String tab) throws ParsingException {
switch (tab) {
case ChannelTabs.PLAYLISTS:
return "/video-playlists";
case ChannelTabs.CHANNELS:
return "/video-channels";
}
throw new ParsingException("tab " + tab + " not supported");
}
@Override
public String getId(final String url) throws ParsingException {
return PeertubeChannelLinkHandlerFactory.getInstance().getId(url);
}
@Override
public String getUrl(final String id, final List<String> contentFilter, final String sortFilter)
throws ParsingException {
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 {
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.PLAYLISTS,
ChannelTabs.CHANNELS,
};
}
}

View File

@ -6,7 +6,6 @@ import org.schabi.newpipe.extractor.channel.ChannelTabExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@ -26,6 +25,7 @@ import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudStr
import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudSubscriptionExtractor;
import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudSuggestionExtractor;
import org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudChartsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudCommentsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudPlaylistLinkHandlerFactory;
@ -66,6 +66,11 @@ public class SoundcloudService extends StreamingService {
return SoundcloudChannelLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return SoundcloudChannelTabLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getPlaylistLHFactory() {
return SoundcloudPlaylistLinkHandlerFactory.getInstance();
@ -90,7 +95,7 @@ public class SoundcloudService extends StreamingService {
}
@Override
public ChannelTabExtractor getChannelTabExtractor(final ChannelTabHandler linkHandler) {
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) {
return new SoundcloudChannelTabExtractor(this, linkHandler);
}

View File

@ -9,7 +9,7 @@ import org.schabi.newpipe.extractor.channel.ChannelExtractor;
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.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
@ -18,6 +18,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper.SOUNDCLOUD_API_V2_URL;
@ -109,10 +110,13 @@ public class SoundcloudChannelExtractor extends ChannelExtractor {
@Nonnull
@Override
public List<ChannelTabHandler> getTabs() throws ParsingException {
public List<ListLinkHandler> getTabs() throws ParsingException {
return Arrays.asList(
new ChannelTabHandler(getLinkHandler(), ChannelTabHandler.Tab.Playlists),
new ChannelTabHandler(getLinkHandler(), ChannelTabHandler.Tab.Albums));
new ListLinkHandler(getOriginalUrl(), getUrl(), getId(),
Collections.singletonList(ChannelTabs.PLAYLISTS), ""),
new ListLinkHandler(getOriginalUrl(), getUrl(), getId(),
Collections.singletonList(ChannelTabs.ALBUMS), "")
);
}
@Nonnull

View File

@ -7,8 +7,8 @@ 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.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
import javax.annotation.Nonnull;
@ -22,29 +22,19 @@ public class SoundcloudChannelTabExtractor extends ChannelTabExtractor {
private static final String USERS_ENDPOINT = SOUNDCLOUD_API_V2_URL + "users/";
public SoundcloudChannelTabExtractor(final StreamingService service,
final ChannelTabHandler linkHandler) {
final ListLinkHandler linkHandler) {
super(service, linkHandler);
userId = getLinkHandler().getId();
}
private String getEndpoint() {
switch (getTab()) {
case Playlists:
case ChannelTabs.PLAYLISTS:
return "/playlists_without_albums";
case Albums:
case ChannelTabs.ALBUMS:
return "/albums";
}
throw new IllegalArgumentException("unsupported tab: " + getTab().name());
}
String getUrlSuffix() {
switch (getTab()) {
case Playlists:
return "/sets";
case Albums:
return "/albums";
}
throw new IllegalArgumentException("tab " + getTab().name() + " not supported");
throw new IllegalArgumentException("unsupported tab: " + getTab());
}
@Override
@ -58,12 +48,6 @@ public class SoundcloudChannelTabExtractor extends ChannelTabExtractor {
return userId;
}
@Nonnull
@Override
public String getUrl() throws ParsingException {
return super.getUrl() + getUrlSuffix();
}
@Nonnull
@Override
public InfoItemsPage<InfoItem> getInitialPage() throws IOException, ExtractionException {

View File

@ -0,0 +1,54 @@
package org.schabi.newpipe.extractor.services.soundcloud.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List;
public final class SoundcloudChannelTabLinkHandlerFactory extends ListLinkHandlerFactory {
private static final SoundcloudChannelTabLinkHandlerFactory INSTANCE
= new SoundcloudChannelTabLinkHandlerFactory();
private SoundcloudChannelTabLinkHandlerFactory() {
}
public static SoundcloudChannelTabLinkHandlerFactory getInstance() {
return INSTANCE;
}
private static String getUrlSuffix(final String tab) throws ParsingException {
switch (tab) {
case ChannelTabs.PLAYLISTS:
return "/sets";
case ChannelTabs.ALBUMS:
return "/albums";
}
throw new ParsingException("tab " + tab + " not supported");
}
@Override
public String getId(final String url) throws ParsingException {
return SoundcloudChannelLinkHandlerFactory.getInstance().getId(url);
}
@Override
public String getUrl(final String id, final List<String> contentFilter, final String sortFilter)
throws ParsingException {
return SoundcloudChannelLinkHandlerFactory.getInstance().getUrl(id)
+ getUrlSuffix(contentFilter.get(0));
}
@Override
public boolean onAcceptUrl(final String url) throws ParsingException {
return SoundcloudChannelLinkHandlerFactory.getInstance().onAcceptUrl(url);
}
@Override
public String[] getAvailableContentFilter() {
return new String[] {
ChannelTabs.PLAYLISTS,
ChannelTabs.ALBUMS,
};
}
}

View File

@ -483,7 +483,7 @@ public final class YoutubeParsingHelper {
/**
* @param playlistId the playlist id to parse
* @return the {@link PlaylistInfo.PlaylistType} extracted from the playlistId (mix playlist
* types included)
* types included)
* @throws ParsingException if the playlistId is null or empty, if the playlistId is not a mix,
* if it is a mix but it's not based on a specific stream (this is the
* case for channel or genre mixes)
@ -516,7 +516,7 @@ public final class YoutubeParsingHelper {
// 11 characters then it can't be a video id, hence we are dealing with a different
// type of mix (e.g. genre mixes handled above, of the form RDGMEM{garbage})
throw new ParsingException("Video id could not be determined from mix id: "
+ playlistId);
+ playlistId);
}
return playlistId.substring(2);
@ -529,7 +529,7 @@ public final class YoutubeParsingHelper {
/**
* @param playlistId the playlist id to parse
* @return the {@link PlaylistInfo.PlaylistType} extracted from the playlistId (mix playlist
* types included)
* types included)
* @throws ParsingException if the playlistId is null or empty
*/
@Nonnull
@ -557,7 +557,7 @@ public final class YoutubeParsingHelper {
/**
* @param playlistUrl the playlist url to parse
* @return the {@link PlaylistInfo.PlaylistType} extracted from the playlistUrl's list param
* (mix playlist types included)
* (mix playlist types included)
* @throws ParsingException if the playlistUrl is malformed, if has no list param or if the list
* param is empty
*/
@ -587,20 +587,20 @@ public final class YoutubeParsingHelper {
}
// @formatter:off
final byte[] body = JsonWriter.string()
.object()
.object()
.object("context")
.object("client")
.value("hl", "en-GB")
.value("gl", "GB")
.value("clientName", "WEB")
.value("clientVersion", HARDCODED_CLIENT_VERSION)
.end()
.object("client")
.value("hl", "en-GB")
.value("gl", "GB")
.value("clientName", "WEB")
.value("clientVersion", HARDCODED_CLIENT_VERSION)
.end()
.object("user")
.value("lockedSafetyMode", false)
.value("lockedSafetyMode", false)
.end()
.value("fetchLiveState", true)
.end()
.end().done().getBytes(UTF_8);
.end().done().getBytes(UTF_8);
// @formatter:on
final Map<String, List<String>> headers = new HashMap<>();
@ -611,7 +611,7 @@ public final class YoutubeParsingHelper {
// This endpoint is fetched by the YouTube website to get the items of its main menu and is
// pretty lightweight (around 30kB)
final Response response = getDownloader().post(YOUTUBEI_V1_URL + "guide?key="
+ HARDCODED_KEY + DISABLE_PRETTY_PRINT_PARAMETER, headers, body);
+ HARDCODED_KEY + DISABLE_PRETTY_PRINT_PARAMETER, headers, body);
final String responseBody = response.responseBody();
final int responseCode = response.responseCode();
@ -688,14 +688,14 @@ public final class YoutubeParsingHelper {
throw new ParsingException(
// CHECKSTYLE:OFF
"Could not extract YouTube WEB InnerTube API key from HTML search results page");
// CHECKSTYLE:ON
// CHECKSTYLE:ON
}
if (clientVersion == null) {
throw new ParsingException(
// CHECKSTYLE:OFF
"Could not extract YouTube WEB InnerTube client version from HTML search results page");
// CHECKSTYLE:ON
// CHECKSTYLE:ON
}
keyAndVersionExtracted = true;
@ -822,30 +822,30 @@ public final class YoutubeParsingHelper {
// @formatter:off
final byte[] json = JsonWriter.string()
.object()
.object()
.object("context")
.object("client")
.value("clientName", "WEB_REMIX")
.value("clientVersion", HARDCODED_YOUTUBE_MUSIC_KEY[2])
.value("hl", "en-GB")
.value("gl", "GB")
.array("experimentIds").end()
.value("experimentsToken", "")
.object("locationInfo").end()
.object("musicAppInfo").end()
.end()
.object("capabilities").end()
.object("request")
.array("internalExperimentFlags").end()
.object("sessionIndex").end()
.end()
.object("activePlayers").end()
.object("user")
.value("enableSafetyMode", false)
.end()
.object("client")
.value("clientName", "WEB_REMIX")
.value("clientVersion", HARDCODED_YOUTUBE_MUSIC_KEY[2])
.value("hl", "en-GB")
.value("gl", "GB")
.array("experimentIds").end()
.value("experimentsToken", "")
.object("locationInfo").end()
.object("musicAppInfo").end()
.end()
.object("capabilities").end()
.object("request")
.array("internalExperimentFlags").end()
.object("sessionIndex").end()
.end()
.object("activePlayers").end()
.object("user")
.value("enableSafetyMode", false)
.end()
.end()
.value("input", "")
.end().done().getBytes(UTF_8);
.end().done().getBytes(UTF_8);
// @formatter:on
final Map<String, List<String>> headers = new HashMap<>();
@ -882,10 +882,10 @@ public final class YoutubeParsingHelper {
headers.put("Origin", singletonList("https://music.youtube.com"));
headers.put("Referer", singletonList("https://music.youtube.com"));
final String response = getDownloader().get(url, headers).responseBody();
musicClientVersion = getStringResultFromRegexArray(response,
INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES, 1);
musicKey = getStringResultFromRegexArray(response, INNERTUBE_API_KEY_REGEXES, 1);
musicClientName = Parser.matchGroup1(INNERTUBE_CLIENT_NAME_REGEX, response);
musicClientVersion = getStringResultFromRegexArray(response,
INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES, 1);
musicKey = getStringResultFromRegexArray(response, INNERTUBE_API_KEY_REGEXES, 1);
musicClientName = Parser.matchGroup1(INNERTUBE_CLIENT_NAME_REGEX, response);
} catch (final Exception e) {
final String url = "https://music.youtube.com/?ucbcb=1";
final String html = getDownloader().get(url, getCookieHeader()).responseBody();
@ -896,7 +896,7 @@ public final class YoutubeParsingHelper {
musicClientName = Parser.matchGroup1(INNERTUBE_CLIENT_NAME_REGEX, html);
}
youtubeMusicKey = new String[] {musicKey, musicClientName, musicClientVersion};
youtubeMusicKey = new String[]{musicKey, musicClientName, musicClientVersion};
return youtubeMusicKey;
}
@ -1142,52 +1142,40 @@ public final class YoutubeParsingHelper {
@Nonnull
public static JsonBuilder<JsonObject> prepareDesktopJsonBuilder(
@Nonnull final Localization localization,
@Nonnull final ContentCountry contentCountry,
@Nullable final String vData)
@Nonnull final ContentCountry contentCountry)
throws IOException, ExtractionException {
// @formatter:off
final JsonBuilder<JsonObject> builder = JsonObject.builder()
.object("context")
.object("client")
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.value("clientName", "WEB")
.value("clientVersion", getClientVersion())
.value("originalUrl", "https://www.youtube.com")
.value("platform", "DESKTOP");
.object("client")
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.value("clientName", "WEB")
.value("clientVersion", getClientVersion())
.value("originalUrl", "https://www.youtube.com")
.value("platform", "DESKTOP");
// Use specified visitor data, otherwise fall back to the configured value
if (vData != null) {
builder.value("visitorData", vData);
} else if (visitorData != null) {
if (visitorData != null) {
builder.value("visitorData", visitorData);
}
builder.end()
.object("request")
.array("internalExperimentFlags")
.end()
.value("useSsl", true)
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.object("request")
.array("internalExperimentFlags")
.end()
.value("useSsl", true)
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.end();
// @formatter:on
return builder;
}
@Nonnull
public static JsonBuilder<JsonObject> prepareDesktopJsonBuilder(
@Nonnull final Localization localization,
@Nonnull final ContentCountry contentCountry)
throws IOException, ExtractionException {
return prepareDesktopJsonBuilder(localization, contentCountry, visitorData);
}
@Nonnull
public static JsonBuilder<JsonObject> prepareAndroidMobileJsonBuilder(
@Nonnull final Localization localization,
@ -1195,32 +1183,32 @@ public final class YoutubeParsingHelper {
// @formatter:off
return JsonObject.builder()
.object("context")
.object("client")
.value("clientName", "ANDROID")
.value("clientVersion", ANDROID_YOUTUBE_CLIENT_VERSION)
.value("platform", "MOBILE")
.value("osName", "Android")
.value("osVersion", "12")
/*
A valid Android SDK version is required to be sure to get a valid player
response
If this parameter is not provided, the player response may be replaced by
the one of a 5-minute video saying the message "The following content is
not available on this app. Watch this content on the latest version on
YouTube"
See https://github.com/TeamNewPipe/NewPipe/issues/8713
The Android SDK version corresponding to the Android version used in
requests is sent
*/
.value("androidSdkVersion", 31)
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.object("client")
.value("clientName", "ANDROID")
.value("clientVersion", ANDROID_YOUTUBE_CLIENT_VERSION)
.value("platform", "MOBILE")
.value("osName", "Android")
.value("osVersion", "12")
/*
A valid Android SDK version is required to be sure to get a valid player
response
If this parameter is not provided, the player response may be replaced by
the one of a 5-minute video saying the message "The following content is
not available on this app. Watch this content on the latest version on
YouTube"
See https://github.com/TeamNewPipe/NewPipe/issues/8713
The Android SDK version corresponding to the Android version used in
requests is sent
*/
.value("androidSdkVersion", 31)
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.end();
// @formatter:on
}
@ -1232,27 +1220,27 @@ public final class YoutubeParsingHelper {
// @formatter:off
return JsonObject.builder()
.object("context")
.object("client")
.value("clientName", "IOS")
.value("clientVersion", IOS_YOUTUBE_CLIENT_VERSION)
.value("deviceMake", "Apple")
// Device model is required to get 60fps streams
.value("deviceModel", IOS_DEVICE_MODEL)
.value("platform", "MOBILE")
.value("osName", "iOS")
// The value of this field seems to use the following structure:
// "iOS version.0.build version"
// The build version corresponding to the iOS version used can be found on
// https://www.theiphonewiki.com/wiki/Firmware/iPhone/15.x#iPhone_13
.value("osVersion", "15.6.0.19G71")
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.object("client")
.value("clientName", "IOS")
.value("clientVersion", IOS_YOUTUBE_CLIENT_VERSION)
.value("deviceMake", "Apple")
// Device model is required to get 60fps streams
.value("deviceModel", IOS_DEVICE_MODEL)
.value("platform", "MOBILE")
.value("osName", "iOS")
// The value of this field seems to use the following structure:
// "iOS version.0.build version"
// The build version corresponding to the iOS version used can be found on
// https://www.theiphonewiki.com/wiki/Firmware/iPhone/15.x#iPhone_13
.value("osVersion", "15.6.0.19G71")
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.end();
// @formatter:on
}
@ -1265,22 +1253,22 @@ public final class YoutubeParsingHelper {
// @formatter:off
return JsonObject.builder()
.object("context")
.object("client")
.value("clientName", "TVHTML5_SIMPLY_EMBEDDED_PLAYER")
.value("clientVersion", TVHTML5_SIMPLY_EMBED_CLIENT_VERSION)
.value("clientScreen", "EMBED")
.value("platform", "TV")
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.end()
.object("thirdParty")
.value("embedUrl", "https://www.youtube.com/watch?v=" + videoId)
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.object("client")
.value("clientName", "TVHTML5_SIMPLY_EMBEDDED_PLAYER")
.value("clientVersion", TVHTML5_SIMPLY_EMBED_CLIENT_VERSION)
.value("clientScreen", "EMBED")
.value("platform", "TV")
.value("hl", localization.getLocalizationCode())
.value("gl", contentCountry.getCountryCode())
.end()
.object("thirdParty")
.value("embedUrl", "https://www.youtube.com/watch?v=" + videoId)
.end()
.object("user")
// TO DO: provide a way to enable restricted mode with:
// .value("enableSafetyMode", boolean)
.value("lockedSafetyMode", false)
.end()
.end();
// @formatter:on
}
@ -1297,19 +1285,19 @@ public final class YoutubeParsingHelper {
return JsonWriter.string((isTvHtml5DesktopJsonBuilder
? prepareTvHtml5EmbedJsonBuilder(localization, contentCountry, videoId)
: prepareDesktopJsonBuilder(localization, contentCountry))
.object("playbackContext")
.object("contentPlaybackContext")
.object("playbackContext")
.object("contentPlaybackContext")
// Signature timestamp from the JavaScript base player is needed to get
// working obfuscated URLs
.value("signatureTimestamp", sts)
.value("referer", "https://www.youtube.com/watch?v=" + videoId)
.end()
.end()
.value(CPN, contentPlaybackNonce)
.value(VIDEO_ID, videoId)
.value(CONTENT_CHECK_OK, true)
.value(RACY_CHECK_OK, true)
.done())
.end()
.end()
.value(CPN, contentPlaybackNonce)
.value(VIDEO_ID, videoId)
.value(CONTENT_CHECK_OK, true)
.value(RACY_CHECK_OK, true)
.done())
.getBytes(StandardCharsets.UTF_8);
// @formatter:on
}
@ -1704,8 +1692,7 @@ public final class YoutubeParsingHelper {
public static ChannelResponseData getChannelResponse(final String channelId,
final String params,
final Localization loc,
final ContentCountry country,
@Nullable final String vData)
final ContentCountry country)
throws ExtractionException, IOException {
String id = channelId;
JsonObject ajaxJson = null;
@ -1713,7 +1700,7 @@ public final class YoutubeParsingHelper {
int level = 0;
while (level < 3) {
final byte[] body = JsonWriter.string(prepareDesktopJsonBuilder(
loc, country, vData)
loc, country)
.value("browseId", id)
.value("params", params) // Equal to videos
.done())

View File

@ -7,7 +7,6 @@ import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.feed.FeedExtractor;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@ -31,6 +30,7 @@ import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSubscript
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSuggestionExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeTrendingExtractor;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeCommentsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubePlaylistLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
@ -90,6 +90,11 @@ public class YoutubeService extends StreamingService {
return YoutubeChannelLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getChannelTabLHFactory() {
return YoutubeChannelTabLinkHandlerFactory.getInstance();
}
@Override
public ListLinkHandlerFactory getPlaylistLHFactory() {
return YoutubePlaylistLinkHandlerFactory.getInstance();
@ -111,7 +116,7 @@ public class YoutubeService extends StreamingService {
}
@Override
public ChannelTabExtractor getChannelTabExtractor(final ChannelTabHandler linkHandler) {
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) {
return new YoutubeChannelTabExtractor(this, linkHandler);
}

View File

@ -11,11 +11,10 @@ import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
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.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YouTubeChannelTabHandler;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
@ -27,6 +26,7 @@ import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -69,7 +69,7 @@ import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
public class YoutubeChannelExtractor extends ChannelExtractor {
private JsonObject initialData;
private JsonObject videoTab;
private List<ChannelTabHandler> tabs;
private List<ListLinkHandler> tabs;
/**
* Some channels have response redirects and the only way to reliably get the id is by saving it
@ -94,7 +94,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
final String channelPath = super.getId();
final String id = resolveChannelId(channelPath);
final ChannelResponseData data = getChannelResponse(id, "EgZ2aWRlb3M%3D",
getExtractorLocalization(), getExtractorContentCountry(), null);
getExtractorLocalization(), getExtractorContentCountry());
initialData = data.responseJson;
redirectedChannelId = data.channelId;
@ -227,7 +227,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
@Nonnull
@Override
public List<ChannelTabHandler> getTabs() throws ParsingException {
public List<ListLinkHandler> getTabs() throws ParsingException {
getVideoTab();
return tabs;
}
@ -393,8 +393,13 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
final String visitorData = initialData.getObject("responseContext")
.getString("visitorData");
final Consumer<ChannelTabHandler.Tab> addTab = tab ->
tabs.add(new YouTubeChannelTabHandler(getLinkHandler(), tab, visitorData));
final Consumer<String> addTab = tab -> {
try {
tabs.add(new ListLinkHandler(getOriginalUrl(), getUrl(), redirectedChannelId,
Collections.singletonList(tab), ""));
} catch (final ParsingException ignored) {
}
};
for (final Object tab : responseTabs) {
if (((JsonObject) tab).has("tabRenderer")) {
@ -411,16 +416,16 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
foundVideoTab = tabRenderer;
break;
case "playlists":
addTab.accept(ChannelTabHandler.Tab.Playlists);
addTab.accept(ChannelTabs.PLAYLISTS);
break;
case "streams":
addTab.accept(ChannelTabHandler.Tab.Livestreams);
addTab.accept(ChannelTabs.LIVE);
break;
case "shorts":
addTab.accept(ChannelTabHandler.Tab.Shorts);
addTab.accept(ChannelTabs.SHORTS);
break;
case "channels":
addTab.accept(ChannelTabHandler.Tab.Channels);
addTab.accept(ChannelTabs.CHANNELS);
break;
}
}

View File

@ -12,9 +12,9 @@ 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.youtube.linkHandler.YouTubeChannelTabHandler;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import javax.annotation.Nonnull;
@ -22,6 +22,7 @@ import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -45,47 +46,22 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
private String redirectedChannelId;
public YoutubeChannelTabExtractor(final StreamingService service,
final ChannelTabHandler linkHandler) {
final ListLinkHandler linkHandler) {
super(service, linkHandler);
}
@Nullable
String getParams() {
private String getParams() throws ParsingException {
switch (getTab()) {
case Playlists:
case ChannelTabs.PLAYLISTS:
return "EglwbGF5bGlzdHPyBgQKAkIA";
case Livestreams:
case ChannelTabs.LIVE:
return "EgdzdHJlYW1z8gYECgJ6AA%3D%3D";
case Shorts:
case ChannelTabs.SHORTS:
return "EgZzaG9ydHPyBgUKA5oBAA%3D%3D";
case Channels:
case ChannelTabs.CHANNELS:
return "EghjaGFubmVsc_IGBAoCUgA%3D";
}
throw new IllegalArgumentException("tab " + getTab().name() + " not supported");
}
String getUrlSuffix() {
switch (getTab()) {
case Playlists:
return "/playlists";
case Livestreams:
return "/streams";
case Shorts:
return "/shorts";
case Channels:
return "/channels";
}
throw new IllegalArgumentException("tab " + getTab().name() + " not supported");
}
@Nullable
private String getVisitorData() {
final ChannelTabHandler tabHandler = getLinkHandler();
if (tabHandler instanceof YouTubeChannelTabHandler) {
return ((YouTubeChannelTabHandler) tabHandler).getVisitorData();
} else {
return null;
}
throw new ParsingException("tab " + getTab() + " not supported");
}
@Override
@ -94,8 +70,7 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
final String params = getParams();
final String id = resolveChannelId(super.getId());
final ChannelResponseData data = getChannelResponse(id, params,
getExtractorLocalization(), getExtractorContentCountry(),
getVisitorData());
getExtractorLocalization(), getExtractorContentCountry());
initialData = data.responseJson;
redirectedChannelId = data.channelId;
@ -105,8 +80,8 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
@Override
public String getUrl() throws ParsingException {
try {
return YoutubeChannelLinkHandlerFactory.getInstance().getUrl(
"channel/" + getId() + getUrlSuffix());
return YoutubeChannelTabLinkHandlerFactory.getInstance().getUrl("channel/" + getId(),
Collections.singletonList(getTab()), "");
} catch (final ParsingException e) {
return super.getUrl();
}
@ -199,11 +174,13 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
}
@Nullable
private JsonObject getTabData() {
private JsonObject getTabData() throws ParsingException {
if (this.tabData != null) {
return this.tabData;
}
final String urlSuffix = YoutubeChannelTabLinkHandlerFactory.getUrlSuffix(getTab());
final JsonArray tabs = initialData.getObject("contents")
.getObject("twoColumnBrowseResultsRenderer")
.getArray("tabs");
@ -213,7 +190,7 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
if (((JsonObject) tab).has("tabRenderer")) {
if (((JsonObject) tab).getObject("tabRenderer").getObject("endpoint")
.getObject("commandMetadata").getObject("webCommandMetadata")
.getString("url").endsWith(getUrlSuffix())) {
.getString("url").endsWith(urlSuffix)) {
foundTab = ((JsonObject) tab).getObject("tabRenderer");
break;
}
@ -324,8 +301,7 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
.getString("token");
final byte[] body = JsonWriter.string(prepareDesktopJsonBuilder(getExtractorLocalization(),
getExtractorContentCountry(),
getVisitorData())
getExtractorContentCountry())
.value("continuation", continuation)
.done())
.getBytes(StandardCharsets.UTF_8);

View File

@ -1,31 +0,0 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import javax.annotation.Nullable;
public class YouTubeChannelTabHandler extends ChannelTabHandler {
/**
* Since YouTube is currently A/B testing a new tab layout,
* we need to store the visitor data cookie when fetching a channel and pass it to
* YouTube when requesting channel tabs. Otherwise YouTube may not enable the A/B test
* on subsequent requests and return empty tabs.
* <p>
* This may be removed when the new layout is made permanent.
*/
@Nullable
private final String visitorData;
public YouTubeChannelTabHandler(final ListLinkHandler linkHandler, final Tab tab,
@Nullable final String visitorData) {
super(linkHandler, tab);
this.visitorData = visitorData;
}
@Nullable
public String getVisitorData() {
return visitorData;
}
}

View File

@ -0,0 +1,64 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List;
public final class YoutubeChannelTabLinkHandlerFactory extends ListLinkHandlerFactory {
private static final YoutubeChannelTabLinkHandlerFactory INSTANCE =
new YoutubeChannelTabLinkHandlerFactory();
private YoutubeChannelTabLinkHandlerFactory() {
}
public static YoutubeChannelTabLinkHandlerFactory getInstance() {
return INSTANCE;
}
public static String getUrlSuffix(final String tab) throws ParsingException {
switch (tab) {
case ChannelTabs.PLAYLISTS:
return "/playlists";
case ChannelTabs.LIVE:
return "/streams";
case ChannelTabs.SHORTS:
return "/shorts";
case ChannelTabs.CHANNELS:
return "/channels";
}
throw new ParsingException("tab " + tab + " not supported");
}
@Override
public String getUrl(final String id, final List<String> contentFilter, final String sortFilter)
throws ParsingException {
return "https://www.youtube.com/" + id + getUrlSuffix(contentFilter.get(0));
}
@Override
public String getId(final String url) throws ParsingException {
return YoutubeChannelLinkHandlerFactory.getInstance().getId(url);
}
@Override
public boolean onAcceptUrl(final String url) throws ParsingException {
try {
getId(url);
} catch (final ParsingException e) {
return false;
}
return true;
}
@Override
public String[] getAvailableContentFilter() {
return new String[] {
ChannelTabs.SHORTS,
ChannelTabs.LIVE,
ChannelTabs.CHANNELS,
ChannelTabs.PLAYLISTS,
};
}
}

View File

@ -19,7 +19,7 @@ public class BandcampChannelLinkHandlerFactoryTest {
@BeforeAll
public static void setUp() {
linkHandler = new BandcampChannelLinkHandlerFactory();
linkHandler = BandcampChannelLinkHandlerFactory.getInstance();
NewPipe.init(DownloaderTestImpl.getInstance());
}

View File

@ -6,7 +6,7 @@ import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.NewPipe;
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.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampChannelTabExtractor;
import java.io.IOException;
@ -23,8 +23,7 @@ public class BandcampChannelTabExtractorTest {
public static void setUp() throws IOException, ExtractionException {
NewPipe.init(DownloaderTestImpl.getInstance());
extractor = (BandcampChannelTabExtractor) Bandcamp
.getChannelTabExtractorFromUrl("https://toupie.bandcamp.com/releases",
ChannelTabHandler.Tab.Albums);
.getChannelTabExtractorFromId("2450875064", ChannelTabs.ALBUMS);
extractor.fetchPage();
}
@ -35,7 +34,7 @@ public class BandcampChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Albums, extractor.getTab());
assertEquals(ChannelTabs.ALBUMS, extractor.getTab());
}
@Test

View File

@ -6,7 +6,7 @@ import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.NewPipe;
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.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeAccountTabExtractor;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeChannelTabExtractor;
@ -24,8 +24,8 @@ public class PeertubeChannelTabExtractorTest {
public static void setUp() throws IOException, ExtractionException {
NewPipe.init(DownloaderTestImpl.getInstance());
extractor = (PeertubeChannelTabExtractor) PeerTube
.getChannelTabExtractorFromUrl("https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/videos",
ChannelTabHandler.Tab.Playlists);
.getChannelTabExtractorFromId("video-channels/lqdn_channel@video.lqdn.fr",
ChannelTabs.PLAYLISTS, "https://framatube.org");
extractor.fetchPage();
}
@ -36,7 +36,7 @@ public class PeertubeChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Playlists, extractor.getTab());
assertEquals(ChannelTabs.PLAYLISTS, extractor.getTab());
}
@Test
@ -62,8 +62,8 @@ public class PeertubeChannelTabExtractorTest {
public static void setUp() throws IOException, ExtractionException {
NewPipe.init(DownloaderTestImpl.getInstance());
extractor = (PeertubeAccountTabExtractor) PeerTube
.getChannelTabExtractorFromUrl("https://framatube.org/accounts/framasoft",
ChannelTabHandler.Tab.Channels);
.getChannelTabExtractorFromId("accounts/framasoft",
ChannelTabs.CHANNELS, "https://framatube.org");
extractor.fetchPage();
}
@ -74,7 +74,7 @@ public class PeertubeChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Channels, extractor.getTab());
assertEquals(ChannelTabs.CHANNELS, extractor.getTab());
}
@Test

View File

@ -6,7 +6,7 @@ import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.NewPipe;
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.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudChannelTabExtractor;
import java.io.IOException;
@ -24,8 +24,7 @@ public class SoundcloudChannelTabExtractorTest {
public static void setUp() throws IOException, ExtractionException {
NewPipe.init(DownloaderTestImpl.getInstance());
extractor = (SoundcloudChannelTabExtractor) SoundCloud
.getChannelTabExtractorFromUrl("https://soundcloud.com/trackaholic",
ChannelTabHandler.Tab.Playlists);
.getChannelTabExtractorFromId("323371733", ChannelTabs.PLAYLISTS);
extractor.fetchPage();
}
@ -36,7 +35,7 @@ public class SoundcloudChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Playlists, extractor.getTab());
assertEquals(ChannelTabs.PLAYLISTS, extractor.getTab());
}
@Test
@ -67,8 +66,7 @@ public class SoundcloudChannelTabExtractorTest {
public static void setUp() throws IOException, ExtractionException {
NewPipe.init(DownloaderTestImpl.getInstance());
extractor = (SoundcloudChannelTabExtractor) SoundCloud
.getChannelTabExtractorFromUrl("https://soundcloud.com/bigsean-1",
ChannelTabHandler.Tab.Albums);
.getChannelTabExtractorFromId("4803918", ChannelTabs.ALBUMS);
extractor.fetchPage();
}
@ -79,7 +77,7 @@ public class SoundcloudChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Albums, extractor.getTab());
assertEquals(ChannelTabs.ALBUMS, extractor.getTab());
}
@Test

View File

@ -6,7 +6,7 @@ import org.schabi.newpipe.downloader.DownloaderFactory;
import org.schabi.newpipe.extractor.NewPipe;
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.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeChannelTabExtractor;
import java.io.IOException;
@ -27,7 +27,7 @@ public class YouTubeChannelTabExtractorTest {
YoutubeTestsUtils.ensureStateless();
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "playlists"));
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId(
"UC2DjFE7Xf11URZqWBigcVOQ", ChannelTabHandler.Tab.Playlists);
"UC2DjFE7Xf11URZqWBigcVOQ", ChannelTabs.PLAYLISTS);
extractor.fetchPage();
}
@ -38,7 +38,7 @@ public class YouTubeChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Playlists, extractor.getTab());
assertEquals(ChannelTabs.PLAYLISTS, extractor.getTab());
}
@Test
@ -69,7 +69,7 @@ public class YouTubeChannelTabExtractorTest {
public static void setUp() throws IOException, ExtractionException {
YoutubeTestsUtils.ensureStateless();
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "channels"));
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId("UC2DjFE7Xf11URZqWBigcVOQ", ChannelTabHandler.Tab.Channels);
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId("UC2DjFE7Xf11URZqWBigcVOQ", ChannelTabs.CHANNELS);
extractor.fetchPage();
}
@ -80,7 +80,7 @@ public class YouTubeChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Channels, extractor.getTab());
assertEquals(ChannelTabs.CHANNELS, extractor.getTab());
}
@Test
@ -112,7 +112,7 @@ public class YouTubeChannelTabExtractorTest {
YoutubeTestsUtils.ensureStateless();
YoutubeParsingHelper.setVisitorData(YoutubeTestsUtils.VISITOR_DATA_NEW_CHANNEL_LAYOUT);
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "livestreams"));
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId("UCR-DXc1voovS8nhAvccRZhg", ChannelTabHandler.Tab.Livestreams);
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId("UCR-DXc1voovS8nhAvccRZhg", ChannelTabs.LIVE);
extractor.fetchPage();
}
@ -123,7 +123,7 @@ public class YouTubeChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Livestreams, extractor.getTab());
assertEquals(ChannelTabs.LIVE, extractor.getTab());
}
@Test
@ -133,7 +133,7 @@ public class YouTubeChannelTabExtractorTest {
@Test
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/live", extractor.getUrl());
assertEquals("https://www.youtube.com/channel/UCR-DXc1voovS8nhAvccRZhg/streams", extractor.getUrl());
}
@Test
@ -155,7 +155,7 @@ public class YouTubeChannelTabExtractorTest {
YoutubeTestsUtils.ensureStateless();
YoutubeParsingHelper.setVisitorData(YoutubeTestsUtils.VISITOR_DATA_NEW_CHANNEL_LAYOUT);
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "shorts"));
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId("UCh8gHdtzO2tXd593_bjErWg", ChannelTabHandler.Tab.Shorts);
extractor = (YoutubeChannelTabExtractor) YouTube.getChannelTabExtractorFromId("UCh8gHdtzO2tXd593_bjErWg", ChannelTabs.SHORTS);
extractor.fetchPage();
}
@ -166,7 +166,7 @@ public class YouTubeChannelTabExtractorTest {
@Test
public void testTab() {
assertEquals(ChannelTabHandler.Tab.Shorts, extractor.getTab());
assertEquals(ChannelTabs.SHORTS, extractor.getTab());
}
@Test

View File

@ -12,7 +12,7 @@ import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
import org.schabi.newpipe.extractor.linkhandler.ChannelTabs;
import org.schabi.newpipe.extractor.services.BaseChannelExtractorTest;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeChannelExtractor;
@ -240,9 +240,10 @@ public class YoutubeChannelExtractorTest {
@Test
public void testTabs() throws Exception {
Set<ChannelTabHandler.Tab> tabs = extractor.getTabs().stream().map(ChannelTabHandler::getTab).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabHandler.Tab.Playlists));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Channels));
Set<String> tabs = extractor.getTabs().stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0)).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabs.PLAYLISTS));
assertTrue(tabs.contains(ChannelTabs.CHANNELS));
}
}
@ -342,9 +343,10 @@ public class YoutubeChannelExtractorTest {
@Test
public void testTabs() throws Exception {
Set<ChannelTabHandler.Tab> tabs = extractor.getTabs().stream().map(ChannelTabHandler::getTab).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabHandler.Tab.Playlists));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Channels));
Set<String> tabs = extractor.getTabs().stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0)).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabs.PLAYLISTS));
assertTrue(tabs.contains(ChannelTabs.CHANNELS));
}
}
@ -446,9 +448,10 @@ public class YoutubeChannelExtractorTest {
@Test
public void testTabs() throws Exception {
Set<ChannelTabHandler.Tab> tabs = extractor.getTabs().stream().map(ChannelTabHandler::getTab).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabHandler.Tab.Playlists));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Channels));
Set<String> tabs = extractor.getTabs().stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0)).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabs.PLAYLISTS));
assertTrue(tabs.contains(ChannelTabs.CHANNELS));
}
}
@ -567,9 +570,10 @@ public class YoutubeChannelExtractorTest {
@Test
public void testTabs() throws Exception {
Set<ChannelTabHandler.Tab> tabs = extractor.getTabs().stream().map(ChannelTabHandler::getTab).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabHandler.Tab.Playlists));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Channels));
Set<String> tabs = extractor.getTabs().stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0)).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabs.PLAYLISTS));
assertTrue(tabs.contains(ChannelTabs.CHANNELS));
}
}
@ -674,9 +678,10 @@ public class YoutubeChannelExtractorTest {
@Test
public void testTabs() throws Exception {
Set<ChannelTabHandler.Tab> tabs = extractor.getTabs().stream().map(ChannelTabHandler::getTab).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabHandler.Tab.Playlists));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Channels));
Set<String> tabs = extractor.getTabs().stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0)).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabs.PLAYLISTS));
assertTrue(tabs.contains(ChannelTabs.CHANNELS));
}
}
@ -737,7 +742,7 @@ public class YoutubeChannelExtractorTest {
/**
* Test the extraction of the new channel tabs
*/
public static class ChannelTabs {
public static class ChannelWithTabs {
private static YoutubeChannelExtractor extractor;
@BeforeAll
@ -781,11 +786,12 @@ public class YoutubeChannelExtractorTest {
@Test
public void testTabs() throws Exception {
Set<ChannelTabHandler.Tab> tabs = extractor.getTabs().stream().map(ChannelTabHandler::getTab).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabHandler.Tab.Shorts));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Livestreams));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Playlists));
assertTrue(tabs.contains(ChannelTabHandler.Tab.Channels));
Set<String> tabs = extractor.getTabs().stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0)).collect(Collectors.toSet());
assertTrue(tabs.contains(ChannelTabs.SHORTS));
assertTrue(tabs.contains(ChannelTabs.LIVE));
assertTrue(tabs.contains(ChannelTabs.PLAYLISTS));
assertTrue(tabs.contains(ChannelTabs.CHANNELS));
}
}
}