Merge branch 'master' into master

This commit is contained in:
Christian Schabesberger 2018-09-15 22:18:54 +02:00 committed by GitHub
commit ae8107b182
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 646 additions and 353 deletions

View File

@ -67,10 +67,10 @@ public abstract class StreamingService {
//////////////////////////////////////////// ////////////////////////////////////////////
// Url Id handler // Url Id handler
//////////////////////////////////////////// ////////////////////////////////////////////
public abstract LinkHandlerFactory getStreamUIHFactory(); public abstract LinkHandlerFactory getStreamLHFactory();
public abstract ListLinkHandlerFactory getChannelUIHFactory(); public abstract ListLinkHandlerFactory getChannelLHFactory();
public abstract ListLinkHandlerFactory getPlaylistUIHFactory(); public abstract ListLinkHandlerFactory getPlaylistLHFactory();
public abstract SearchQueryHandlerFactory getSearchQIHFactory(); public abstract SearchQueryHandlerFactory getSearchQHFactory();
//////////////////////////////////////////// ////////////////////////////////////////////
@ -86,31 +86,31 @@ public abstract class StreamingService {
public abstract StreamExtractor getStreamExtractor(LinkHandler UIHFactory) throws ExtractionException; public abstract StreamExtractor getStreamExtractor(LinkHandler UIHFactory) throws ExtractionException;
public SearchExtractor getSearchExtractor(String query, List<String> contentFilter, String sortFilter, String contentCountry) throws ExtractionException { public SearchExtractor getSearchExtractor(String query, List<String> contentFilter, String sortFilter, String contentCountry) throws ExtractionException {
return getSearchExtractor(getSearchQIHFactory().fromQuery(query, contentFilter, sortFilter), contentCountry); return getSearchExtractor(getSearchQHFactory().fromQuery(query, contentFilter, sortFilter), contentCountry);
} }
public ChannelExtractor getChannelExtractor(String id, List<String> contentFilter, String sortFilter) throws ExtractionException { public ChannelExtractor getChannelExtractor(String id, List<String> contentFilter, String sortFilter) throws ExtractionException {
return getChannelExtractor(getChannelUIHFactory().fromQuery(id, contentFilter, sortFilter)); return getChannelExtractor(getChannelLHFactory().fromQuery(id, contentFilter, sortFilter));
} }
public PlaylistExtractor getPlaylistExtractor(String id, List<String> contentFilter, String sortFilter) throws ExtractionException { public PlaylistExtractor getPlaylistExtractor(String id, List<String> contentFilter, String sortFilter) throws ExtractionException {
return getPlaylistExtractor(getPlaylistUIHFactory().fromQuery(id, contentFilter, sortFilter)); return getPlaylistExtractor(getPlaylistLHFactory().fromQuery(id, contentFilter, sortFilter));
} }
public SearchExtractor getSearchExtractor(String query, String contentCountry) throws ExtractionException { public SearchExtractor getSearchExtractor(String query, String contentCountry) throws ExtractionException {
return getSearchExtractor(getSearchQIHFactory().fromQuery(query), contentCountry); return getSearchExtractor(getSearchQHFactory().fromQuery(query), contentCountry);
} }
public ChannelExtractor getChannelExtractor(String url) throws ExtractionException { public ChannelExtractor getChannelExtractor(String url) throws ExtractionException {
return getChannelExtractor(getChannelUIHFactory().fromUrl(url)); return getChannelExtractor(getChannelLHFactory().fromUrl(url));
} }
public PlaylistExtractor getPlaylistExtractor(String url) throws ExtractionException { public PlaylistExtractor getPlaylistExtractor(String url) throws ExtractionException {
return getPlaylistExtractor(getPlaylistUIHFactory().fromUrl(url)); return getPlaylistExtractor(getPlaylistLHFactory().fromUrl(url));
} }
public StreamExtractor getStreamExtractor(String url) throws ExtractionException { public StreamExtractor getStreamExtractor(String url) throws ExtractionException {
return getStreamExtractor(getStreamUIHFactory().fromUrl(url)); return getStreamExtractor(getStreamLHFactory().fromUrl(url));
} }
@ -119,9 +119,9 @@ public abstract class StreamingService {
* figure out where the link is pointing to (a channel, video, playlist, etc.) * figure out where the link is pointing to (a channel, video, playlist, etc.)
*/ */
public final LinkType getLinkTypeByUrl(String url) throws ParsingException { public final LinkType getLinkTypeByUrl(String url) throws ParsingException {
LinkHandlerFactory sH = getStreamUIHFactory(); LinkHandlerFactory sH = getStreamLHFactory();
LinkHandlerFactory cH = getChannelUIHFactory(); LinkHandlerFactory cH = getChannelLHFactory();
LinkHandlerFactory pH = getPlaylistUIHFactory(); LinkHandlerFactory pH = getPlaylistLHFactory();
if (sH.acceptUrl(url)) { if (sH.acceptUrl(url)) {
return LinkType.STREAM; return LinkType.STREAM;

View File

@ -57,11 +57,11 @@ public class SoundcloudChartsExtractor extends KioskExtractor {
apiUrl += "&kind=trending"; apiUrl += "&kind=trending";
} }
List<String> supportedCountries = Arrays.asList("AU", "CA", "FR", "DE", "IE", "NL", "NZ", "GB", "US"); /*List<String> supportedCountries = Arrays.asList("AU", "CA", "FR", "DE", "IE", "NL", "NZ", "GB", "US");
String contentCountry = getContentCountry(); String contentCountry = getContentCountry();
if (supportedCountries.contains(contentCountry)) { if (supportedCountries.contains(contentCountry)) {
apiUrl += "&region=soundcloud:regions:" + contentCountry; apiUrl += "&region=soundcloud:regions:" + contentCountry;
} }*/
nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl, true); nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl, true);
} }

View File

@ -26,22 +26,22 @@ public class SoundcloudService extends StreamingService {
} }
@Override @Override
public SearchQueryHandlerFactory getSearchQIHFactory() { public SearchQueryHandlerFactory getSearchQHFactory() {
return new SoundcloudSearchQueryHandlerFactory(); return new SoundcloudSearchQueryHandlerFactory();
} }
@Override @Override
public LinkHandlerFactory getStreamUIHFactory() { public LinkHandlerFactory getStreamLHFactory() {
return SoundcloudStreamLinkHandlerFactory.getInstance(); return SoundcloudStreamLinkHandlerFactory.getInstance();
} }
@Override @Override
public ListLinkHandlerFactory getChannelUIHFactory() { public ListLinkHandlerFactory getChannelLHFactory() {
return SoundcloudChannelLinkHandlerFactory.getInstance(); return SoundcloudChannelLinkHandlerFactory.getInstance();
} }
@Override @Override
public ListLinkHandlerFactory getPlaylistUIHFactory() { public ListLinkHandlerFactory getPlaylistLHFactory() {
return SoundcloudPlaylistLinkHandlerFactory.getInstance(); return SoundcloudPlaylistLinkHandlerFactory.getInstance();
} }

View File

@ -31,7 +31,7 @@ public class SoundcloudSubscriptionExtractor extends SubscriptionExtractor {
String id; String id;
try { try {
id = service.getChannelUIHFactory().fromUrl(getUrlFrom(channelUrl)).getId(); id = service.getChannelLHFactory().fromUrl(getUrlFrom(channelUrl)).getId();
} catch (ExtractionException e) { } catch (ExtractionException e) {
throw new InvalidSourceException(e); throw new InvalidSourceException(e);
} }

View File

@ -34,10 +34,6 @@ public class ItagItem {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// AUDIO ID ItagType Format Bitrate /// // AUDIO ID ItagType Format Bitrate ///
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Disable Opus codec as it's not well supported in older devices
// new ItagItem(249, AUDIO, WEBMA, 50),
// new ItagItem(250, AUDIO, WEBMA, 70),
// new ItagItem(251, AUDIO, WEBMA, 160),
new ItagItem(171, AUDIO, WEBMA, 128), new ItagItem(171, AUDIO, WEBMA, 128),
new ItagItem(172, AUDIO, WEBMA, 256), new ItagItem(172, AUDIO, WEBMA, 256),
new ItagItem(139, AUDIO, M4A, 48), new ItagItem(139, AUDIO, M4A, 48),
@ -45,7 +41,7 @@ public class ItagItem {
new ItagItem(141, AUDIO, M4A, 256), new ItagItem(141, AUDIO, M4A, 256),
new ItagItem(249, AUDIO, OPUS, 50), new ItagItem(249, AUDIO, OPUS, 50),
new ItagItem(250, AUDIO, OPUS, 70), new ItagItem(250, AUDIO, OPUS, 70),
new ItagItem(160, AUDIO, OPUS, 160), new ItagItem(251, AUDIO, OPUS, 160),
/// VIDEO ONLY //////////////////////////////////////////// /// VIDEO ONLY ////////////////////////////////////////////
// ID Type Format Resolution FPS /// // ID Type Format Resolution FPS ///

View File

@ -49,22 +49,22 @@ public class YoutubeService extends StreamingService {
} }
@Override @Override
public LinkHandlerFactory getStreamUIHFactory() { public LinkHandlerFactory getStreamLHFactory() {
return YoutubeStreamLinkHandlerFactory.getInstance(); return YoutubeStreamLinkHandlerFactory.getInstance();
} }
@Override @Override
public ListLinkHandlerFactory getChannelUIHFactory() { public ListLinkHandlerFactory getChannelLHFactory() {
return YoutubeChannelLinkHandlerFactory.getInstance(); return YoutubeChannelLinkHandlerFactory.getInstance();
} }
@Override @Override
public ListLinkHandlerFactory getPlaylistUIHFactory() { public ListLinkHandlerFactory getPlaylistLHFactory() {
return YoutubePlaylistLinkHandlerFactory.getInstance(); return YoutubePlaylistLinkHandlerFactory.getInstance();
} }
@Override @Override
public SearchQueryHandlerFactory getSearchQIHFactory() { public SearchQueryHandlerFactory getSearchQHFactory() {
return YoutubeSearchQueryHandlerFactory.getInstance(); return YoutubeSearchQueryHandlerFactory.getInstance();
} }

View File

@ -7,13 +7,15 @@ import com.grack.nanojson.JsonParserException;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.schabi.newpipe.extractor.*; import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor; import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.utils.DonationLinkHelper; import org.schabi.newpipe.extractor.utils.DonationLinkHelper;
import org.schabi.newpipe.extractor.utils.Parser; import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
@ -131,11 +133,16 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
@Override @Override
public long getSubscriberCount() throws ParsingException { public long getSubscriberCount() throws ParsingException {
Element el = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]").first(); final Element el = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]").first();
if (el != null) { if (el != null) {
return Long.parseLong(Utils.removeNonDigitCharacters(el.text())); try {
return Long.parseLong(Utils.removeNonDigitCharacters(el.text()));
} catch (NumberFormatException e) {
throw new ParsingException("Could not get subscriber count", e);
}
} else { } else {
throw new ParsingException("Could not get subscriber count"); // If the element is null, the channel have the subscriber count disabled
return -1;
} }
} }

View File

@ -59,11 +59,16 @@ public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor
@Override @Override
public long getSubscriberCount() throws ParsingException { public long getSubscriberCount() throws ParsingException {
Element subsEl = el.select("span[class*=\"yt-subscriber-count\"]").first(); final Element subsEl = el.select("span[class*=\"yt-subscriber-count\"]").first();
if (subsEl == null) { if (subsEl != null) {
return 0; try {
return Long.parseLong(Utils.removeNonDigitCharacters(subsEl.text()));
} catch (NumberFormatException e) {
throw new ParsingException("Could not get subscriber count", e);
}
} else { } else {
return Long.parseLong(Utils.removeNonDigitCharacters(subsEl.text())); // If the element is null, the channel have the subscriber count disabled
return -1;
} }
} }

View File

@ -6,7 +6,8 @@ import com.grack.nanojson.JsonParserException;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.schabi.newpipe.extractor.*; import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory; import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
@ -19,6 +20,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@ -118,7 +120,7 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
@Nonnull @Nonnull
@Override @Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException { public InfoItemsPage<StreamInfoItem> getInitialPage() throws ExtractionException {
StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
Element tbody = doc.select("tbody[id=\"pl-load-more-destination\"]").first(); Element tbody = doc.select("tbody[id=\"pl-load-more-destination\"]").first();
collectStreamsFrom(collector, tbody); collectStreamsFrom(collector, tbody);
@ -172,10 +174,14 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
} }
} }
private void collectStreamsFrom(StreamInfoItemsCollector collector, Element element) { private void collectStreamsFrom(@Nonnull StreamInfoItemsCollector collector, @Nullable Element element) {
collector.reset(); collector.reset();
final LinkHandlerFactory streamLinkHandlerFactory = getService().getStreamUIHFactory(); if (element == null) {
return;
}
final LinkHandlerFactory streamLinkHandlerFactory = getService().getStreamLHFactory();
for (final Element li : element.children()) { for (final Element li : element.children()) {
if(isDeletedItem(li)) { if(isDeletedItem(li)) {
continue; continue;

View File

@ -48,18 +48,22 @@ public class YoutubePlaylistInfoItemExtractor implements PlaylistInfoItemExtract
@Override @Override
public String getUrl() throws ParsingException { public String getUrl() throws ParsingException {
String url;
try { try {
final Element href = el.select("div[class=\"yt-lockup-meta\"]").first() final Element div = el.select("div[class=\"yt-lockup-meta\"]").first();
.select("a").first();
if(div != null) {
final Element a = div.select("a").first();
return a.attr("abs:href");
}
// this is for yt premium playlists
return el.select("h3[class=\"yt-lockup-title\"").first()
.select("a").first()
.attr("abs:href");
url = href.attr("abs:href");
} catch (Exception e) { } catch (Exception e) {
throw new ParsingException("Failed to extract playlist url", e); throw new ParsingException("Failed to extract playlist url", e);
} }
return url;
} }
@Override @Override

View File

@ -18,13 +18,15 @@ import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler; import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.services.youtube.ItagItem; import org.schabi.newpipe.extractor.services.youtube.ItagItem;
import org.schabi.newpipe.extractor.stream.*; import org.schabi.newpipe.extractor.stream.*;
import org.schabi.newpipe.extractor.utils.DonationLinkHelper;
import org.schabi.newpipe.extractor.utils.Parser; import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*; import java.util.*;
/* /*
@ -152,12 +154,41 @@ public class YoutubeStreamExtractor extends StreamExtractor {
public String getDescription() throws ParsingException { public String getDescription() throws ParsingException {
assertPageFetched(); assertPageFetched();
try { try {
return doc.select("p[id=\"eow-description\"]").first().html(); return parseHtmlAndGetFullLinks(doc.select("p[id=\"eow-description\"]").first().html());
} catch (Exception e) {//todo: add fallback method <-- there is no ... as long as i know } catch (Exception e) {
throw new ParsingException("Could not get the description", e); throw new ParsingException("Could not get the description", e);
} }
} }
private String parseHtmlAndGetFullLinks(String descriptionHtml)
throws MalformedURLException, UnsupportedEncodingException, ParsingException {
final Document description = Jsoup.parse(descriptionHtml, getUrl());
for(Element a : description.select("a")) {
final URL redirectLink = new URL(
a.attr("abs:href"));
final String queryString = redirectLink.getQuery();
if(queryString != null) {
// if the query string is null we are not dealing with a redirect link,
// so we don't need to override it.
final String link =
Parser.compatParseMap(queryString).get("q");
if(link != null) {
// if link is null the a tag is a hashtag.
// They refer to the youtube search. We do not handle them.
a.text(link);
}
} else if(redirectLink.toString().contains("watch?v=")
|| redirectLink.toString().contains("https://www.youtube.com/")) {
// Another posibility is that this link is pointing to another video
// we need to put the redirectLink in here explicitly in order to add the domain part to the link.
a.text(redirectLink.toString());
}
}
return description.select("body").first().html();
}
@Override @Override
public int getAgeLimit() throws ParsingException { public int getAgeLimit() throws ParsingException {
assertPageFetched(); assertPageFetched();
@ -409,7 +440,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
} }
@Override @Override
public List<VideoStream> getVideoOnlyStreams() throws IOException, ExtractionException { public List<VideoStream> getVideoOnlyStreams() throws ExtractionException {
assertPageFetched(); assertPageFetched();
List<VideoStream> videoOnlyStreams = new ArrayList<>(); List<VideoStream> videoOnlyStreams = new ArrayList<>();
try { try {
@ -530,6 +561,13 @@ public class YoutubeStreamExtractor extends StreamExtractor {
private static final String VERIFIED_URL_PARAMS = "&has_verified=1&bpctr=9999999999"; private static final String VERIFIED_URL_PARAMS = "&has_verified=1&bpctr=9999999999";
private final static String DECYRYPTION_SIGNATURE_FUNCTION_REGEX =
"(\\w+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;";
private final static String DECRYPTION_AKAMAIZED_STRING_REGEX =
"yt\\.akamaized\\.net/\\)\\s*\\|\\|\\s*.*?\\s*c\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*([a-zA-Z0-9$]+)\\(";
private final static String DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX =
"\\bc\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*([a-zA-Z0-9$]+)\\(";
private volatile String decryptionCode = ""; private volatile String decryptionCode = "";
private String pageHtml = null; private String pageHtml = null;
@ -652,13 +690,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
} }
private String loadDecryptionCode(String playerUrl) throws DecryptException { private String loadDecryptionCode(String playerUrl) throws DecryptException {
String decryptionFuncName;
String decryptionFunc;
String helperObjectName;
String helperObject;
String callerFunc = "function " + DECRYPTION_FUNC_NAME + "(a){return %%(a);}";
String decryptionCode;
try { try {
Downloader downloader = NewPipe.getDownloader(); Downloader downloader = NewPipe.getDownloader();
if (!playerUrl.contains("https://youtube.com")) { if (!playerUrl.contains("https://youtube.com")) {
@ -666,33 +697,38 @@ public class YoutubeStreamExtractor extends StreamExtractor {
//than we have to add it by hand //than we have to add it by hand
playerUrl = "https://youtube.com" + playerUrl; playerUrl = "https://youtube.com" + playerUrl;
} }
String playerCode = downloader.download(playerUrl);
decryptionFuncName = final String playerCode = downloader.download(playerUrl);
Parser.matchGroup("([\"\\'])signature\\1\\s*,\\s*([a-zA-Z0-9$]+)\\(", playerCode, 2);
String functionPattern = "(" final String decryptionFunctionName;
+ decryptionFuncName.replace("$", "\\$") if (Parser.isMatch(DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX, playerCode)) {
decryptionFunctionName = Parser.matchGroup1(DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX, playerCode);
} else if (Parser.isMatch(DECRYPTION_AKAMAIZED_STRING_REGEX, playerCode)) {
decryptionFunctionName = Parser.matchGroup1(DECRYPTION_AKAMAIZED_STRING_REGEX, playerCode);
} else {
decryptionFunctionName = Parser.matchGroup1(DECYRYPTION_SIGNATURE_FUNCTION_REGEX, playerCode);
}
final String functionPattern = "("
+ decryptionFunctionName.replace("$", "\\$")
+ "=function\\([a-zA-Z0-9_]+\\)\\{.+?\\})"; + "=function\\([a-zA-Z0-9_]+\\)\\{.+?\\})";
decryptionFunc = "var " + Parser.matchGroup1(functionPattern, playerCode) + ";"; final String decryptionFunction = "var " + Parser.matchGroup1(functionPattern, playerCode) + ";";
helperObjectName = Parser final String helperObjectName =
.matchGroup1(";([A-Za-z0-9_\\$]{2})\\...\\(", decryptionFunc); Parser.matchGroup1(";([A-Za-z0-9_\\$]{2})\\...\\(", decryptionFunction);
final String helperPattern =
"(var " + helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)";
final String helperObject =
Parser.matchGroup1(helperPattern, playerCode.replace("\n", ""));
String helperPattern = "(var " final String callerFunction =
+ helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)"; "function " + DECRYPTION_FUNC_NAME + "(a){return " + decryptionFunctionName + "(a);}";
helperObject = Parser.matchGroup1(helperPattern, playerCode.replace("\n", ""));
return helperObject + decryptionFunction + callerFunction;
callerFunc = callerFunc.replace("%%", decryptionFuncName);
decryptionCode = helperObject + decryptionFunc + callerFunc;
} catch (IOException ioe) { } catch (IOException ioe) {
throw new DecryptException("Could not load decrypt function", ioe); throw new DecryptException("Could not load decrypt function", ioe);
} catch (Exception e) { } catch (Exception e) {
throw new DecryptException("Could not parse decrypt function ", e); throw new DecryptException("Could not parse decrypt function ", e);
} }
return decryptionCode;
} }
private String decryptSignature(String encryptedSig, String decryptionCode) throws DecryptException { private String decryptSignature(String encryptedSig, String decryptionCode) throws DecryptException {

View File

@ -45,7 +45,17 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
@Override @Override
public boolean isAd() throws ParsingException { public boolean isAd() throws ParsingException {
return !item.select("span[class*=\"icon-not-available\"]").isEmpty() return !item.select("span[class*=\"icon-not-available\"]").isEmpty()
|| !item.select("span[class*=\"yt-badge-ad\"]").isEmpty(); || !item.select("span[class*=\"yt-badge-ad\"]").isEmpty()
|| isPremiumVideo();
}
private boolean isPremiumVideo() {
Element premiumSpan = item.select("span[class=\"standalone-collection-badge-renderer-red-text\"]").first();
if(premiumSpan == null) return false;
// if this span has text it most likely says ("Free Video") so we can play this
if(premiumSpan.hasText()) return false;
return true;
} }
@Override @Override
@ -119,6 +129,9 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
Element meta = item.select("div[class=\"yt-lockup-meta\"]").first(); Element meta = item.select("div[class=\"yt-lockup-meta\"]").first();
if (meta == null) return ""; if (meta == null) return "";
Element li = meta.select("li").first();
if(li == null) return "";
return meta.select("li").first().text(); return meta.select("li").first().text();
} catch (Exception e) { } catch (Exception e) {
throw new ParsingException("Could not get upload date", e); throw new ParsingException("Could not get upload date", e);

View File

@ -30,11 +30,17 @@ public class YoutubeParsingHelper {
public static long parseDurationString(String input) public static long parseDurationString(String input)
throws ParsingException, NumberFormatException { throws ParsingException, NumberFormatException {
String[] splitInput = input.split(":");
// If time separator : is not detected, try . instead
final String[] splitInput = input.contains(":")
? input.split(":")
: input.split("\\.");
String days = "0"; String days = "0";
String hours = "0"; String hours = "0";
String minutes = "0"; String minutes = "0";
String seconds; final String seconds;
switch (splitInput.length) { switch (splitInput.length) {
case 4: case 4:

View File

@ -74,9 +74,6 @@ public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
throw new ParsingException("Could not parse attribution_link", uee); throw new ParsingException("Could not parse attribution_link", uee);
} }
} }
if (lowercaseUrl.contains("youtube.com/shared?ci=")) {
return getRealIdFromSharedLink(url);
}
if (url.contains("vnd.youtube")) { if (url.contains("vnd.youtube")) {
return Parser.matchGroup1(ID_PATTERN, url); return Parser.matchGroup1(ID_PATTERN, url);
} }
@ -115,56 +112,6 @@ public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
throw new ParsingException("Error no suitable url: " + url); throw new ParsingException("Error no suitable url: " + url);
} }
/**
* Get the real url from a shared uri.
* <p>
* Shared URI's look like this:
* <pre>
* * https://www.youtube.com/shared?ci=PJICrTByb3E
* * vnd.youtube://www.youtube.com/shared?ci=PJICrTByb3E&amp;feature=twitter-deep-link
* </pre>
*
* @param url The shared url
* @return the id of the stream
* @throws ParsingException
*/
private String getRealIdFromSharedLink(String url) throws ParsingException {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new ParsingException("Invalid shared link", e);
}
String sharedId = getSharedId(uri);
Downloader downloader = NewPipe.getDownloader();
String content;
try {
content = downloader.download("https://www.youtube.com/shared?ci=" + sharedId);
} catch (IOException | ReCaptchaException e) {
throw new ParsingException("Unable to resolve shared link", e);
}
final Document document = Jsoup.parse(content);
final Element element = document.select("link[rel=\"canonical\"]").first();
final String urlWithRealId = (element != null)
? element.attr("abs:href")
: document.select("meta[property=\"og:url\"]").first()
.attr("abs:content");
String realId = Parser.matchGroup1(ID_PATTERN, urlWithRealId);
if (sharedId.equals(realId)) {
throw new ParsingException("Got same id for as shared info_id: " + sharedId);
}
return realId;
}
private String getSharedId(URI uri) throws ParsingException {
if (!"/shared".equals(uri.getPath())) {
throw new ParsingException("Not a shared link: " + uri.toString() + " (path != " + uri.getPath() + ")");
}
return Parser.matchGroup1("ci=" + ID_PATTERN, uri.getQuery());
}
@Override @Override
public boolean onAcceptUrl(final String url) throws FoundAdException { public boolean onAcceptUrl(final String url) throws FoundAdException {
final String lowercaseUrl = url.toLowerCase(); final String lowercaseUrl = url.toLowerCase();

View File

@ -147,7 +147,10 @@ public class StreamInfo extends Info {
Exception dashMpdError = null; Exception dashMpdError = null;
if (streamInfo.getDashMpdUrl() != null && !streamInfo.getDashMpdUrl().isEmpty()) { if (streamInfo.getDashMpdUrl() != null && !streamInfo.getDashMpdUrl().isEmpty()) {
try { try {
DashMpdParser.getStreams(streamInfo); DashMpdParser.ParserResult result = DashMpdParser.getStreams(streamInfo);
streamInfo.getVideoOnlyStreams().addAll(result.getVideoOnlyStreams());
streamInfo.getAudioStreams().addAll(result.getAudioStreams());
streamInfo.getVideoStreams().addAll(result.getVideoStreams());
} catch (Exception e) { } catch (Exception e) {
// Sometimes we receive 403 (forbidden) error when trying to download the manifest (similar to what happens with youtube-dl), // Sometimes we receive 403 (forbidden) error when trying to download the manifest (similar to what happens with youtube-dl),
// just skip the exception (but store it somewhere), as we later check if we have streams anyway. // just skip the exception (but store it somewhere), as we later check if we have streams anyway.

View File

@ -12,6 +12,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
@ -19,6 +20,8 @@ import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/* /*
* Created by Christian Schabesberger on 02.02.16. * Created by Christian Schabesberger on 02.02.16.
@ -51,6 +54,30 @@ public class DashMpdParser {
} }
} }
public static class ParserResult {
private final List<VideoStream> videoStreams;
private final List<AudioStream> audioStreams;
private final List<VideoStream> videoOnlyStreams;
public ParserResult(List<VideoStream> videoStreams, List<AudioStream> audioStreams, List<VideoStream> videoOnlyStreams) {
this.videoStreams = videoStreams;
this.audioStreams = audioStreams;
this.videoOnlyStreams = videoOnlyStreams;
}
public List<VideoStream> getVideoStreams() {
return videoStreams;
}
public List<AudioStream> getAudioStreams() {
return audioStreams;
}
public List<VideoStream> getVideoOnlyStreams() {
return videoOnlyStreams;
}
}
/** /**
* Will try to download (using {@link StreamInfo#dashMpdUrl}) and parse the dash manifest, * Will try to download (using {@link StreamInfo#dashMpdUrl}) and parse the dash manifest,
* then it will search for any stream that the ItagItem has (by the id). * then it will search for any stream that the ItagItem has (by the id).
@ -58,9 +85,12 @@ public class DashMpdParser {
* It has video, video only and audio streams and will only add to the list if it don't * It has video, video only and audio streams and will only add to the list if it don't
* find a similar stream in the respective lists (calling {@link Stream#equalStats}). * find a similar stream in the respective lists (calling {@link Stream#equalStats}).
* *
* Info about dash MPD can be found here
* @see <a href="https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html">www.brendanlog.com</a>
*
* @param streamInfo where the parsed streams will be added * @param streamInfo where the parsed streams will be added
*/ */
public static void getStreams(StreamInfo streamInfo) throws DashMpdParsingException, ReCaptchaException { public static ParserResult getStreams(final StreamInfo streamInfo) throws DashMpdParsingException, ReCaptchaException {
String dashDoc; String dashDoc;
Downloader downloader = NewPipe.getDownloader(); Downloader downloader = NewPipe.getDownloader();
try { try {
@ -72,45 +102,58 @@ public class DashMpdParser {
} }
try { try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder(); final DocumentBuilder builder = factory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(dashDoc.getBytes()); final InputStream stream = new ByteArrayInputStream(dashDoc.getBytes());
Document doc = builder.parse(stream); final Document doc = builder.parse(stream);
NodeList representationList = doc.getElementsByTagName("Representation"); final NodeList representationList = doc.getElementsByTagName("Representation");
final List<VideoStream> videoStreams = new ArrayList<>();
final List<AudioStream> audioStreams = new ArrayList<>();
final List<VideoStream> videoOnlyStreams = new ArrayList<>();
for (int i = 0; i < representationList.getLength(); i++) { for (int i = 0; i < representationList.getLength(); i++) {
Element representation = ((Element) representationList.item(i)); final Element representation = (Element) representationList.item(i);
try { try {
String mimeType = ((Element) representation.getParentNode()).getAttribute("mimeType"); final String mimeType = ((Element) representation.getParentNode()).getAttribute("mimeType");
String id = representation.getAttribute("id"); final String id = representation.getAttribute("id");
String url = representation.getElementsByTagName("BaseURL").item(0).getTextContent(); final String url = representation.getElementsByTagName("BaseURL").item(0).getTextContent();
ItagItem itag = ItagItem.getItag(Integer.parseInt(id)); final ItagItem itag = ItagItem.getItag(Integer.parseInt(id));
if (itag != null) { final Node segmentationList = representation.getElementsByTagName("SegmentList").item(0);
MediaFormat mediaFormat = MediaFormat.getFromMimeType(mimeType);
// if SegmentList is not null this means that BaseUrl is not representing the url to the stream.
// instead we need to add the "media=" value from the <SegementURL/> tags inside the <SegmentList/>
// tag in order to get a full working url. However each of these is just pointing to a part of the
// video, so we can not return a URL with a working stream here.
// We decided not to ignore such streams for the moment.
if (itag != null && segmentationList == null) {
final MediaFormat mediaFormat = MediaFormat.getFromMimeType(mimeType);
if (itag.itagType.equals(ItagItem.ItagType.AUDIO)) { if (itag.itagType.equals(ItagItem.ItagType.AUDIO)) {
AudioStream audioStream = new AudioStream(url, mediaFormat, itag.avgBitrate); final AudioStream audioStream = new AudioStream(url, mediaFormat, itag.avgBitrate);
if (!Stream.containSimilarStream(audioStream, streamInfo.getAudioStreams())) { if (!Stream.containSimilarStream(audioStream, streamInfo.getAudioStreams())) {
streamInfo.getAudioStreams().add(audioStream); audioStreams.add(audioStream);
} }
} else { } else {
boolean isVideoOnly = itag.itagType.equals(ItagItem.ItagType.VIDEO_ONLY); boolean isVideoOnly = itag.itagType.equals(ItagItem.ItagType.VIDEO_ONLY);
VideoStream videoStream = new VideoStream(url, mediaFormat, itag.resolutionString, isVideoOnly); final VideoStream videoStream = new VideoStream(url, mediaFormat, itag.resolutionString, isVideoOnly);
if (isVideoOnly) { if (isVideoOnly) {
if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoOnlyStreams())) { if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoOnlyStreams())) {
streamInfo.getVideoOnlyStreams().add(videoStream); streamInfo.getVideoOnlyStreams().add(videoStream);
videoOnlyStreams.add(videoStream);
} }
} else if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoStreams())) { } else if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoStreams())) {
streamInfo.getVideoStreams().add(videoStream); videoStreams.add(videoStream);
} }
} }
} }
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
return new ParserResult(videoStreams, audioStreams, videoOnlyStreams);
} catch (Exception e) { } catch (Exception e) {
throw new DashMpdParsingException("Could not parse Dash mpd", e); throw new DashMpdParsingException("Could not parse Dash mpd", e);
} }

View File

@ -27,7 +27,7 @@ public class SoundcloudSubscriptionExtractorTest {
public static void setupClass() { public static void setupClass() {
NewPipe.init(Downloader.getInstance()); NewPipe.init(Downloader.getInstance());
subscriptionExtractor = new SoundcloudSubscriptionExtractor(ServiceList.SoundCloud); subscriptionExtractor = new SoundcloudSubscriptionExtractor(ServiceList.SoundCloud);
urlHandler = ServiceList.SoundCloud.getChannelUIHFactory(); urlHandler = ServiceList.SoundCloud.getChannelLHFactory();
} }
@Test @Test

View File

@ -8,8 +8,11 @@ import org.schabi.newpipe.extractor.NewPipe;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud; import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudSearchQueryHandlerFactory.PLAYLISTS;
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudSearchQueryHandlerFactory.TRACKS;
import static org.schabi.newpipe.extractor.services.soundcloud.SoundcloudSearchQueryHandlerFactory.USERS;
public class SoundcloudSearchQUHTest { public class SoundcloudSearchQHTest {
@BeforeClass @BeforeClass
public static void setUpClass() throws Exception { public static void setUpClass() throws Exception {
@ -24,50 +27,50 @@ public class SoundcloudSearchQUHTest {
@Test @Test
public void testRegularValues() throws Exception { public void testRegularValues() throws Exception {
assertEquals("https://api-v2.soundcloud.com/search?q=asdf&limit=10&offset=0", assertEquals("https://api-v2.soundcloud.com/search?q=asdf&limit=10&offset=0",
removeClientId(SoundCloud.getSearchQIHFactory().fromQuery("asdf").getUrl())); removeClientId(SoundCloud.getSearchQHFactory().fromQuery("asdf").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search?q=hans&limit=10&offset=0", assertEquals("https://api-v2.soundcloud.com/search?q=hans&limit=10&offset=0",
removeClientId(SoundCloud.getSearchQIHFactory().fromQuery("hans").getUrl())); removeClientId(SoundCloud.getSearchQHFactory().fromQuery("hans").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search?q=Poifj%26jaijf&limit=10&offset=0", assertEquals("https://api-v2.soundcloud.com/search?q=Poifj%26jaijf&limit=10&offset=0",
removeClientId(SoundCloud.getSearchQIHFactory().fromQuery("Poifj&jaijf").getUrl())); removeClientId(SoundCloud.getSearchQHFactory().fromQuery("Poifj&jaijf").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search?q=G%C3%BCl%C3%BCm&limit=10&offset=0", assertEquals("https://api-v2.soundcloud.com/search?q=G%C3%BCl%C3%BCm&limit=10&offset=0",
removeClientId(SoundCloud.getSearchQIHFactory().fromQuery("Gülüm").getUrl())); removeClientId(SoundCloud.getSearchQHFactory().fromQuery("Gülüm").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search?q=%3Fj%24%29H%C2%A7B&limit=10&offset=0", assertEquals("https://api-v2.soundcloud.com/search?q=%3Fj%24%29H%C2%A7B&limit=10&offset=0",
removeClientId(SoundCloud.getSearchQIHFactory().fromQuery("?j$)H§B").getUrl())); removeClientId(SoundCloud.getSearchQHFactory().fromQuery("?j$)H§B").getUrl()));
} }
@Test @Test
public void testGetContentFilter() throws Exception { public void testGetContentFilter() throws Exception {
assertEquals("tracks", SoundCloud.getSearchQIHFactory() assertEquals("tracks", SoundCloud.getSearchQHFactory()
.fromQuery("", asList(new String[]{"tracks"}), "").getContentFilters().get(0)); .fromQuery("", asList(new String[]{"tracks"}), "").getContentFilters().get(0));
assertEquals("users", SoundCloud.getSearchQIHFactory() assertEquals("users", SoundCloud.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{"users"}), "").getContentFilters().get(0)); .fromQuery("asdf", asList(new String[]{"users"}), "").getContentFilters().get(0));
} }
@Test @Test
public void testWithContentfilter() throws Exception { public void testWithContentfilter() throws Exception {
assertEquals("https://api-v2.soundcloud.com/search/tracks?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQIHFactory() assertEquals("https://api-v2.soundcloud.com/search/tracks?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{"tracks"}), "").getUrl())); .fromQuery("asdf", asList(new String[]{TRACKS}), "").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search/users?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQIHFactory() assertEquals("https://api-v2.soundcloud.com/search/users?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{"users"}), "").getUrl())); .fromQuery("asdf", asList(new String[]{USERS}), "").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search/playlists?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQIHFactory() assertEquals("https://api-v2.soundcloud.com/search/playlists?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{"playlist"}), "").getUrl())); .fromQuery("asdf", asList(new String[]{PLAYLISTS}), "").getUrl()));
assertEquals("https://api-v2.soundcloud.com/search?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQIHFactory() assertEquals("https://api-v2.soundcloud.com/search?q=asdf&limit=10&offset=0", removeClientId(SoundCloud.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{"fjiijie"}), "").getUrl())); .fromQuery("asdf", asList(new String[]{"fjiijie"}), "").getUrl()));
} }
@Test @Test
public void testGetAvailableContentFilter() { public void testGetAvailableContentFilter() {
final String[] contentFilter = SoundCloud.getSearchQIHFactory().getAvailableContentFilter(); final String[] contentFilter = SoundCloud.getSearchQHFactory().getAvailableContentFilter();
assertEquals(4, contentFilter.length); assertEquals(4, contentFilter.length);
assertEquals("tracks", contentFilter[0]); assertEquals("all", contentFilter[0]);
assertEquals("users", contentFilter[1]); assertEquals("tracks", contentFilter[1]);
assertEquals("playlist", contentFilter[2]); assertEquals("users", contentFilter[2]);
assertEquals("any", contentFilter[3]); assertEquals("playlists", contentFilter[3]);
} }
@Test @Test
public void testGetAvailableSortFilter() { public void testGetAvailableSortFilter() {
final String[] contentFilter = SoundCloud.getSearchQIHFactory().getAvailableSortFilter(); final String[] contentFilter = SoundCloud.getSearchQHFactory().getAvailableSortFilter();
assertEquals(0, contentFilter.length); assertEquals(0, contentFilter.length);
} }
} }

View File

@ -114,6 +114,103 @@ public class YoutubeChannelExtractorTest {
} }
} }
// Youtube RED/Premium ad blocking test
public static class VSauce implements BaseChannelExtractorTest {
private static YoutubeChannelExtractor extractor;
@BeforeClass
public static void setUp() throws Exception {
NewPipe.init(Downloader.getInstance());
extractor = (YoutubeChannelExtractor) YouTube
.getChannelExtractor("https://www.youtube.com/user/Vsauce");
extractor.fetchPage();
}
/*//////////////////////////////////////////////////////////////////////////
// Extractor
//////////////////////////////////////////////////////////////////////////*/
@Test
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
}
@Test
public void testName() throws Exception {
assertEquals("Vsauce", extractor.getName());
}
@Test
public void testId() throws Exception {
assertEquals("UC6nSFpj9HTCZ5t-N3Rm3-HA", extractor.getId());
}
@Test
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UC6nSFpj9HTCZ5t-N3Rm3-HA", extractor.getUrl());
}
@Test
public void testOriginalUrl() throws ParsingException {
assertEquals("https://www.youtube.com/user/Vsauce", extractor.getOriginalUrl());
}
/*//////////////////////////////////////////////////////////////////////////
// ListExtractor
//////////////////////////////////////////////////////////////////////////*/
@Test
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor, YouTube.getServiceId());
}
@Test
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor, ServiceList.YouTube.getServiceId());
}
/*//////////////////////////////////////////////////////////////////////////
// ChannelExtractor
//////////////////////////////////////////////////////////////////////////*/
@Test
public void testDescription() throws Exception {
assertTrue("What it actually was: " + extractor.getDescription(),
extractor.getDescription().contains("Our World is Amazing. Questions? Ideas? Tweet me:"));
}
@Test
public void testAvatarUrl() throws Exception {
String avatarUrl = extractor.getAvatarUrl();
assertIsSecureUrl(avatarUrl);
assertTrue(avatarUrl, avatarUrl.contains("yt3"));
}
@Test
public void testBannerUrl() throws Exception {
String bannerUrl = extractor.getBannerUrl();
assertIsSecureUrl(bannerUrl);
assertTrue(bannerUrl, bannerUrl.contains("yt3"));
}
@Test
public void testFeedUrl() throws Exception {
assertEquals("https://www.youtube.com/feeds/videos.xml?channel_id=UC6nSFpj9HTCZ5t-N3Rm3-HA", extractor.getFeedUrl());
}
@Test
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);
}
}
public static class Kurzgesagt implements BaseChannelExtractorTest { public static class Kurzgesagt implements BaseChannelExtractorTest {
private static YoutubeChannelExtractor extractor; private static YoutubeChannelExtractor extractor;

View File

@ -120,14 +120,14 @@ public class YoutubePlaylistExtractorTest {
} }
} }
public static class ImportantVideos implements BasePlaylistExtractorTest { public static class HugePlaylist implements BasePlaylistExtractorTest {
private static YoutubePlaylistExtractor extractor; private static YoutubePlaylistExtractor extractor;
@BeforeClass @BeforeClass
public static void setUp() throws Exception { public static void setUp() throws Exception {
NewPipe.init(Downloader.getInstance()); NewPipe.init(Downloader.getInstance());
extractor = (YoutubePlaylistExtractor) YouTube extractor = (YoutubePlaylistExtractor) YouTube
.getPlaylistExtractor("https://www.youtube.com/watch?v=lH1caqoAGe0&list=PL45xb3ujEhqUexNt53jb9WT2mS-uUaUrn"); .getPlaylistExtractor("https://www.youtube.com/watch?v=8SbUC-UaAxE&list=PLWwAypAcFRgKAIIFqBr9oy-ZYZnixa_Fj");
extractor.fetchPage(); extractor.fetchPage();
} }
@ -152,23 +152,23 @@ public class YoutubePlaylistExtractorTest {
@Test @Test
public void testName() throws Exception { public void testName() throws Exception {
String name = extractor.getName(); final String name = extractor.getName();
assertTrue(name, name.contains("Korrekte Aussprache - Lektion 1")); assertEquals("I Wanna Rock Super Gigantic Playlist 1: Hardrock, AOR, Metal and more !!! 5000 music videos !!!", name);
} }
@Test @Test
public void testId() throws Exception { public void testId() throws Exception {
assertEquals("PL45xb3ujEhqUexNt53jb9WT2mS-uUaUrn", extractor.getId()); assertEquals("PLWwAypAcFRgKAIIFqBr9oy-ZYZnixa_Fj", extractor.getId());
} }
@Test @Test
public void testUrl() throws ParsingException { public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/playlist?list=PL45xb3ujEhqUexNt53jb9WT2mS-uUaUrn", extractor.getUrl()); assertEquals("https://www.youtube.com/playlist?list=PLWwAypAcFRgKAIIFqBr9oy-ZYZnixa_Fj", extractor.getUrl());
} }
@Test @Test
public void testOriginalUrl() throws ParsingException { public void testOriginalUrl() throws ParsingException {
assertEquals("https://www.youtube.com/watch?v=lH1caqoAGe0&list=PL45xb3ujEhqUexNt53jb9WT2mS-uUaUrn", extractor.getOriginalUrl()); assertEquals("https://www.youtube.com/watch?v=8SbUC-UaAxE&list=PLWwAypAcFRgKAIIFqBr9oy-ZYZnixa_Fj", extractor.getOriginalUrl());
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -182,8 +182,10 @@ public class YoutubePlaylistExtractorTest {
@Test @Test
public void testMoreRelatedItems() throws Exception { public void testMoreRelatedItems() throws Exception {
ListExtractor.InfoItemsPage<StreamInfoItem> currentPage = defaultTestMoreItems(extractor, ServiceList.YouTube.getServiceId()); ListExtractor.InfoItemsPage<StreamInfoItem> currentPage
= defaultTestMoreItems(extractor, ServiceList.YouTube.getServiceId());
// Test for 2 more levels // Test for 2 more levels
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
currentPage = extractor.getPage(currentPage.getNextPageUrl()); currentPage = extractor.getPage(currentPage.getNextPageUrl());
defaultTestListOfItems(YouTube.getServiceId(), currentPage.getItems(), currentPage.getErrors()); defaultTestListOfItems(YouTube.getServiceId(), currentPage.getItems(), currentPage.getErrors());
@ -216,7 +218,7 @@ public class YoutubePlaylistExtractorTest {
@Test @Test
public void testUploaderName() throws Exception { public void testUploaderName() throws Exception {
assertEquals("Luksan Wunder", extractor.getUploaderName()); assertEquals("Tomas Nilsson", extractor.getUploaderName());
} }
@Test @Test

View File

@ -24,7 +24,7 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
/** /**
* Test for {@link YoutubeStreamLinkHandlerFactory} * Test for {@link YoutubeStreamLinkHandlerFactory}
*/ */
public class YoutubeStreamExtractorRestrictedTest { public class YoutubeStreamExtractorAgeRestrictedTest {
public static final String HTTPS = "https://"; public static final String HTTPS = "https://";
private static YoutubeStreamExtractor extractor; private static YoutubeStreamExtractor extractor;
@ -32,7 +32,7 @@ public class YoutubeStreamExtractorRestrictedTest {
public static void setUp() throws Exception { public static void setUp() throws Exception {
NewPipe.init(Downloader.getInstance()); NewPipe.init(Downloader.getInstance());
extractor = (YoutubeStreamExtractor) YouTube extractor = (YoutubeStreamExtractor) YouTube
.getStreamExtractor("https://www.youtube.com/watch?v=i6JTvzrpBy0"); .getStreamExtractor("https://www.youtube.com/watch?v=MmBeUZqv1QA");
extractor.fetchPage(); extractor.fetchPage();
} }

View File

@ -61,7 +61,7 @@ public class YoutubeStreamExtractorControversialTest {
@Test @Test
public void testGetDescription() throws ParsingException { public void testGetDescription() throws ParsingException {
assertNotNull(extractor.getDescription()); assertNotNull(extractor.getDescription());
assertFalse(extractor.getDescription().isEmpty()); // assertFalse(extractor.getDescription().isEmpty());
} }
@Test @Test
@ -112,13 +112,14 @@ public class YoutubeStreamExtractorControversialTest {
assertTrue(streams.size() > 0); assertTrue(streams.size() > 0);
} }
@Ignore
@Test @Test
public void testGetSubtitlesListDefault() throws IOException, ExtractionException { public void testGetSubtitlesListDefault() throws IOException, ExtractionException {
// Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null
assertTrue(!extractor.getSubtitlesDefault().isEmpty()); assertTrue(!extractor.getSubtitlesDefault().isEmpty());
} }
@Ignore
@Test @Test
public void testGetSubtitlesList() throws IOException, ExtractionException { public void testGetSubtitlesList() throws IOException, ExtractionException {
// Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null

View File

@ -0,0 +1,60 @@
package org.schabi.newpipe.extractor.services.youtube;
/*
* Created by Christian Schabesberger on 30.12.15.
*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* YoutubeVideoExtractorDefault.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
/**
* Test for {@link StreamExtractor}
*/
public class YoutubeStreamExtractorDASHTest {
private static StreamInfo info;
@BeforeClass
public static void setUp() throws Exception {
NewPipe.init(Downloader.getInstance());
info = StreamInfo.getInfo(YouTube, "https://www.youtube.com/watch?v=00Q4SUnVQK4");
}
@Test
public void testGetDashMpd() {
System.out.println(info.getDashMpdUrl());
assertTrue(info.getDashMpdUrl(),
info.getDashMpdUrl() != null && !info.getDashMpdUrl().isEmpty());
}
@Test
public void testDashMpdParser() {
assertEquals(0, info.getAudioStreams().size());
assertEquals(0, info.getVideoOnlyStreams().size());
assertEquals(4, info.getVideoStreams().size());
}
}

View File

@ -8,6 +8,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.*; import org.schabi.newpipe.extractor.stream.*;
import org.schabi.newpipe.extractor.utils.DashMpdParser;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import java.io.IOException; import java.io.IOException;
@ -15,6 +16,7 @@ import java.io.IOException;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
import static org.schabi.newpipe.extractor.ServiceList.YouTube; import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeTrendingExtractorTest.extractor;
/* /*
* Created by Christian Schabesberger on 30.12.15. * Created by Christian Schabesberger on 30.12.15.
@ -40,120 +42,161 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
* Test for {@link StreamExtractor} * Test for {@link StreamExtractor}
*/ */
public class YoutubeStreamExtractorDefaultTest { public class YoutubeStreamExtractorDefaultTest {
private static YoutubeStreamExtractor extractor;
@BeforeClass public static class AdeleHello {
public static void setUp() throws Exception { private static YoutubeStreamExtractor extractor;
NewPipe.init(Downloader.getInstance());
extractor = (YoutubeStreamExtractor) YouTube
.getStreamExtractor("https://www.youtube.com/watch?v=rYEDA3JcQqw");
extractor.fetchPage();
}
@Test @BeforeClass
public void testGetInvalidTimeStamp() throws ParsingException { public static void setUp() throws Exception {
assertTrue(extractor.getTimeStamp() + "", NewPipe.init(Downloader.getInstance());
extractor.getTimeStamp() <= 0); extractor = (YoutubeStreamExtractor) YouTube
} .getStreamExtractor("https://www.youtube.com/watch?v=rYEDA3JcQqw");
extractor.fetchPage();
}
@Test @Test
public void testGetValidTimeStamp() throws IOException, ExtractionException { public void testGetInvalidTimeStamp() throws ParsingException {
StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); assertTrue(extractor.getTimeStamp() + "",
assertEquals(extractor.getTimeStamp() + "", "174"); extractor.getTimeStamp() <= 0);
} }
@Test @Test
public void testGetTitle() throws ParsingException { public void testGetValidTimeStamp() throws ExtractionException {
assertFalse(extractor.getName().isEmpty()); StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174");
} assertEquals(extractor.getTimeStamp() + "", "174");
}
@Test @Test
public void testGetDescription() throws ParsingException { public void testGetTitle() throws ParsingException {
assertNotNull(extractor.getDescription()); assertFalse(extractor.getName().isEmpty());
assertFalse(extractor.getDescription().isEmpty()); }
}
@Test @Test
public void testGetUploaderName() throws ParsingException { public void testGetDescription() throws ParsingException {
assertNotNull(extractor.getUploaderName()); assertNotNull(extractor.getDescription());
assertFalse(extractor.getUploaderName().isEmpty()); assertFalse(extractor.getDescription().isEmpty());
} }
@Test
public void testGetFullLinksInDescriptlion() throws ParsingException {
assertTrue(extractor.getDescription().contains("http://smarturl.it/SubscribeAdele?IQid=yt"));
assertFalse(extractor.getDescription().contains("http://smarturl.it/SubscribeAdele?IQi..."));
}
@Test
public void testGetUploaderName() throws ParsingException {
assertNotNull(extractor.getUploaderName());
assertFalse(extractor.getUploaderName().isEmpty());
}
@Test @Test
public void testGetLength() throws ParsingException { public void testGetLength() throws ParsingException {
assertTrue(extractor.getLength() > 0); assertTrue(extractor.getLength() > 0);
} }
@Test @Test
public void testGetViewCount() throws ParsingException { public void testGetViewCount() throws ParsingException {
Long count = extractor.getViewCount(); Long count = extractor.getViewCount();
assertTrue(Long.toString(count), count >= /* specific to that video */ 1220025784); assertTrue(Long.toString(count), count >= /* specific to that video */ 1220025784);
} }
@Test @Test
public void testGetUploadDate() throws ParsingException { public void testGetUploadDate() throws ParsingException {
assertTrue(extractor.getUploadDate().length() > 0); assertTrue(extractor.getUploadDate().length() > 0);
} }
@Test @Test
public void testGetUploaderUrl() throws ParsingException { public void testGetUploaderUrl() throws ParsingException {
assertTrue(extractor.getUploaderUrl().length() > 0); assertTrue(extractor.getUploaderUrl().length() > 0);
} }
@Test @Test
public void testGetThumbnailUrl() throws ParsingException { public void testGetThumbnailUrl() throws ParsingException {
assertIsSecureUrl(extractor.getThumbnailUrl()); assertIsSecureUrl(extractor.getThumbnailUrl());
} }
@Test @Test
public void testGetUploaderAvatarUrl() throws ParsingException { public void testGetUploaderAvatarUrl() throws ParsingException {
assertIsSecureUrl(extractor.getUploaderAvatarUrl()); assertIsSecureUrl(extractor.getUploaderAvatarUrl());
} }
@Test @Test
public void testGetAudioStreams() throws IOException, ExtractionException { public void testGetAudioStreams() throws IOException, ExtractionException {
assertFalse(extractor.getAudioStreams().isEmpty()); assertFalse(extractor.getAudioStreams().isEmpty());
} }
@Test @Test
public void testGetVideoStreams() throws IOException, ExtractionException { public void testGetVideoStreams() throws IOException, ExtractionException {
for (VideoStream s : extractor.getVideoStreams()) { for (VideoStream s : extractor.getVideoStreams()) {
assertIsSecureUrl(s.url); assertIsSecureUrl(s.url);
assertTrue(s.resolution.length() > 0); assertTrue(s.resolution.length() > 0);
assertTrue(Integer.toString(s.getFormatId()), assertTrue(Integer.toString(s.getFormatId()),
0 <= s.getFormatId() && s.getFormatId() <= 4); 0 <= s.getFormatId() && s.getFormatId() <= 4);
}
}
@Test
public void testStreamType() throws ParsingException {
assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM);
}
@Test
public void testGetDashMpd() throws ParsingException {
// we dont expect this particular video to have a DASH file. For this purpouse we use a different test class.
assertTrue(extractor.getDashMpdUrl(),
extractor.getDashMpdUrl() != null && extractor.getDashMpdUrl().isEmpty());
}
@Test
public void testGetRelatedVideos() throws ExtractionException, IOException {
StreamInfoItemsCollector relatedVideos = extractor.getRelatedVideos();
Utils.printErrors(relatedVideos.getErrors());
assertFalse(relatedVideos.getItems().isEmpty());
assertTrue(relatedVideos.getErrors().isEmpty());
}
@Test
public void testGetSubtitlesListDefault() throws IOException, ExtractionException {
// Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null
assertTrue(extractor.getSubtitlesDefault().isEmpty());
}
@Test
public void testGetSubtitlesList() throws IOException, ExtractionException {
// Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null
assertTrue(extractor.getSubtitles(SubtitlesFormat.TTML).isEmpty());
} }
} }
@Test public static class DescriptionTestPewdiepie {
public void testStreamType() throws ParsingException { private static YoutubeStreamExtractor extractor;
assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM);
}
@Test @BeforeClass
public void testGetDashMpd() throws ParsingException { public static void setUp() throws Exception {
assertTrue(extractor.getDashMpdUrl(), NewPipe.init(Downloader.getInstance());
extractor.getDashMpdUrl() != null || !extractor.getDashMpdUrl().isEmpty()); extractor = (YoutubeStreamExtractor) YouTube
} .getStreamExtractor("https://www.youtube.com/watch?v=dJY8iT341F4");
extractor.fetchPage();
}
@Test @Test
public void testGetRelatedVideos() throws ExtractionException, IOException { public void testGetDescription() throws ParsingException {
StreamInfoItemsCollector relatedVideos = extractor.getRelatedVideos(); assertNotNull(extractor.getDescription());
Utils.printErrors(relatedVideos.getErrors()); assertFalse(extractor.getDescription().isEmpty());
assertFalse(relatedVideos.getItems().isEmpty()); }
assertTrue(relatedVideos.getErrors().isEmpty());
}
@Test @Test
public void testGetSubtitlesListDefault() throws IOException, ExtractionException { public void testGetFullLinksInDescriptlion() throws ParsingException {
// Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null assertTrue(extractor.getDescription().contains("https://www.reddit.com/r/PewdiepieSubmissions/"));
assertTrue(extractor.getSubtitlesDefault().isEmpty()); assertTrue(extractor.getDescription().contains("https://www.youtube.com/channel/UC3e8EMTOn4g6ZSKggHTnNng"));
}
@Test assertFalse(extractor.getDescription().contains("https://www.reddit.com/r/PewdiepieSub..."));
public void testGetSubtitlesList() throws IOException, ExtractionException { assertFalse(extractor.getDescription().contains("https://usa.clutchchairz.com/product/..."));
// Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null assertFalse(extractor.getDescription().contains("https://europe.clutchchairz.com/en/pr..."));
assertTrue(extractor.getSubtitles(SubtitlesFormat.TTML).isEmpty()); assertFalse(extractor.getDescription().contains("https://canada.clutchchairz.com/produ..."));
assertFalse(extractor.getDescription().contains("http://store.steampowered.com/app/703..."));
assertFalse(extractor.getDescription().contains("https://www.youtube.com/channel/UC3e8..."));
}
} }
} }

View File

@ -81,16 +81,6 @@ public class YoutubeStreamLinkHandlerFactoryTest {
assertEquals("jZViOEv90dI", urlIdHandler.fromUrl("vnd.youtube:jZViOEv90dI").getId()); assertEquals("jZViOEv90dI", urlIdHandler.fromUrl("vnd.youtube:jZViOEv90dI").getId());
} }
@Test
public void getIdfromSharedLinksYt() throws Exception {
String sharedId = "7JIArTByb3E";
String realId = "Q7JsK50NGaA";
assertEquals(realId, urlIdHandler.fromUrl("vnd.youtube://www.YouTube.com/shared?ci=" + sharedId + "&feature=twitter-deep-link").getId());
assertEquals(realId, urlIdHandler.fromUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId).getId());
assertEquals(realId, urlIdHandler.fromUrl("https://www.youtube.com/shared?ci=" + sharedId).getId());
}
@Test @Test
public void testAcceptYtUrl() throws ParsingException { public void testAcceptYtUrl() throws ParsingException {
assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/watch?v=jZViOEv90dI")); assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/watch?v=jZViOEv90dI"));
@ -111,14 +101,6 @@ public class YoutubeStreamLinkHandlerFactoryTest {
assertTrue(urlIdHandler.acceptUrl("vnd.youtube:jZViOEv90dI")); assertTrue(urlIdHandler.acceptUrl("vnd.youtube:jZViOEv90dI"));
} }
@Test
public void testAcceptSharedYtUrl() throws ParsingException {
String sharedId = "8A940MXKFmQ";
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId + "&feature=twitter-deep-link"));
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId));
assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/shared?ci=" + sharedId));
}
@Test @Test
public void testAcceptHookUrl() throws ParsingException { public void testAcceptHookUrl() throws ParsingException {
assertTrue(urlIdHandler.acceptUrl("https://hooktube.com/watch?v=TglNG-yjabU")); assertTrue(urlIdHandler.acceptUrl("https://hooktube.com/watch?v=TglNG-yjabU"));

View File

@ -29,7 +29,7 @@ public class YoutubeSubscriptionExtractorTest {
public static void setupClass() { public static void setupClass() {
NewPipe.init(Downloader.getInstance()); NewPipe.init(Downloader.getInstance());
subscriptionExtractor = new YoutubeSubscriptionExtractor(ServiceList.YouTube); subscriptionExtractor = new YoutubeSubscriptionExtractor(ServiceList.YouTube);
urlHandler = ServiceList.YouTube.getChannelUIHFactory(); urlHandler = ServiceList.YouTube.getChannelLHFactory();
} }
@Test @Test

View File

@ -0,0 +1,35 @@
package org.schabi.newpipe.extractor.services.youtube.search;
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.services.youtube.extractors.YoutubeSearchExtractor;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
import static java.util.Collections.singletonList;
import static junit.framework.TestCase.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
public class YoutubeSearchCountTest {
public static class YoutubeChannelViewCountTest extends YoutubeSearchExtractorBaseTest {
@BeforeClass
public static void setUpClass() throws Exception {
NewPipe.init(Downloader.getInstance());
extractor = (YoutubeSearchExtractor) YouTube.getSearchExtractor("pewdiepie",
singletonList(YoutubeSearchQueryHandlerFactory.CHANNELS), null,"de");
extractor.fetchPage();
itemsPage = extractor.getInitialPage();
}
@Test
public void testViewCount() throws Exception {
boolean foundKnownChannel = false;
ChannelInfoItem ci = (ChannelInfoItem) itemsPage.getItems().get(0);
assertTrue("Count does not fit: " + Long.toString(ci.getSubscriberCount()),
65043316 < ci.getSubscriberCount() && ci.getSubscriberCount() < 68043316);
}
}
}

View File

@ -0,0 +1,59 @@
package org.schabi.newpipe.extractor.services.youtube.search;
import org.junit.Test;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.CHANNELS;
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.PLAYLISTS;
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.VIDEOS;
public class YoutubeSearchQHTest {
@Test
public void testRegularValues() throws Exception {
assertEquals("https://www.youtube.com/results?q=asdf", YouTube.getSearchQHFactory().fromQuery("asdf").getUrl());
assertEquals("https://www.youtube.com/results?q=hans",YouTube.getSearchQHFactory().fromQuery("hans").getUrl());
assertEquals("https://www.youtube.com/results?q=Poifj%26jaijf", YouTube.getSearchQHFactory().fromQuery("Poifj&jaijf").getUrl());
assertEquals("https://www.youtube.com/results?q=G%C3%BCl%C3%BCm", YouTube.getSearchQHFactory().fromQuery("Gülüm").getUrl());
assertEquals("https://www.youtube.com/results?q=%3Fj%24%29H%C2%A7B", YouTube.getSearchQHFactory().fromQuery("?j$)H§B").getUrl());
}
@Test
public void testGetContentFilter() throws Exception {
assertEquals(VIDEOS, YouTube.getSearchQHFactory()
.fromQuery("", asList(new String[]{VIDEOS}), "").getContentFilters().get(0));
assertEquals(CHANNELS, YouTube.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{CHANNELS}), "").getContentFilters().get(0));
}
@Test
public void testWithContentfilter() throws Exception {
assertEquals("https://www.youtube.com/results?q=asdf&sp=EgIQAVAU", YouTube.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{VIDEOS}), "").getUrl());
assertEquals("https://www.youtube.com/results?q=asdf&sp=EgIQAlAU", YouTube.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{CHANNELS}), "").getUrl());
assertEquals("https://www.youtube.com/results?q=asdf&sp=EgIQA1AU", YouTube.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{PLAYLISTS}), "").getUrl());
assertEquals("https://www.youtube.com/results?q=asdf", YouTube.getSearchQHFactory()
.fromQuery("asdf", asList(new String[]{"fjiijie"}), "").getUrl());
}
@Test
public void testGetAvailableContentFilter() {
final String[] contentFilter = YouTube.getSearchQHFactory().getAvailableContentFilter();
assertEquals(4, contentFilter.length);
assertEquals("all", contentFilter[0]);
assertEquals("videos", contentFilter[1]);
assertEquals("channels", contentFilter[2]);
assertEquals("playlists", contentFilter[3]);
}
@Test
public void testGetAvailableSortFilter() {
final String[] contentFilter = YouTube.getSearchQHFactory().getAvailableSortFilter();
assertEquals(0, contentFilter.length);
}
}

