merged upstream/dev

This commit is contained in:
Ritvik Saraf 2019-03-08 03:09:05 +05:30
commit 22dac63698
55 changed files with 1775 additions and 253 deletions

View File

@ -19,6 +19,7 @@ The following sites are currently supported:
- YouTube
- SoundCloud
- MediaCCC
## License

View File

View File

@ -27,7 +27,7 @@ public abstract class Info implements Serializable {
*
* @see Extractor#getOriginalUrl()
*/
private final String originalUrl;
private String originalUrl;
private final String name;
private final List<Throwable> errors = new ArrayList<>();
@ -62,6 +62,12 @@ public abstract class Info implements Serializable {
return getClass().getSimpleName() + "[url=\"" + url + "\"" + ifDifferentString + ", name=\"" + name + "\"]";
}
// if you use an api and want to handle the website url
// overriding original url is essential
public void setOriginalUrl(String url) {
originalUrl = url;
}
public int getServiceId() {
return serviceId;
}

View File

@ -30,20 +30,21 @@ public enum MediaFormat {
//video and audio combined formats
// id name suffix mime type
MPEG_4 (0x0, "MPEG-4", "mp4", "video/mp4"),
v3GPP (0x1, "3GPP", "3gp", "video/3gpp"),
WEBM (0x2, "WebM", "webm", "video/webm"),
v3GPP (0x10, "3GPP", "3gp", "video/3gpp"),
WEBM (0x20, "WebM", "webm", "video/webm"),
// audio formats
M4A (0x3, "m4a", "m4a", "audio/mp4"),
WEBMA (0x4, "WebM", "webm", "audio/webm"),
MP3 (0x5, "MP3", "mp3", "audio/mpeg"),
OPUS (0x6, "opus", "opus", "audio/opus"),
M4A (0x100, "m4a", "m4a", "audio/mp4"),
WEBMA (0x200, "WebM", "webm", "audio/webm"),
MP3 (0x300, "MP3", "mp3", "audio/mpeg"),
OPUS (0x400, "opus", "opus", "audio/opus"),
OGG (0x500, "ogg", "ogg", "audio/ogg"),
// subtitles formats
VTT (0x7, "WebVTT", "vtt", "text/vtt"),
TTML (0x8, "Timed Text Markup Language", "ttml", "application/ttml+xml"),
TRANSCRIPT1 (0x9, "TranScript v1", "srv1", "text/xml"),
TRANSCRIPT2 (0xA, "TranScript v2", "srv2", "text/xml"),
TRANSCRIPT3 (0xB, "TranScript v3", "srv3", "text/xml"),
SRT (0xC, "SubRip file format", "srt", "text/srt");
VTT (0x1000, "WebVTT", "vtt", "text/vtt"),
TTML (0x2000, "Timed Text Markup Language", "ttml", "application/ttml+xml"),
TRANSCRIPT1 (0x3000, "TranScript v1", "srv1", "text/xml"),
TRANSCRIPT2 (0x4000, "TranScript v2", "srv2", "text/xml"),
TRANSCRIPT3 (0x5000, "TranScript v3", "srv3", "text/xml"),
SRT (0x6000, "SubRip file format", "srt", "text/srt");
public final int id;
public final String name;

View File

@ -1,14 +1,14 @@
package org.schabi.newpipe.extractor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.schabi.newpipe.extractor.services.media_ccc.MediaCCCService;
import org.schabi.newpipe.extractor.services.peertube.PeertubeService;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudService;
import org.schabi.newpipe.extractor.services.youtube.YoutubeService;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
/*
* Copyright (C) Christian Schabesberger 2018 <chris.schabesberger@mailbox.org>
* ServiceList.java is part of NewPipe.
@ -38,17 +38,18 @@ public final class ServiceList {
public static final YoutubeService YouTube;
public static final SoundcloudService SoundCloud;
public static final PeertubeService PeerTube;
public static final MediaCCCService MediaCCC;
/**
* When creating a new service, put this service in the end of this list,
* and give it the next free id.
*/
private static final List<StreamingService> SERVICES = unmodifiableList(
asList(
private static final List<StreamingService> SERVICES = Collections.unmodifiableList(
Arrays.asList(
YouTube = new YoutubeService(0),
SoundCloud = new SoundcloudService(1),
PeerTube = new PeertubeService(2)
PeerTube = new PeertubeService(2),
MediaCCC = new MediaCCCService(3)
));
/**

View File

@ -71,7 +71,7 @@ public abstract class StreamingService {
}
public enum MediaCapability {
AUDIO, VIDEO, LIVE
AUDIO, VIDEO, LIVE, COMMENTS
}
}
@ -301,12 +301,8 @@ public abstract class StreamingService {
return getCommentsExtractor(llhf.fromUrl(url), NewPipe.getPreferredLocalization());
}
public abstract boolean isCommentsSupported();
public abstract String getBaseUrl();
/**
* Figures out where the link is pointing to (a channel, a video, a playlist, etc.)
* @param url the url on which it should be decided of which link type it is
@ -318,11 +314,11 @@ public abstract class StreamingService {
LinkHandlerFactory cH = getChannelLHFactory();
LinkHandlerFactory pH = getPlaylistLHFactory();
if (sH.acceptUrl(url)) {
if (sH != null && sH.acceptUrl(url)) {
return LinkType.STREAM;
} else if (cH.acceptUrl(url)) {
} else if (cH != null && cH.acceptUrl(url)) {
return LinkType.CHANNEL;
} else if (pH.acceptUrl(url)) {
} else if (pH != null && pH.acceptUrl(url)) {
return LinkType.PLAYLIST;
} else {
return LinkType.NONE;

View File

@ -38,5 +38,4 @@ public abstract class ChannelExtractor extends ListExtractor<StreamInfoItem> {
public abstract String getFeedUrl() throws ParsingException;
public abstract long getSubscriberCount() throws ParsingException;
public abstract String getDescription() throws ParsingException;
public abstract String[] getDonationLinks() throws ParsingException;
}

View File

@ -61,7 +61,11 @@ public class ChannelInfo extends ListInfo<StreamInfoItem> {
extractor.getLinkHandler(),
extractor.getName());
try {
info.setOriginalUrl(extractor.getOriginalUrl());
} catch (Exception e) {
info.addError(e);
}
try {
info.setAvatarUrl(extractor.getAvatarUrl());
} catch (Exception e) {
@ -92,11 +96,6 @@ public class ChannelInfo extends ListInfo<StreamInfoItem> {
} catch (Exception e) {
info.addError(e);
}
try {
info.setDonationLinks(extractor.getDonationLinks());
} catch (Exception e) {
info.addError(e);
}
return info;
}

View File

@ -20,6 +20,7 @@ package org.schabi.newpipe.extractor.kiosk;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
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;
@ -29,7 +30,7 @@ import org.schabi.newpipe.extractor.utils.Localization;
import javax.annotation.Nonnull;
public abstract class KioskExtractor extends ListExtractor<StreamInfoItem> {
public abstract class KioskExtractor<T extends InfoItem> extends ListExtractor<T> {
private final String id;
public KioskExtractor(StreamingService streamingService,

View File

@ -49,6 +49,11 @@ public class KioskList {
defaultKiosk = kioskType;
}
public KioskExtractor getDefaultKioskExtractor()
throws ExtractionException, IOException {
return getDefaultKioskExtractor("");
}
public KioskExtractor getDefaultKioskExtractor(String nextPageUrl)
throws ExtractionException, IOException {
return getDefaultKioskExtractor(nextPageUrl, NewPipe.getPreferredLocalization());

View File

@ -47,6 +47,11 @@ public class PlaylistInfo extends ListInfo<StreamInfoItem> {
extractor.getLinkHandler(),
extractor.getName());
try {
info.setOriginalUrl(extractor.getOriginalUrl());
} catch (Exception e) {
info.addError(e);
}
try {
info.setStreamCount(extractor.getStreamCount());
} catch (Exception e) {

View File

@ -37,6 +37,11 @@ public class SearchInfo extends ListInfo<InfoItem> {
extractor.getLinkHandler(),
extractor.getSearchString());
try {
info.setOriginalUrl(extractor.getOriginalUrl());
} catch (Exception e) {
info.addError(e);
}
try {
info.searchSuggestion = extractor.getSearchSuggestion();
} catch (Exception e) {

View File

@ -0,0 +1,131 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import static java.util.Arrays.asList;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
import java.io.IOException;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.SuggestionExtractor;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCConferenceExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCConferenceKiosk;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCSearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCStreamExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferencesListLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
public class MediaCCCService extends StreamingService {
public MediaCCCService(int id) {
super(id, "MediaCCC", asList(AUDIO, VIDEO));
}
@Override
public SearchExtractor getSearchExtractor(SearchQueryHandler query, Localization localization) {
return new MediaCCCSearchExtractor(this, query, localization);
}
@Override
public LinkHandlerFactory getStreamLHFactory() {
return new MediaCCCStreamLinkHandlerFactory();
}
@Override
public ListLinkHandlerFactory getChannelLHFactory() {
return new MediaCCCConferenceLinkHandlerFactory();
}
@Override
public ListLinkHandlerFactory getPlaylistLHFactory() {
return null;
}
@Override
public SearchQueryHandlerFactory getSearchQHFactory() {
return new MediaCCCSearchQueryHandlerFactory();
}
@Override
public StreamExtractor getStreamExtractor(LinkHandler linkHandler, Localization localization) {
return new MediaCCCStreamExtractor(this, linkHandler, localization);
}
@Override
public ChannelExtractor getChannelExtractor(ListLinkHandler linkHandler, Localization localization) {
return new MediaCCCConferenceExtractor(this, linkHandler, localization);
}
@Override
public PlaylistExtractor getPlaylistExtractor(ListLinkHandler linkHandler, Localization localization) {
return null;
}
@Override
public SuggestionExtractor getSuggestionExtractor(Localization localization) {
return null;
}
@Override
public KioskList getKioskList() throws ExtractionException {
KioskList list = new KioskList(getServiceId());
// add kiosks here e.g.:
try {
list.addKioskEntry(new KioskList.KioskExtractorFactory() {
@Override
public KioskExtractor createNewKiosk(StreamingService streamingService,
String url,
String kioskId,
Localization localization) throws ExtractionException, IOException {
return new MediaCCCConferenceKiosk(MediaCCCService.this,
new MediaCCCConferencesListLinkHandlerFactory().fromUrl(url), kioskId, localization);
}
}, new MediaCCCConferencesListLinkHandlerFactory(), "conferences");
list.setDefaultKiosk("conferences");
} catch (Exception e) {
throw new ExtractionException(e);
}
return list;
}
@Override
public SubscriptionExtractor getSubscriptionExtractor() {
return null;
}
@Override
public ListLinkHandlerFactory getCommentsLHFactory() {
return null;
}
@Override
public CommentsExtractor getCommentsExtractor(ListLinkHandler linkHandler, Localization localization)
throws ExtractionException {
return null;
}
@Override
public String getBaseUrl() {
return "https://media.ccc.de";
}
}

View File

@ -0,0 +1,94 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.utils.Localization;
import javax.annotation.Nonnull;
import java.io.IOException;
public class MediaCCCConferenceExtractor extends ChannelExtractor {
private JsonObject conferenceData;
public MediaCCCConferenceExtractor(StreamingService service, ListLinkHandler linkHandler, Localization localization) {
super(service, linkHandler, localization);
}
@Override
public String getAvatarUrl() throws ParsingException {
return conferenceData.getString("logo_url");
}
@Override
public String getBannerUrl() throws ParsingException {
return conferenceData.getString("logo_url");
}
@Override
public String getFeedUrl() throws ParsingException {
return null;
}
@Override
public long getSubscriberCount() throws ParsingException {
return -1;
}
@Override
public String getDescription() throws ParsingException {
return null;
}
@Nonnull
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException {
StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
JsonArray events = conferenceData.getArray("events");
for(int i = 0; i < events.size(); i++) {
collector.commit(new MediaCCCStreamInfoItemExtractor(events.getObject(i)));
}
return new InfoItemsPage<>(collector, null);
}
@Override
public String getNextPageUrl() throws IOException, ExtractionException {
return null;
}
@Override
public InfoItemsPage<StreamInfoItem> getPage(String pageUrl) throws IOException, ExtractionException {
return null;
}
@Override
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
try {
conferenceData = JsonParser.object().from(downloader.download(getUrl()));
} catch (JsonParserException jpe) {
throw new ExtractionException("Could not parse json returnd by url: " + getUrl());
}
}
@Nonnull
@Override
public String getName() throws ParsingException {
return conferenceData.getString("title");
}
@Override
public String getOriginalUrl() throws ParsingException {
return "https://media.ccc.de/c/" + conferenceData.getString("acronym");
}
}

View File

@ -0,0 +1,69 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItemsCollector;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCConferenceInfoItemExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
import javax.annotation.Nonnull;
import java.io.IOException;
public class MediaCCCConferenceKiosk extends KioskExtractor<ChannelInfoItem> {
private JsonObject doc;
public MediaCCCConferenceKiosk(StreamingService streamingService,
ListLinkHandler linkHandler,
String kioskId,
Localization localization) {
super(streamingService, linkHandler, kioskId, localization);
}
@Nonnull
@Override
public InfoItemsPage<ChannelInfoItem> getInitialPage() throws IOException, ExtractionException {
JsonArray conferences = doc.getArray("conferences");
ChannelInfoItemsCollector collector = new ChannelInfoItemsCollector(getServiceId());
for(int i = 0; i < conferences.size(); i++) {
collector.commit(new MediaCCCConferenceInfoItemExtractor(conferences.getObject(i)));
}
return new InfoItemsPage<>(collector, "");
}
@Override
public String getNextPageUrl() throws IOException, ExtractionException {
return "";
}
@Override
public InfoItemsPage<ChannelInfoItem> getPage(String pageUrl) throws IOException, ExtractionException {
return InfoItemsPage.emptyPage();
}
@Override
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
String site = downloader.download(getLinkHandler().getUrl());
try {
doc = JsonParser.object().from(site);
} catch (JsonParserException jpe) {
throw new ExtractionException("Could not parse json.", jpe);
}
}
@Nonnull
@Override
public String getName() throws ParsingException {
return doc.getString("Conferences");
}
}

View File

@ -0,0 +1,144 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferencesListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Localization;
import static org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory.CONFERENCES;
import static org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory.EVENTS;
import static org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory.ALL;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.List;
public class MediaCCCSearchExtractor extends SearchExtractor {
private JsonObject doc;
private MediaCCCConferenceKiosk conferenceKiosk;
public MediaCCCSearchExtractor(StreamingService service, SearchQueryHandler linkHandler, Localization localization) {
super(service, linkHandler, localization);
try {
conferenceKiosk = new MediaCCCConferenceKiosk(service,
new MediaCCCConferencesListLinkHandlerFactory().fromId("conferences"),
"conferences",
localization);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String getSearchSuggestion() throws ParsingException {
return null;
}
@Nonnull
@Override
public InfoItemsPage<InfoItem> getInitialPage() throws IOException, ExtractionException {
InfoItemsSearchCollector searchItems = getInfoItemSearchCollector();
if(getLinkHandler().getContentFilters().contains(CONFERENCES)
|| getLinkHandler().getContentFilters().contains(ALL)
|| getLinkHandler().getContentFilters().isEmpty()) {
searchConferences(getSearchString(),
conferenceKiosk.getInitialPage().getItems(),
searchItems);
}
if(getLinkHandler().getContentFilters().contains(EVENTS)
|| getLinkHandler().getContentFilters().contains(ALL)
|| getLinkHandler().getContentFilters().isEmpty()) {
JsonArray events = doc.getArray("events");
for (int i = 0; i < events.size(); i++) {
searchItems.commit(new MediaCCCStreamInfoItemExtractor(
events.getObject(i)));
}
}
return new InfoItemsPage<>(searchItems, null);
}
@Override
public String getNextPageUrl() throws IOException, ExtractionException {
return "";
}
@Override
public InfoItemsPage<InfoItem> getPage(String pageUrl) throws IOException, ExtractionException {
return InfoItemsPage.emptyPage();
}
@Override
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
if(getLinkHandler().getContentFilters().contains(EVENTS)
|| getLinkHandler().getContentFilters().contains(ALL)
|| getLinkHandler().getContentFilters().isEmpty()) {
final String site;
final String url = getUrl();
site = downloader.download(url, getLocalization());
try {
doc = JsonParser.object().from(site);
} catch (JsonParserException jpe) {
throw new ExtractionException("Could not parse json.", jpe);
}
}
if(getLinkHandler().getContentFilters().contains(CONFERENCES)
|| getLinkHandler().getContentFilters().contains(ALL)
|| getLinkHandler().getContentFilters().isEmpty())
conferenceKiosk.fetchPage();
}
private void searchConferences(String searchString,
List<ChannelInfoItem> channelItems,
InfoItemsSearchCollector collector) {
for(final ChannelInfoItem item : channelItems) {
if(item.getName().toUpperCase().contains(
searchString.toUpperCase())) {
collector.commit(new ChannelInfoItemExtractor() {
@Override
public String getDescription() throws ParsingException {
return item.getDescription();
}
@Override
public long getSubscriberCount() throws ParsingException {
return item.getSubscriberCount();
}
@Override
public long getStreamCount() throws ParsingException {
return item.getStreamCount();
}
@Override
public String getName() throws ParsingException {
return item.getName();
}
@Override
public String getUrl() throws ParsingException {
return item.getUrl();
}
@Override
public String getThumbnailUrl() throws ParsingException {
return item.getThumbnailUrl();
}
});
}
}
}
}

View File

@ -0,0 +1,222 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonParser;
import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.stream.*;
import org.schabi.newpipe.extractor.utils.Localization;
import org.schabi.newpipe.extractor.utils.Parser;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MediaCCCStreamExtractor extends StreamExtractor {
private JsonObject data;
private JsonObject conferenceData;
public MediaCCCStreamExtractor(StreamingService service, LinkHandler linkHandler, Localization localization) {
super(service, linkHandler, localization);
}
@Nonnull
@Override
public String getUploadDate() throws ParsingException {
return data.getString("release_date");
}
@Nonnull
@Override
public String getThumbnailUrl() throws ParsingException {
return data.getString("thumb_url");
}
@Nonnull
@Override
public String getDescription() throws ParsingException {
return data.getString("description");
}
@Override
public int getAgeLimit() throws ParsingException {
return 0;
}
@Override
public long getLength() throws ParsingException {
return data.getInt("length");
}
@Override
public long getTimeStamp() throws ParsingException {
return 0;
}
@Override
public long getViewCount() throws ParsingException {
return data.getInt("view_count");
}
@Override
public long getLikeCount() throws ParsingException {
return -1;
}
@Override
public long getDislikeCount() throws ParsingException {
return -1;
}
@Nonnull
@Override
public String getUploaderUrl() throws ParsingException {
return data.getString("conference_url");
}
@Nonnull
@Override
public String getUploaderName() throws ParsingException {
return data.getString("conference_url")
.replace("https://api.media.ccc.de/public/conferences/", "");
}
@Nonnull
@Override
public String getUploaderAvatarUrl() throws ParsingException {
return conferenceData.getString("logo_url");
}
@Nonnull
@Override
public String getDashMpdUrl() throws ParsingException {
return null;
}
@Nonnull
@Override
public String getHlsUrl() throws ParsingException {
return null;
}
@Override
public List<AudioStream> getAudioStreams() throws IOException, ExtractionException {
final JsonArray recordings = data.getArray("recordings");
final List<AudioStream> audioStreams = new ArrayList<>();
for(int i = 0; i < recordings.size(); i++) {
final JsonObject recording = recordings.getObject(i);
final String mimeType = recording.getString("mime_type");
if(mimeType.startsWith("audio")) {
//first we need to resolve the actual video data from CDN
final MediaFormat mediaFormat;
if(mimeType.endsWith("opus")) {
mediaFormat = MediaFormat.OPUS;
} else if(mimeType.endsWith("mpeg")) {
mediaFormat = MediaFormat.MP3;
} else if(mimeType.endsWith("ogg")){
mediaFormat = MediaFormat.OGG;
} else {
throw new ExtractionException("Unknown media format: " + mimeType);
}
audioStreams.add(new AudioStream(recording.getString("recording_url"), mediaFormat, -1));
}
}
return audioStreams;
}
@Override
public List<VideoStream> getVideoStreams() throws IOException, ExtractionException {
final JsonArray recordings = data.getArray("recordings");
final List<VideoStream> videoStreams = new ArrayList<>();
for(int i = 0; i < recordings.size(); i++) {
final JsonObject recording = recordings.getObject(i);
final String mimeType = recording.getString("mime_type");
if(mimeType.startsWith("video")) {
//first we need to resolve the actual video data from CDN
final MediaFormat mediaFormat;
if(mimeType.endsWith("webm")) {
mediaFormat = MediaFormat.WEBM;
} else if(mimeType.endsWith("mp4")) {
mediaFormat = MediaFormat.MPEG_4;
} else {
throw new ExtractionException("Unknown media format: " + mimeType);
}
videoStreams.add(new VideoStream(recording.getString("recording_url"),
mediaFormat, recording.getInt("height") + "p"));
}
}
return videoStreams;
}
@Override
public List<VideoStream> getVideoOnlyStreams() throws IOException, ExtractionException {
return null;
}
@Nonnull
@Override
public List<SubtitlesStream> getSubtitlesDefault() throws IOException, ExtractionException {
return null;
}
@Nonnull
@Override
public List<SubtitlesStream> getSubtitles(MediaFormat format) throws IOException, ExtractionException {
return null;
}
@Override
public StreamType getStreamType() throws ParsingException {
return StreamType.VIDEO_STREAM;
}
@Override
public StreamInfoItem getNextStream() throws IOException, ExtractionException {
return null;
}
@Override
public StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException {
return new StreamInfoItemsCollector(getServiceId());
}
@Override
public String getErrorMessage() {
return null;
}
@Override
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
try {
data = JsonParser.object().from(
downloader.download(getLinkHandler().getUrl()));
conferenceData = JsonParser.object()
.from(downloader.download(getUploaderUrl()));
} catch (JsonParserException jpe) {
throw new ExtractionException("Could not parse json returned by url: " + getLinkHandler().getUrl(), jpe);
}
}
@Nonnull
@Override
public String getName() throws ParsingException {
return data.getString("title");
}
@Override
public String getOriginalUrl() throws ParsingException {
return data.getString("frontend_link");
}
}

View File

@ -0,0 +1,21 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors;
import org.schabi.newpipe.extractor.SuggestionExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.utils.Localization;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MediaCCCSuggestionExtractor extends SuggestionExtractor {
public MediaCCCSuggestionExtractor(int serviceId, Localization localization) {
super(serviceId, localization);
}
@Override
public List<String> suggestionList(String query) throws IOException, ExtractionException {
return new ArrayList<>(0);
}
}

View File

@ -0,0 +1,44 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems;
import com.grack.nanojson.JsonObject;
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
public class MediaCCCConferenceInfoItemExtractor implements ChannelInfoItemExtractor {
JsonObject conference;
public MediaCCCConferenceInfoItemExtractor(JsonObject conference) {
this.conference = conference;
}
@Override
public String getDescription() throws ParsingException {
return "";
}
@Override
public long getSubscriberCount() throws ParsingException {
return -1;
}
@Override
public long getStreamCount() throws ParsingException {
return -1;
}
@Override
public String getName() throws ParsingException {
return conference.getString("title");
}
@Override
public String getUrl() throws ParsingException {
return conference.getString("url");
}
@Override
public String getThumbnailUrl() throws ParsingException {
return conference.getString("logo_url");
}
}

View File

@ -0,0 +1,67 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems;
import com.grack.nanojson.JsonObject;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamType;
public class MediaCCCStreamInfoItemExtractor implements StreamInfoItemExtractor {
JsonObject event;
public MediaCCCStreamInfoItemExtractor(JsonObject event) {
this.event = event;
}
@Override
public StreamType getStreamType() throws ParsingException {
return StreamType.VIDEO_STREAM;
}
@Override
public boolean isAd() throws ParsingException {
return false;
}
@Override
public long getDuration() throws ParsingException {
return event.getInt("length");
}
@Override
public long getViewCount() throws ParsingException {
return event.getInt("view_count");
}
@Override
public String getUploaderName() throws ParsingException {
return event.getString("conference_url")
.replace("https://api.media.ccc.de/public/conferences/", "");
}
@Override
public String getUploaderUrl() throws ParsingException {
return event.getString("conference_url");
}
@Override
public String getUploadDate() throws ParsingException {
return event.getString("release_date");
}
@Override
public String getName() throws ParsingException {
return event.getString("title");
}
@Override
public String getUrl() throws ParsingException {
return "https://api.media.ccc.de/public/events/" +
event.getString("guid");
}
@Override
public String getThumbnailUrl() throws ParsingException {
return event.getString("thumb_url");
}
}

View File

@ -0,0 +1,32 @@
package org.schabi.newpipe.extractor.services.media_ccc.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Parser;
import java.util.List;
public class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory {
@Override
public String getUrl(String id, List<String> contentFilter, String sortFilter) throws ParsingException {
return "https://api.media.ccc.de/public/conferences/" + id;
}
@Override
public String getId(String url) throws ParsingException {
if(url.startsWith("https://api.media.ccc.de/public/conferences/")) {
return url.replace("https://api.media.ccc.de/public/conferences/", "");
} else if(url.startsWith("https://media.ccc.de/c/")) {
return Parser.matchGroup1("https://media.ccc.de/c/([^?#]*)", url);
} else {
throw new ParsingException("Could not get id from url: " + url);
}
}
@Override
public boolean onAcceptUrl(String url) throws ParsingException {
return url.startsWith("https://api.media.ccc.de/public/conferences/")
|| url.startsWith("https://media.ccc.de/c/");
}
}

View File

@ -0,0 +1,25 @@
package org.schabi.newpipe.extractor.services.media_ccc.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.List;
public class MediaCCCConferencesListLinkHandlerFactory extends ListLinkHandlerFactory {
@Override
public String getId(String url) throws ParsingException {
return "conferences";
}
@Override
public String getUrl(String id, List<String> contentFilter, String sortFilter) throws ParsingException {
return "https://api.media.ccc.de/public/conferences";
}
@Override
public boolean onAcceptUrl(String url) throws ParsingException {
return url.equals("https://media.ccc.de/b/conferences")
|| url.equals("https://api.media.ccc.de/public/conferences");
}
}

View File

@ -0,0 +1,38 @@
package org.schabi.newpipe.extractor.services.media_ccc.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
public static final String ALL = "all";
public static final String CONFERENCES = "conferences";
public static final String EVENTS = "events";
@Override
public String[] getAvailableContentFilter() {
return new String[] {
ALL,
CONFERENCES,
EVENTS
};
}
@Override
public String[] getAvailableSortFilter() {
return new String[0];
}
@Override
public String getUrl(String querry, List<String> contentFilter, String sortFilter) throws ParsingException {
try {
return "https://api.media.ccc.de/public/events/search?q=" + URLEncoder.encode(querry, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new ParsingException("Could not create search string with querry: " + querry, e);
}
}
}

View File

@ -0,0 +1,27 @@
package org.schabi.newpipe.extractor.services.media_ccc.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory {
@Override
public String getId(String url) throws ParsingException {
if(url.startsWith("https://api.media.ccc.de/public/events/") &&
!url.contains("?q=")) {
return url.replace("https://api.media.ccc.de/public/events/", "");
}
throw new ParsingException("Could not get id from url: " + url);
}
@Override
public String getUrl(String id) throws ParsingException {
return "https://api.media.ccc.de/public/events/" + id;
}
@Override
public boolean onAcceptUrl(String url) throws ParsingException {
return url.startsWith("https://api.media.ccc.de/public/events/") &&
!url.contains("?q=");
}
}

View File

@ -1,6 +1,7 @@
package org.schabi.newpipe.extractor.services.peertube;
import static java.util.Collections.singletonList;
import static java.util.Arrays.asList;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
import java.io.IOException;
@ -47,7 +48,7 @@ public class PeertubeService extends StreamingService {
}
public PeertubeService(int id, PeertubeInstance instance) {
super(id, instance.getName(), singletonList(VIDEO));
super(id, instance.getName(), asList(VIDEO, COMMENTS));
this.instance = instance;
}
@ -122,11 +123,6 @@ public class PeertubeService extends StreamingService {
return new PeertubeCommentsExtractor(this, linkHandler, localization);
}
@Override
public boolean isCommentsSupported() {
return true;
}
@Override
public String getBaseUrl() {
return instance.getUrl();

View File

@ -75,11 +75,6 @@ public class PeertubeChannelExtractor extends ChannelExtractor {
}
}
@Override
public String[] getDonationLinks() throws ParsingException {
return new String[0];
}
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException {
super.fetchPage();

View File

@ -127,9 +127,4 @@ public class SoundcloudChannelExtractor extends ChannelExtractor {
return new InfoItemsPage<>(collector, nextPageUrl);
}
@Override
public String[] getDonationLinks() {
return new String[0];
}
}

View File

@ -14,7 +14,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class SoundcloudChartsExtractor extends KioskExtractor {
public class SoundcloudChartsExtractor extends KioskExtractor<StreamInfoItem> {
private StreamInfoItemsCollector collector = null;
private String nextPageUrl = null;

View File

@ -1,21 +1,27 @@
package org.schabi.newpipe.extractor.services.soundcloud;
import org.schabi.newpipe.extractor.*;
import org.schabi.newpipe.extractor.linkhandler.*;
import static java.util.Collections.singletonList;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.SuggestionExtractor;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
import static java.util.Collections.singletonList;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
public class SoundcloudService extends StreamingService {
public SoundcloudService(int id) {
@ -113,11 +119,6 @@ public class SoundcloudService extends StreamingService {
return null;
}
@Override
public boolean isCommentsSupported() {
return false;
}
@Override
public String getBaseUrl() {
return "https://soundcloud.com";

View File

@ -1,5 +1,11 @@
package org.schabi.newpipe.extractor.services.youtube;
import static java.util.Arrays.asList;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.LIVE;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.SuggestionExtractor;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
@ -33,11 +39,6 @@ import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
import static java.util.Arrays.asList;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.LIVE;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
/*
* Created by Christian Schabesberger on 23.08.15.
*
@ -61,7 +62,7 @@ import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCap
public class YoutubeService extends StreamingService {
public YoutubeService(int id) {
super(id, "YouTube", asList(AUDIO, VIDEO, LIVE));
super(id, "YouTube", asList(AUDIO, VIDEO, LIVE, COMMENTS));
}
@Override
@ -150,11 +151,6 @@ public class YoutubeService extends StreamingService {
return new YoutubeCommentsExtractor(this, urlIdHandler, localization);
}
@Override
public boolean isCommentsSupported() {
return true;
}
@Override
public String getBaseUrl() {
return "https://youtube.com";

View File

@ -189,29 +189,6 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return new InfoItemsPage<>(collector, getNextPageUrlFromAjaxPage(ajaxJson, pageUrl));
}
@Override
public String[] getDonationLinks() throws ParsingException {
try {
ArrayList<String> links = new ArrayList<>();
Element linkHolder = doc.select("div[id=\"header-links\"]").first();
if(linkHolder == null) {
// this occures if no links are embeded into the channel
return new String[0];
}
for(Element a : linkHolder.select("a")) {
String link = a.attr("abs:href");
if(DonationLinkHelper.getDonatoinServiceByLink(link) != DonationLinkHelper.DonationService.NO_DONATION) {
links.add(link);
}
}
String[] retLinks = new String[links.size()];
retLinks = links.toArray(retLinks);
return retLinks;
} catch (Exception e) {
throw new ParsingException("Could not get donation links", e);
}
}
private String getNextPageUrlFromAjaxPage(final JsonObject ajaxJson, final String pageUrl)
throws ParsingException {
String loadMoreHtmlDataRaw = ajaxJson.getString("load_more_widget_html");

View File

@ -107,11 +107,11 @@ public class YoutubeCommentsExtractor extends CommentsExtractor {
throw new ParsingException("Could not parse json data for comments", e);
}
CommentsInfoItemsCollector collector = new CommentsInfoItemsCollector(getServiceId());
collectCommentsFrom(collector, ajaxJson, pageUrl);
collectCommentsFrom(collector, ajaxJson);
return new InfoItemsPage<>(collector, getNextPageUrl(ajaxJson));
}
private void collectCommentsFrom(CommentsInfoItemsCollector collector, JsonObject ajaxJson, String pageUrl) throws ParsingException {
private void collectCommentsFrom(CommentsInfoItemsCollector collector, JsonObject ajaxJson) throws ParsingException {
JsonArray contents;
try {
@ -130,7 +130,7 @@ public class YoutubeCommentsExtractor extends CommentsExtractor {
for(Object c: comments) {
if(c instanceof JsonObject) {
CommentsInfoItemExtractor extractor = new YoutubeCommentsInfoItemExtractor((JsonObject) c, pageUrl);
CommentsInfoItemExtractor extractor = new YoutubeCommentsInfoItemExtractor((JsonObject) c, getUrl());
collector.commit(extractor);
}
}

View File

@ -3,6 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
import org.schabi.newpipe.extractor.comments.CommentsInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Utils;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
@ -62,7 +63,9 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract
@Override
public String getCommentText() throws ParsingException {
try {
return YoutubeCommentsExtractor.getYoutubeText(JsonUtils.getObject(json, "contentText"));
String commentText = YoutubeCommentsExtractor.getYoutubeText(JsonUtils.getObject(json, "contentText"));
// youtube adds U+FEFF in some comments. eg. https://www.youtube.com/watch?v=Nj4F63E59io<feff>
return Utils.removeUTF8BOM(commentText);
} catch (Exception e) {
throw new ParsingException("Could not get comment text", e);
}
@ -99,7 +102,7 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract
@Override
public String getAuthorEndpoint() throws ParsingException {
try {
return "https://youtube.com" + JsonUtils.getString(json, "authorEndpoint.browseEndpoint.canonicalBaseUrl");
return "https://youtube.com/channel/" + JsonUtils.getString(json, "authorEndpoint.browseEndpoint.browseId");
} catch (Exception e) {
throw new ParsingException("Could not get author endpoint", e);
}

View File

@ -386,11 +386,16 @@ public class YoutubeStreamExtractor extends StreamExtractor {
public String getHlsUrl() throws ParsingException {
assertPageFetched();
try {
String hlsvp;
if (playerArgs != null && playerArgs.isString("hlsvp")) {
hlsvp = playerArgs.getString("hlsvp", "");
} else {
return "";
String hlsvp = "";
if (playerArgs != null) {
if( playerArgs.isString("hlsvp") ) {
hlsvp = playerArgs.getString("hlsvp", "");
}else {
hlsvp = JsonParser.object()
.from(playerArgs.getString("player_response", "{}"))
.getObject("streamingData", new JsonObject())
.getString("hlsManifestUrl", "");
}
}
return hlsvp;

View File

@ -37,7 +37,7 @@ import org.schabi.newpipe.extractor.utils.Localization;
import javax.annotation.Nonnull;
import java.io.IOException;
public class YoutubeTrendingExtractor extends KioskExtractor {
public class YoutubeTrendingExtractor extends KioskExtractor<StreamInfoItem> {
private Document doc;

View File

@ -1,9 +1,10 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.URL;
import java.util.List;
/*
@ -29,25 +30,53 @@ import java.util.List;
public class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFactory {
private static final YoutubeChannelLinkHandlerFactory instance = new YoutubeChannelLinkHandlerFactory();
private static final String ID_PATTERN = "/(user/[A-Za-z0-9_-]*|channel/[A-Za-z0-9_-]*)";
public static YoutubeChannelLinkHandlerFactory getInstance() {
return instance;
}
@Override
public String getId(String url) throws ParsingException {
return Parser.matchGroup1(ID_PATTERN, url);
}
@Override
public String getUrl(String id, List<String> contentFilters, String searchFilter) {
return "https://www.youtube.com/" + id;
}
@Override
public String getId(String url) throws ParsingException {
try {
URL urlObj = Utils.stringToURL(url);
String path = urlObj.getPath();
if (!(YoutubeParsingHelper.isYoutubeURL(urlObj) || urlObj.getHost().equalsIgnoreCase("hooktube.com"))) {
throw new ParsingException("the URL given is not a Youtube-URL");
}
if (!path.startsWith("/user/") && !path.startsWith("/channel/")) {
throw new ParsingException("the URL given is neither a channel nor an user");
}
// remove leading "/"
path = path.substring(1);
String[] splitPath = path.split("/");
String id = splitPath[1];
if (id == null || !id.matches("[A-Za-z0-9_-]+")) {
throw new ParsingException("The given id is not a Youtube-Video-ID");
}
return splitPath[0] + "/" + id;
} catch (final Exception exception) {
throw new ParsingException("Error could not parse url :" + exception.getMessage(), exception);
}
}
@Override
public boolean onAcceptUrl(String url) {
return (url.contains("youtube") || url.contains("youtu.be") || url.contains("hooktube.com"))
&& (url.contains("/user/") || url.contains("/channel/"));
try {
getId(url);
} catch (ParsingException e) {
return false;
}
return true;
}
}

View File

@ -3,6 +3,8 @@ package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import java.net.URL;
/*
* Created by Christian Schabesberger on 02.03.16.
*
@ -28,6 +30,42 @@ public class YoutubeParsingHelper {
private YoutubeParsingHelper() {
}
private static boolean isHTTP(URL url) {
// make sure its http or https
String protocol = url.getProtocol();
if (!protocol.equals("http") && !protocol.equals("https")) {
return false;
}
boolean usesDefaultPort = url.getPort() == url.getDefaultPort();
boolean setsNoPort = url.getPort() == -1;
return setsNoPort || usesDefaultPort;
}
public static boolean isYoutubeURL(URL url) {
// make sure its http or https
if (!isHTTP(url))
return false;
// make sure its a known youtube url
String host = url.getHost();
return host.equalsIgnoreCase("youtube.com") || host.equalsIgnoreCase("www.youtube.com")
|| host.equalsIgnoreCase("m.youtube.com");
}
public static boolean isYoutubeALikeURL(URL url) {
// make sure its http or https
if (!isHTTP(url))
return false;
// make sure its a known youtube url
String host = url.getHost();
return host.equalsIgnoreCase("youtube.com") || host.equalsIgnoreCase("www.youtube.com")
|| host.equalsIgnoreCase("m.youtube.com") || host.equalsIgnoreCase("www.youtube-nocookie.com")
|| host.equalsIgnoreCase("youtu.be") || host.equalsIgnoreCase("hooktube.com");
}
public static long parseDurationString(String input)
throws ParsingException, NumberFormatException {

View File

@ -1,16 +1,15 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.URL;
import java.util.List;
public class YoutubePlaylistLinkHandlerFactory extends ListLinkHandlerFactory {
private static final YoutubePlaylistLinkHandlerFactory instance = new YoutubePlaylistLinkHandlerFactory();
private static final String ID_PATTERN = "([\\-a-zA-Z0-9_]{10,})";
public static YoutubePlaylistLinkHandlerFactory getInstance() {
return instance;
@ -24,17 +23,35 @@ public class YoutubePlaylistLinkHandlerFactory extends ListLinkHandlerFactory {
@Override
public String getId(String url) throws ParsingException {
try {
return Parser.matchGroup1("list=" + ID_PATTERN, url);
URL urlObj = Utils.stringToURL(url);
if (!YoutubeParsingHelper.isYoutubeURL(urlObj)) {
throw new ParsingException("the url given is not a Youtube-URL");
}
String listID = Utils.getQueryValue(urlObj, "list");
if (listID == null) {
throw new ParsingException("the url given does not include a playlist");
}
if (!listID.matches("[a-zA-Z0-9_-]{10,}")) {
throw new ParsingException("the list-ID given in the URL does not match the list pattern");
}
return listID;
} catch (final Exception exception) {
throw new ParsingException("Error could not parse url :" + exception.getMessage(), exception);
}
}
@Override
public boolean onAcceptUrl(final String url) {
final boolean hasNotEmptyUrl = url != null && !url.isEmpty();
final boolean isYoutubeDomain = hasNotEmptyUrl && (url.contains("youtube") || url.contains("youtu.be"));
return isYoutubeDomain && url.contains("list=");
try {
getId(url);
} catch (ParsingException e) {
return false;
}
return true;
}
}

View File

@ -1,21 +1,14 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.exceptions.FoundAdException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URL;
/*
* Created by Christian Schabesberger on 02.02.16.
@ -40,7 +33,6 @@ import java.net.URLDecoder;
public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
private static final YoutubeStreamLinkHandlerFactory instance = new YoutubeStreamLinkHandlerFactory();
private static final String ID_PATTERN = "([\\-a-zA-Z0-9_]{11})";
private YoutubeStreamLinkHandlerFactory() {
}
@ -49,78 +41,143 @@ public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
return instance;
}
private static String assertIsID(String id) throws ParsingException {
if (id == null || !id.matches("[a-zA-Z0-9_-]{11}")) {
throw new ParsingException("The given string is not a Youtube-Video-ID");
}
return id;
}
@Override
public String getUrl(String id) {
return "https://www.youtube.com/watch?v=" + id;
}
@Override
public String getId(String url) throws ParsingException, IllegalArgumentException {
if (url.isEmpty()) {
throw new IllegalArgumentException("The url parameter should not be empty");
}
public String getId(String urlString) throws ParsingException, IllegalArgumentException {
try {
URI uri = new URI(urlString);
String scheme = uri.getScheme();
String lowercaseUrl = url.toLowerCase();
if (lowercaseUrl.contains("youtube")) {
if (lowercaseUrl.contains("list=")) {
throw new ParsingException("Error no suitable url: " + url);
}
if (url.contains("attribution_link")) {
try {
String escapedQuery = Parser.matchGroup1("u=(.[^&|$]*)", url);
String query = URLDecoder.decode(escapedQuery, "UTF-8");
return Parser.matchGroup1("v=" + ID_PATTERN, query);
} catch (UnsupportedEncodingException uee) {
throw new ParsingException("Could not parse attribution_link", uee);
if (scheme != null && scheme.equals("vnd.youtube")) {
String schemeSpecificPart = uri.getSchemeSpecificPart();
if (schemeSpecificPart.startsWith("//")) {
urlString = "https:" + schemeSpecificPart;
} else {
return assertIsID(schemeSpecificPart);
}
}
if (url.contains("vnd.youtube")) {
return Parser.matchGroup1(ID_PATTERN, url);
}
if (url.contains("embed")) {
return Parser.matchGroup1("embed/" + ID_PATTERN, url);
}
if (url.contains("googleads")) {
throw new FoundAdException("Error found add: " + url);
}
return Parser.matchGroup1("[?&]v=" + ID_PATTERN, url);
} catch (URISyntaxException ignored) {
}
if (lowercaseUrl.contains("youtu.be")) {
if (lowercaseUrl.contains("list=")) {
throw new ParsingException("Error no suitable url: " + url);
}
if (url.contains("v=")) {
return Parser.matchGroup1("v=" + ID_PATTERN, url);
}
return Parser.matchGroup1("[Yy][Oo][Uu][Tt][Uu]\\.[Bb][Ee]/" + ID_PATTERN, url);
URL url;
try {
url = Utils.stringToURL(urlString);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("The given URL is not valid");
}
if (lowercaseUrl.contains("hooktube")) {
if (lowercaseUrl.contains("&v=")
|| lowercaseUrl.contains("?v=")) {
return Parser.matchGroup1("[?&]v=" + ID_PATTERN, url);
}
if (url.contains("/embed/")) {
return Parser.matchGroup1("embed/" + ID_PATTERN, url);
}
if (url.contains("/v/")) {
return Parser.matchGroup1("v/" + ID_PATTERN, url);
}
if (url.contains("/watch/")) {
return Parser.matchGroup1("watch/" + ID_PATTERN, url);
}
String host = url.getHost();
String path = url.getPath();
// remove leading "/" of URL-path if URL-path is given
if (!path.isEmpty()) {
path = path.substring(1);
}
throw new ParsingException("Error no suitable url: " + url);
if (!YoutubeParsingHelper.isYoutubeALikeURL(url)) {
if (host.equalsIgnoreCase("googleads.g.doubleclick.net")) {
throw new FoundAdException("Error found ad: " + urlString);
}
throw new ParsingException("The url is not a Youtube-URL");
}
if (YoutubePlaylistLinkHandlerFactory.getInstance().acceptUrl(urlString)) {
throw new ParsingException("Error no suitable url: " + urlString);
}
// using uppercase instead of lowercase, because toLowercase replaces some unicode characters
// with their lowercase ASCII equivalent. Using toLowercase could result in faultily matching unicode urls.
switch (host.toUpperCase()) {
case "WWW.YOUTUBE-NOCOOKIE.COM": {
if (path.startsWith("embed/")) {
String id = path.split("/")[1];
return assertIsID(id);
}
break;
}
case "YOUTUBE.COM":
case "WWW.YOUTUBE.COM":
case "M.YOUTUBE.COM": {
if (path.equals("attribution_link")) {
String uQueryValue = Utils.getQueryValue(url, "u");
URL decodedURL;
try {
decodedURL = Utils.stringToURL("http://www.youtube.com" + uQueryValue);
} catch (MalformedURLException e) {
throw new ParsingException("Error no suitable url: " + urlString);
}
String viewQueryValue = Utils.getQueryValue(decodedURL, "v");
return assertIsID(viewQueryValue);
}
if (path.startsWith("embed/")) {
String id = path.split("/")[1];
return assertIsID(id);
}
String viewQueryValue = Utils.getQueryValue(url, "v");
return assertIsID(viewQueryValue);
}
case "YOUTU.BE": {
String viewQueryValue = Utils.getQueryValue(url, "v");
if (viewQueryValue != null) {
return assertIsID(viewQueryValue);
}
return assertIsID(path);
}
case "HOOKTUBE.COM": {
if (path.equals("watch")) {
String viewQueryValue = Utils.getQueryValue(url, "v");
if (viewQueryValue != null) {
return assertIsID(viewQueryValue);
}
}
if (path.startsWith("embed/")) {
String id = path.substring("embed/".length());
return assertIsID(id);
}
if (path.startsWith("v/")) {
String id = path.substring("v/".length());
return assertIsID(id);
}
if (path.startsWith("watch/")) {
String id = path.substring("watch/".length());
return assertIsID(id);
}
}
break;
}
throw new ParsingException("Error no suitable url: " + urlString);
}
@Override
public boolean onAcceptUrl(final String url) throws FoundAdException {
final String lowercaseUrl = url.toLowerCase();
if (!lowercaseUrl.contains("youtube") &&
!lowercaseUrl.contains("youtu.be") &&
!lowercaseUrl.contains("hooktube")) {
return false;
// bad programming I know <-- nice meme
}
try {
getId(url);
return true;

View File

@ -21,8 +21,10 @@ package org.schabi.newpipe.extractor.services.youtube.linkHandler;
*/
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public class YoutubeTrendingLinkHandlerFactory extends ListLinkHandlerFactory {
@ -38,6 +40,14 @@ public class YoutubeTrendingLinkHandlerFactory extends ListLinkHandlerFactory {
@Override
public boolean onAcceptUrl(final String url) {
return Parser.isMatch("^(https://|http://|)(www.|m.|)youtube.com/feed/trending(|\\?.*)$", url);
URL urlObj;
try {
urlObj = Utils.stringToURL(url);
} catch (MalformedURLException e) {
return false;
}
String urlPath = urlObj.getPath();
return YoutubeParsingHelper.isYoutubeURL(urlObj) && urlPath.equals("/feed/trending");
}
}

View File

@ -31,6 +31,7 @@ public class ExtractorHelper {
public static List<InfoItem> getRelatedVideosOrLogError(StreamInfo info, StreamExtractor extractor) {
try {
InfoItemsCollector<? extends InfoItem, ?> collector = extractor.getRelatedStreams();
if(collector == null) return Collections.emptyList();
info.addAllErrors(collector.getErrors());
//noinspection unchecked

View File

@ -1,9 +1,13 @@
package org.schabi.newpipe.extractor.utils;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.List;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
public class Utils {
private Utils() {
@ -40,7 +44,7 @@ public class Utils {
}
public static void printErrors(List<Throwable> errors) {
for(Throwable e : errors) {
for (Throwable e : errors) {
e.printStackTrace();
System.err.println("----------------");
}
@ -52,10 +56,78 @@ public class Utils {
public static String replaceHttpWithHttps(final String url) {
if (url == null) return null;
if(!url.isEmpty() && url.startsWith(HTTP)) {
if (!url.isEmpty() && url.startsWith(HTTP)) {
return HTTPS + url.substring(HTTP.length());
}
return url;
}
}
/**
* get the value of a URL-query by name.
* if a url-query is give multiple times, only the value of the first query is returned
*
* @param url the url to be used
* @param parameterName the pattern that will be used to check the url
* @return a string that contains the value of the query parameter or null if nothing was found
*/
public static String getQueryValue(URL url, String parameterName) {
String urlQuery = url.getQuery();
if (urlQuery != null) {
for (String param : urlQuery.split("&")) {
String[] params = param.split("=", 2);
String query;
try {
query = URLDecoder.decode(params[0], "UTF-8");
} catch (UnsupportedEncodingException e) {
System.err.println("Cannot decode string with UTF-8. using the string without decoding");
e.printStackTrace();
query = params[0];
}
if (query.equals(parameterName)) {
try {
return URLDecoder.decode(params[1], "UTF-8");
} catch (UnsupportedEncodingException e) {
System.err.println("Cannot decode string with UTF-8. using the string without decoding");
e.printStackTrace();
return params[1];
}
}
}
}
return null;
}
/**
* converts a string to a URL-Object.
* defaults to HTTP if no protocol is given
*
* @param url the string to be converted to a URL-Object
* @return a URL-Object containing the url
*/
public static URL stringToURL(String url) throws MalformedURLException {
try {
return new URL(url);
} catch (MalformedURLException e) {
// if no protocol is given try prepending "http://"
if (e.getMessage().equals("no protocol: " + url)) {
return new URL(HTTP + url);
}
throw e;
}
}
public static String removeUTF8BOM(String s) {
if (s.startsWith("\uFEFF")) {
s = s.substring(1);
}
if (s.endsWith("\uFEFF")) {
s = s.substring(0, s.length()-1);
}
return s;
}
}

View File

@ -0,0 +1,51 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCConferenceExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
import static junit.framework.TestCase.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
/**
* Test {@link MediaCCCConferenceExtractor}
*/
public class MediaCCCConferenceExtractorTest {
private static ChannelExtractor extractor;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("en", "en_GB"));
extractor = MediaCCC.getChannelExtractor("https://api.media.ccc.de/public/conferences/froscon2017");
extractor.fetchPage();
}
@Test
public void testName() throws Exception {
assertEquals("FrOSCon 2017", extractor.getName());
}
@Test
public void testGetUrl() throws Exception {
assertEquals("https://api.media.ccc.de/public/conferences/froscon2017", extractor.getUrl());
}
@Test
public void testGetOriginalUrl() throws Exception {
assertEquals("https://media.ccc.de/c/froscon2017", extractor.getOriginalUrl());
}
@Test
public void testGetThumbnailUrl() throws Exception {
assertEquals("https://static.media.ccc.de/media/events/froscon/2017/logo.png", extractor.getAvatarUrl());
}
@Test
public void testGetInitalPage() throws Exception {
assertEquals(97,extractor.getInitialPage().getItems().size());
}
}

View File

@ -0,0 +1,59 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCConferenceKiosk;
import org.schabi.newpipe.extractor.utils.Localization;
import java.util.List;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
import static org.junit.Assert.assertTrue;
/**
* Test {@link MediaCCCConferenceKiosk}
*/
public class MediaCCCConferenceListExtractorTest {
private static KioskExtractor extractor;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("en", "en_GB"));
extractor = MediaCCC.getKioskList().getDefaultKioskExtractor();
extractor.fetchPage();
}
@Test
public void getConferencesListTest() throws Exception {
assertTrue("returned list was to small",
extractor.getInitialPage().getItems().size() >= 174);
}
@Test
public void conferenceTypeTest() throws Exception {
assertTrue(contains(extractor.getInitialPage().getItems(), "FrOSCon 2016"));
assertTrue(contains(extractor.getInitialPage().getItems(), "ChaosWest @ 35c3"));
assertTrue(contains(extractor.getInitialPage().getItems(), "CTreffOS chaOStalks"));
assertTrue(contains(extractor.getInitialPage().getItems(), "Datenspuren 2015"));
assertTrue(contains(extractor.getInitialPage().getItems(), "Chaos Singularity 2017"));
assertTrue(contains(extractor.getInitialPage().getItems(), "SIGINT10"));
assertTrue(contains(extractor.getInitialPage().getItems(), "Vintage Computing Festival Berlin 2015"));
assertTrue(contains(extractor.getInitialPage().getItems(), "FIfFKon 2015"));
assertTrue(contains(extractor.getInitialPage().getItems(), "33C3: trailers"));
assertTrue(contains(extractor.getInitialPage().getItems(), "Blinkenlights"));
}
private boolean contains(List<InfoItem> itemList, String name) {
for(InfoItem item : itemList) {
if(item.getName().equals(name))
return true;
}
return false;
}
}

View File

@ -0,0 +1,42 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCStreamExtractor;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
import static junit.framework.TestCase.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
/**
* Test {@link MediaCCCStreamExtractor}
*/
public class MediaCCCOggTest {
// test against https://api.media.ccc.de/public/events/1317
private static StreamExtractor extractor;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
extractor = MediaCCC.getStreamExtractor("https://api.media.ccc.de/public/events/1317");
extractor.fetchPage();
}
@Test
public void getAudioStreamsCount() throws Exception {
assertEquals(1, extractor.getAudioStreams().size());
}
@Test
public void getAudioStreamsContainOgg() throws Exception {
for(AudioStream stream : extractor.getAudioStreams()) {
System.out.println(stream.getFormat());
}
}
}

View File

@ -0,0 +1,60 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCSearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.utils.Localization;
import java.util.Arrays;
import static junit.framework.TestCase.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
/**
* Test for {@link MediaCCCSearchExtractor}
*/
public class MediaCCCSearchExtractorAllTest {
private static SearchExtractor extractor;
private static ListExtractor.InfoItemsPage<InfoItem> itemsPage;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
extractor = MediaCCC.getSearchExtractor( new MediaCCCSearchQueryHandlerFactory()
.fromQuery("c3", Arrays.asList(new String[0]), "")
,new Localization("GB", "en"));
extractor.fetchPage();
itemsPage = extractor.getInitialPage();
}
@Test
public void testIfChannelInfoItemsAvailable() {
boolean isAvialable = false;
for(InfoItem item : itemsPage.getItems()) {
if(item instanceof ChannelInfoItem) {
isAvialable = true;
}
}
assertTrue("ChannelInfoItem not in all list", isAvialable);
}
@Test
public void testIfStreamInfoitemsAvailable() {
boolean isAvialable = false;
for(InfoItem item : itemsPage.getItems()) {
if(item instanceof StreamInfoItem) {
isAvialable = true;
}
}
assertTrue("ChannelInfoItem not in all list", isAvialable);
}
}

View File

@ -0,0 +1,50 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCSearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.utils.Localization;
import java.util.Arrays;
import static junit.framework.TestCase.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
/**
* Test for {@link MediaCCCSearchExtractor}
*/
public class MediaCCCSearchExtractorConferencesTest {
private static SearchExtractor extractor;
private static ListExtractor.InfoItemsPage<InfoItem> itemsPage;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
extractor = MediaCCC.getSearchExtractor( new MediaCCCSearchQueryHandlerFactory()
.fromQuery("c3", Arrays.asList(new String[] {"conferences"}), "")
,new Localization("GB", "en"));
extractor.fetchPage();
itemsPage = extractor.getInitialPage();
}
@Test
public void testReturnTypeChannel() {
for(InfoItem item : itemsPage.getItems()) {
assertTrue("Item is not of type channel", item instanceof ChannelInfoItem);
}
}
@Test
public void testItemCount() {
assertTrue("Count is to hight: " + itemsPage.getItems().size(), itemsPage.getItems().size() < 127);
assertTrue("Countis to low: " + itemsPage.getItems().size(), itemsPage.getItems().size() >= 29);
}
}

View File

@ -0,0 +1,74 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCSearchExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.utils.Localization;
import java.util.Arrays;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
/**
* Test for {@link MediaCCCSearchExtractor}
*/
public class MediaCCCSearchExtractorEventsTest {
private static SearchExtractor extractor;
private static ListExtractor.InfoItemsPage<InfoItem> itemsPage;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
extractor = MediaCCC.getSearchExtractor( new MediaCCCSearchQueryHandlerFactory()
.fromQuery("linux", Arrays.asList(new String[] {"events"}), "")
,new Localization("GB", "en"));
extractor.fetchPage();
itemsPage = extractor.getInitialPage();
}
@Test
public void testCount() throws Exception {
assertTrue(Integer.toString(itemsPage.getItems().size()),
itemsPage.getItems().size() >= 25);
}
@Test
public void testServiceId() throws Exception {
assertEquals(2, extractor.getServiceId());
}
@Test
public void testName() throws Exception {
assertFalse(itemsPage.getItems().get(0).getName(), itemsPage.getItems().get(0).getName().isEmpty());
}
@Test
public void testUrl() throws Exception {
assertTrue("Url should start with: https://api.media.ccc.de/public/events/",
itemsPage.getItems().get(0).getUrl().startsWith("https://api.media.ccc.de/public/events/"));
}
@Test
public void testThumbnailUrl() throws Exception {
assertTrue(itemsPage.getItems().get(0).getThumbnailUrl(),
itemsPage.getItems().get(0).getThumbnailUrl().startsWith("https://static.media.ccc.de/media/")
&& itemsPage.getItems().get(0).getThumbnailUrl().endsWith(".jpg"));
}
@Test
public void testReturnTypeStream() throws Exception {
for(InfoItem item : itemsPage.getItems()) {
assertTrue("Item is not of type StreamInfoItem", item instanceof StreamInfoItem);
}
}
}

View File

@ -0,0 +1,83 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.services.BaseExtractorTest;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCStreamExtractor;
import org.schabi.newpipe.extractor.utils.Localization;
import static junit.framework.TestCase.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
/**
* Test {@link MediaCCCStreamExtractor}
*/
public class MediaCCCStreamExtractorTest implements BaseExtractorTest {
private static StreamExtractor extractor;
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
extractor = MediaCCC.getStreamExtractor("https://api.media.ccc.de/public/events/8afc16c2-d76a-53f6-85e4-90494665835d");
extractor.fetchPage();
}
@Override
public void testServiceId() throws Exception {
assertEquals(2, extractor.getServiceId());
}
@Override
public void testName() throws Exception {
assertEquals("tmux - Warum ein schwarzes Fenster am Bildschirm reicht", extractor.getName());
}
@Override
public void testId() throws Exception {
assertEquals("", extractor.getId());
}
@Override
public void testUrl() throws Exception {
assertEquals("", extractor.getUrl());
}
@Override
public void testOriginalUrl() throws Exception {
assertEquals("", extractor.getOriginalUrl());
}
@Test
public void testThumbnail() throws Exception {
assertEquals("https://static.media.ccc.de/media/events/gpn/gpn18/105-hd.jpg", extractor.getThumbnailUrl());
}
@Test
public void testUploaderName() throws Exception {
assertEquals("gpn18", extractor.getUploaderName());
}
@Test
public void testUploaderUrl() throws Exception {
assertEquals("https://api.media.ccc.de/public/conferences/gpn18", extractor.getUploaderUrl());
}
@Test
public void testUploaderAvatarUrl() throws Exception {
assertEquals("https://static.media.ccc.de/media/events/gpn/gpn18/logo.png", extractor.getUploaderAvatarUrl());
}
@Test
public void testVideoStreams() throws Exception {
assertEquals(4, extractor.getVideoStreams().size());
}
@Test
public void testAudioStreams() throws Exception {
assertEquals(2, extractor.getAudioStreams().size());
}
}

View File

@ -8,10 +8,13 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudSearchExtractor;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSearchExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.utils.Localization;
import java.util.Arrays;
import static org.junit.Assert.*;
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
@ -44,26 +47,20 @@ public class SoundcloudSearchExtractorDefaultTest extends SoundcloudSearchExtrac
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
extractor = (SoundcloudSearchExtractor) SoundCloud.getSearchExtractor("lill uzi vert");
extractor = (SoundcloudSearchExtractor) SoundCloud.getSearchExtractor(
new SoundcloudSearchQueryHandlerFactory().fromQuery("lill uzi vert",
Arrays.asList(new String[]{"tracks"}), ""),
new Localization("GB", "en"));
extractor.fetchPage();
itemsPage = extractor.getInitialPage();
}
@Test
public void testGetSecondPageUrl() throws Exception {
assertEquals("https://api-v2.soundcloud.com/search?q=lill+uzi+vert&limit=10&offset=10",
assertEquals("https://api-v2.soundcloud.com/search/tracks?q=lill+uzi+vert&limit=10&offset=10",
removeClientId(extractor.getNextPageUrl()));
}
@Test
public void testResultList_FirstElement() {
InfoItem firstInfoItem = itemsPage.getItems().get(0);
// THe channel should be the first item
assertEquals("name", "Bad and Boujee (Feat. Lil Uzi Vert) [Prod. By Metro Boomin]", firstInfoItem.getName());
assertEquals("url","https://soundcloud.com/migosatl/bad-and-boujee-feat-lil-uzi-vert-prod-by-metro-boomin", firstInfoItem.getUrl());
}
@Test
public void testResultListCheckIfContainsStreamItems() {
boolean hasStreams = false;
@ -94,7 +91,7 @@ public class SoundcloudSearchExtractorDefaultTest extends SoundcloudSearchExtrac
}
assertFalse("First and second page are equal", equals);
assertEquals("https://api-v2.soundcloud.com/search?q=lill+uzi+vert&limit=10&offset=20",
assertEquals("https://api-v2.soundcloud.com/search/tracks?q=lill+uzi+vert&limit=10&offset=20",
removeClientId(secondPage.getNextPageUrl()));
}

View File

@ -106,13 +106,6 @@ public class YoutubeChannelExtractorTest {
public void testSubscriberCount() throws Exception {
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 0);
}
@Test
public void testChannelDonation() throws Exception {
// this needs to be ignored since wed have to upgrade channel extractor to the new yt interface
// in order to make this work
assertTrue(extractor.getDonationLinks().length == 0);
}
}
// Youtube RED/Premium ad blocking test
@ -204,12 +197,6 @@ public class YoutubeChannelExtractorTest {
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 0);
}
@Test
public void testChannelDonation() throws Exception {
// this needs to be ignored since wed have to upgrade channel extractor to the new yt interface
// in order to make this work
assertTrue(extractor.getDonationLinks().length == 0);
}
}
public static class Kurzgesagt implements BaseChannelExtractorTest {
@ -312,11 +299,6 @@ public class YoutubeChannelExtractorTest {
public void testSubscriberCount() throws Exception {
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 5e6);
}
@Test
public void testChannelDonation() throws Exception {
assertTrue(extractor.getDonationLinks().length == 1);
}
}
public static class CaptainDisillusion implements BaseChannelExtractorTest {
@ -501,11 +483,6 @@ public class YoutubeChannelExtractorTest {
public void testSubscriberCount() throws Exception {
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 50);
}
@Test
public void testChannelDonation() throws Exception {
assertTrue(extractor.getDonationLinks().length == 0);
}
}
};

View File

@ -117,7 +117,7 @@ public class YoutubeStreamExtractorAgeRestrictedTest {
s.getUrl().contains(HTTPS));
assertTrue(s.resolution.length() > 0);
assertTrue(Integer.toString(s.getFormatId()),
0 <= s.getFormatId() && s.getFormatId() <= 4);
0 <= s.getFormatId() && s.getFormatId() <= 0x100);
}
}

View File

@ -135,7 +135,7 @@ public class YoutubeStreamExtractorDefaultTest {
assertIsSecureUrl(s.url);
assertTrue(s.resolution.length() > 0);
assertTrue(Integer.toString(s.getFormatId()),
0 <= s.getFormatId() && s.getFormatId() <= 4);
0 <= s.getFormatId() && s.getFormatId() <= 0x100);
}
}

View File

@ -60,9 +60,9 @@ public class YoutubeStreamLinkHandlerFactoryTest {
public void getIdfromYt() throws Exception {
assertEquals("jZViOEv90dI", linkHandler.fromUrl("https://www.youtube.com/watch?v=jZViOEv90dI").getId());
assertEquals("W-fFHeTX70Q", linkHandler.fromUrl("https://www.youtube.com/watch?v=W-fFHeTX70Q").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("https://www.youtube.com/watch?v=jZViOEv90dI?t=100").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("https://WWW.YouTube.com/watch?v=jZViOEv90dI?t=100").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("HTTPS://www.youtube.com/watch?v=jZViOEv90dI?t=100").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("https://www.youtube.com/watch?v=jZViOEv90dI&t=100").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("https://WWW.YouTube.com/watch?v=jZViOEv90dI&t=100").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("HTTPS://www.youtube.com/watch?v=jZViOEv90dI&t=100").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("https://youtu.be/jZViOEv90dI?t=9s").getId());
assertEquals("jZViOEv90dI", linkHandler.fromUrl("HTTPS://Youtu.be/jZViOEv90dI?t=9s").getId());
assertEquals("uEJuoEs1UxY", linkHandler.fromUrl("http://www.youtube.com/watch_popup?v=uEJuoEs1UxY").getId());
@ -85,9 +85,9 @@ public class YoutubeStreamLinkHandlerFactoryTest {
@Test
public void testAcceptYtUrl() throws ParsingException {
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/watch?v=jZViOEv90dI"));
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/watch?v=jZViOEv90dI?t=100"));
assertTrue(linkHandler.acceptUrl("https://WWW.YouTube.com/watch?v=jZViOEv90dI?t=100"));
assertTrue(linkHandler.acceptUrl("HTTPS://www.youtube.com/watch?v=jZViOEv90dI?t=100"));
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/watch?v=jZViOEv90dI&t=100"));
assertTrue(linkHandler.acceptUrl("https://WWW.YouTube.com/watch?v=jZViOEv90dI&t=100"));
assertTrue(linkHandler.acceptUrl("HTTPS://www.youtube.com/watch?v=jZViOEv90dI&t=100"));
assertTrue(linkHandler.acceptUrl("https://youtu.be/jZViOEv90dI?t=9s"));
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/embed/jZViOEv90dI"));
assertTrue(linkHandler.acceptUrl("https://www.youtube-nocookie.com/embed/jZViOEv90dI"));

View File

@ -6,6 +6,7 @@ import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSearchExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
@ -63,13 +64,16 @@ public class YoutubeSearchExtractorDefaultTest extends YoutubeSearchExtractorBas
@Test
public void testResultList_FirstElement() {
InfoItem firstInfoItem = itemsPage.getItems().get(0);
if(! (firstInfoItem instanceof ChannelInfoItem))
firstInfoItem = itemsPage.getItems().get(1);
InfoItem secondInfoItem = itemsPage.getItems().get(1);
InfoItem channelItem = firstInfoItem instanceof ChannelInfoItem ? firstInfoItem
: secondInfoItem;
// The channel should be the first item
assertTrue(firstInfoItem instanceof ChannelInfoItem);
assertEquals("name", "PewDiePie", firstInfoItem.getName());
assertEquals("url","https://www.youtube.com/user/PewDiePie", firstInfoItem.getUrl());
assertTrue((firstInfoItem instanceof ChannelInfoItem)
|| (secondInfoItem instanceof ChannelInfoItem));
assertEquals("name", "PewDiePie", channelItem.getName());
assertEquals("url","https://www.youtube.com/user/PewDiePie", channelItem.getUrl());
}
@Test