View File

@ -1,55 +0,0 @@
package org.schabi.newpipe.extractor.services.youtube.search;
import org.junit.Test;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
public class YoutubeSearchQUHTest {
@Test
public void testRegularValues() throws Exception {
assertEquals("https://www.youtube.com/results?q=asdf", YouTube.getSearchQIHFactory().fromQuery("asdf").getUrl());
assertEquals("https://www.youtube.com/results?q=hans",YouTube.getSearchQIHFactory().fromQuery("hans").getUrl());
assertEquals("https://www.youtube.com/results?q=Poifj%26jaijf", YouTube.getSearchQIHFactory().fromQuery("Poifj&jaijf").getUrl());
assertEquals("https://www.youtube.com/results?q=G%C3%BCl%C3%BCm", YouTube.getSearchQIHFactory().fromQuery("Gülüm").getUrl());
assertEquals("https://www.youtube.com/results?q=%3Fj%24%29H%C2%A7B", YouTube.getSearchQIHFactory().fromQuery("?j$)H§B").getUrl());
}
@Test
public void testGetContentFilter() throws Exception {
assertEquals("stream", YouTube.getSearchQIHFactory()
.fromQuery("", asList(new String[]{"stream"}), "").getContentFilters().get(0));
assertEquals("channel", YouTube.getSearchQIHFactory()
.fromQuery("asdf", asList(new String[]{"channel"}), "").getContentFilters().get(0));
}
@Test
public void testWithContentfilter() throws Exception {
assertEquals("https://www.youtube.com/results?q=asdf&sp=EgIQAVAU", YouTube.getSearchQIHFactory()
.fromQuery("asdf", asList(new String[]{"stream"}), "").getUrl());
assertEquals("https://www.youtube.com/results?q=asdf&sp=EgIQAlAU", YouTube.getSearchQIHFactory()
.fromQuery("asdf", asList(new String[]{"channel"}), "").getUrl());
assertEquals("https://www.youtube.com/results?q=asdf&sp=EgIQA1AU", YouTube.getSearchQIHFactory()
.fromQuery("asdf", asList(new String[]{"playlist"}), "").getUrl());
assertEquals("https://www.youtube.com/results?q=asdf", YouTube.getSearchQIHFactory()
.fromQuery("asdf", asList(new String[]{"fjiijie"}), "").getUrl());
}
@Test
public void testGetAvailableContentFilter() {
final String[] contentFilter = YouTube.getSearchQIHFactory().getAvailableContentFilter();
assertEquals(4, contentFilter.length);
assertEquals("stream", contentFilter[0]);
assertEquals("channel", contentFilter[1]);
assertEquals("playlist", contentFilter[2]);
assertEquals("any", contentFilter[3]);
}
@Test
public void testGetAvailableSortFilter() {
final String[] contentFilter = YouTube.getSearchQIHFactory().getAvailableSortFilter();
assertEquals(0, contentFilter.length);
}
}