Merge branch 'bugfix-dont-call-fetch-page-in-constructor' of https://github.com/coffeemakr/NewPipeExtractor into f
This commit is contained in:
commit
18e486da30
|
@ -24,4 +24,12 @@ task sourcesJar(type: Jar, dependsOn: classes) {
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
archives sourcesJar
|
archives sourcesJar
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
testLogging {
|
||||||
|
events "skipped", "failed"
|
||||||
|
showStandardStreams = true
|
||||||
|
exceptionFormat = 'full'
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -33,12 +33,16 @@ public abstract class Extractor {
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private String cleanUrl;
|
private String cleanUrl;
|
||||||
|
private boolean pageFetched = false;
|
||||||
|
private final Downloader downloader;
|
||||||
|
|
||||||
public Extractor(StreamingService service, String url) throws ExtractionException {
|
public Extractor(StreamingService service, String url) throws ExtractionException {
|
||||||
if(service == null) throw new NullPointerException("service is null");
|
if(service == null) throw new NullPointerException("service is null");
|
||||||
if(url == null) throw new NullPointerException("url is null");
|
if(url == null) throw new NullPointerException("url is null");
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.originalUrl = url;
|
this.originalUrl = url;
|
||||||
|
this.downloader = NewPipe.getDownloader();
|
||||||
|
if(downloader == null) throw new NullPointerException("downloader is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,8 +53,26 @@ public abstract class Extractor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the current page.
|
* Fetch the current page.
|
||||||
|
* @throws IOException if the page can not be loaded
|
||||||
|
* @throws ExtractionException if the pages content is not understood
|
||||||
*/
|
*/
|
||||||
public abstract void fetchPage() throws IOException, ExtractionException;
|
public void fetchPage() throws IOException, ExtractionException {
|
||||||
|
if(pageFetched) return;
|
||||||
|
onFetchPage(downloader);
|
||||||
|
pageFetched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertPageFetched() {
|
||||||
|
if(!pageFetched) throw new IllegalStateException("Page is not fetched. Make sure you call fetchPage()");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the current page.
|
||||||
|
* @param downloader the download to use
|
||||||
|
* @throws IOException if the page can not be loaded
|
||||||
|
* @throws ExtractionException if the pages content is not understood
|
||||||
|
*/
|
||||||
|
public abstract void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException;
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public abstract String getId() throws ParsingException;
|
public abstract String getId() throws ParsingException;
|
||||||
|
|
|
@ -16,7 +16,7 @@ public abstract class Info implements Serializable {
|
||||||
public final String url;
|
public final String url;
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
public List<Throwable> errors = new ArrayList<>();
|
public final List<Throwable> errors = new ArrayList<>();
|
||||||
|
|
||||||
public void addError(Throwable throwable) {
|
public void addError(Throwable throwable) {
|
||||||
this.errors.add(throwable);
|
this.errors.add(throwable);
|
||||||
|
|
|
@ -3,9 +3,10 @@ package org.schabi.newpipe.extractor;
|
||||||
import org.schabi.newpipe.extractor.stream.SubtitlesFormat;
|
import org.schabi.newpipe.extractor.stream.SubtitlesFormat;
|
||||||
|
|
||||||
public class Subtitles {
|
public class Subtitles {
|
||||||
private SubtitlesFormat format;
|
private final SubtitlesFormat format;
|
||||||
private String languageCode, URL;
|
private final String languageCode;
|
||||||
private boolean autoGenerated;
|
private final String URL;
|
||||||
|
private final boolean autoGenerated;
|
||||||
|
|
||||||
public Subtitles(SubtitlesFormat format, String languageCode, String URL, boolean autoGenerated) {
|
public Subtitles(SubtitlesFormat format, String languageCode, String URL, boolean autoGenerated) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.List;
|
||||||
|
|
||||||
public abstract class SuggestionExtractor {
|
public abstract class SuggestionExtractor {
|
||||||
|
|
||||||
private int serviceId;
|
private final int serviceId;
|
||||||
|
|
||||||
public SuggestionExtractor(int serviceId) {
|
public SuggestionExtractor(int serviceId) {
|
||||||
this.serviceId = serviceId;
|
this.serviceId = serviceId;
|
||||||
|
|
|
@ -30,7 +30,7 @@ import java.io.IOException;
|
||||||
|
|
||||||
public abstract class KioskExtractor extends ListExtractor {
|
public abstract class KioskExtractor extends ListExtractor {
|
||||||
private String contentCountry = null;
|
private String contentCountry = null;
|
||||||
private String id = null;
|
private final String id;
|
||||||
|
|
||||||
public KioskExtractor(StreamingService streamingService,
|
public KioskExtractor(StreamingService streamingService,
|
||||||
String url,
|
String url,
|
||||||
|
|
|
@ -19,8 +19,8 @@ public class KioskList {
|
||||||
throws ExtractionException, IOException;
|
throws ExtractionException, IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int service_id;
|
private final int service_id;
|
||||||
private HashMap<String, KioskEntry> kioskList = new HashMap<>();
|
private final HashMap<String, KioskEntry> kioskList = new HashMap<>();
|
||||||
private String defaultKiosk = null;
|
private String defaultKiosk = null;
|
||||||
|
|
||||||
private class KioskEntry {
|
private class KioskEntry {
|
||||||
|
@ -28,8 +28,8 @@ public class KioskList {
|
||||||
extractorFactory = ef;
|
extractorFactory = ef;
|
||||||
handler = h;
|
handler = h;
|
||||||
}
|
}
|
||||||
KioskExtractorFactory extractorFactory;
|
final KioskExtractorFactory extractorFactory;
|
||||||
UrlIdHandler handler;
|
final UrlIdHandler handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KioskList(int service_id) {
|
public KioskList(int service_id) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ public abstract class SearchEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private InfoItemSearchCollector collector;
|
private final InfoItemSearchCollector collector;
|
||||||
|
|
||||||
public SearchEngine(int serviceId) {
|
public SearchEngine(int serviceId) {
|
||||||
collector = new InfoItemSearchCollector(serviceId);
|
collector = new InfoItemSearchCollector(serviceId);
|
||||||
|
|
|
@ -24,14 +24,13 @@ public class SoundcloudChannelExtractor extends ChannelExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
Downloader dl = NewPipe.getDownloader();
|
|
||||||
|
|
||||||
userId = getUrlIdHandler().getId(getOriginalUrl());
|
userId = getUrlIdHandler().getId(getOriginalUrl());
|
||||||
String apiUrl = "https://api.soundcloud.com/users/" + userId +
|
String apiUrl = "https://api.soundcloud.com/users/" + userId +
|
||||||
"?client_id=" + SoundcloudParsingHelper.clientId();
|
"?client_id=" + SoundcloudParsingHelper.clientId();
|
||||||
|
|
||||||
String response = dl.download(apiUrl);
|
String response = downloader.download(apiUrl);
|
||||||
try {
|
try {
|
||||||
user = JsonParser.object().from(response);
|
user = JsonParser.object().from(response);
|
||||||
} catch (JsonParserException e) {
|
} catch (JsonParserException e) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.grack.nanojson.JsonObject;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||||
|
|
||||||
public class SoundcloudChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
public class SoundcloudChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
||||||
private JsonObject searchResult;
|
private final JsonObject searchResult;
|
||||||
|
|
||||||
public SoundcloudChannelInfoItemExtractor(JsonObject searchResult) {
|
public SoundcloudChannelInfoItemExtractor(JsonObject searchResult) {
|
||||||
this.searchResult = searchResult;
|
this.searchResult = searchResult;
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.Downloader;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.UrlIdHandler;
|
import org.schabi.newpipe.extractor.UrlIdHandler;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
@ -23,7 +24,7 @@ public class SoundcloudChartsExtractor extends KioskExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() {
|
public void onFetchPage(@Nonnull Downloader downloader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
|
|
@ -67,13 +67,13 @@ public class SoundcloudParsingHelper {
|
||||||
*
|
*
|
||||||
* See https://developers.soundcloud.com/docs/api/reference#resolve
|
* See https://developers.soundcloud.com/docs/api/reference#resolve
|
||||||
*/
|
*/
|
||||||
public static JsonObject resolveFor(String url) throws IOException, ReCaptchaException, ParsingException {
|
public static JsonObject resolveFor(Downloader downloader, String url) throws IOException, ReCaptchaException, ParsingException {
|
||||||
String apiUrl = "https://api.soundcloud.com/resolve"
|
String apiUrl = "https://api.soundcloud.com/resolve"
|
||||||
+ "?url=" + URLEncoder.encode(url, "UTF-8")
|
+ "?url=" + URLEncoder.encode(url, "UTF-8")
|
||||||
+ "&client_id=" + clientId();
|
+ "&client_id=" + clientId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return JsonParser.object().from(NewPipe.getDownloader().download(apiUrl));
|
return JsonParser.object().from(downloader.download(apiUrl));
|
||||||
} catch (JsonParserException e) {
|
} catch (JsonParserException e) {
|
||||||
throw new ParsingException("Could not parse json response", e);
|
throw new ParsingException("Could not parse json response", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,14 @@ public class SoundcloudPlaylistExtractor extends PlaylistExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
Downloader dl = NewPipe.getDownloader();
|
|
||||||
|
|
||||||
playlistId = getUrlIdHandler().getId(getOriginalUrl());
|
playlistId = getUrlIdHandler().getId(getOriginalUrl());
|
||||||
String apiUrl = "https://api.soundcloud.com/playlists/" + playlistId +
|
String apiUrl = "https://api.soundcloud.com/playlists/" + playlistId +
|
||||||
"?client_id=" + SoundcloudParsingHelper.clientId() +
|
"?client_id=" + SoundcloudParsingHelper.clientId() +
|
||||||
"&representation=compact";
|
"&representation=compact";
|
||||||
|
|
||||||
String response = dl.download(apiUrl);
|
String response = downloader.download(apiUrl);
|
||||||
try {
|
try {
|
||||||
playlist = JsonParser.object().from(response);
|
playlist = JsonParser.object().from(response);
|
||||||
} catch (JsonParserException e) {
|
} catch (JsonParserException e) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ public class SoundcloudPlaylistInfoItemExtractor implements PlaylistInfoItemExtr
|
||||||
private static final String AVATAR_URL_KEY = "avatar_url";
|
private static final String AVATAR_URL_KEY = "avatar_url";
|
||||||
private static final String ARTWORK_URL_KEY = "artwork_url";
|
private static final String ARTWORK_URL_KEY = "artwork_url";
|
||||||
|
|
||||||
private JsonObject searchResult;
|
private final JsonObject searchResult;
|
||||||
|
|
||||||
public SoundcloudPlaylistInfoItemExtractor(JsonObject searchResult) {
|
public SoundcloudPlaylistInfoItemExtractor(JsonObject searchResult) {
|
||||||
this.searchResult = searchResult;
|
this.searchResult = searchResult;
|
||||||
|
|
|
@ -21,12 +21,11 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
public SoundcloudStreamExtractor(StreamingService service, String url) throws IOException, ExtractionException {
|
public SoundcloudStreamExtractor(StreamingService service, String url) throws IOException, ExtractionException {
|
||||||
super(service, url);
|
super(service, url);
|
||||||
fetchPage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
track = SoundcloudParsingHelper.resolveFor(getOriginalUrl());
|
track = SoundcloudParsingHelper.resolveFor(downloader, getOriginalUrl());
|
||||||
|
|
||||||
String policy = track.getString("policy", "");
|
String policy = track.getString("policy", "");
|
||||||
if (!policy.equals("ALLOW") && !policy.equals("MONETIZE")) {
|
if (!policy.equals("ALLOW") && !policy.equals("MONETIZE")) {
|
||||||
|
|
|
@ -146,8 +146,8 @@ public class ItagItem {
|
||||||
return mediaFormat;
|
return mediaFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int id;
|
public final int id;
|
||||||
public ItagType itagType;
|
public final ItagType itagType;
|
||||||
|
|
||||||
// Audio fields
|
// Audio fields
|
||||||
public int avgBitrate = -1;
|
public int avgBitrate = -1;
|
||||||
|
|
|
@ -59,9 +59,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
Downloader downloader = NewPipe.getDownloader();
|
|
||||||
|
|
||||||
String channelUrl = super.getCleanUrl() + CHANNEL_URL_PARAMETERS;
|
String channelUrl = super.getCleanUrl() + CHANNEL_URL_PARAMETERS;
|
||||||
String pageContent = downloader.download(channelUrl);
|
String pageContent = downloader.download(channelUrl);
|
||||||
doc = Jsoup.parse(pageContent, channelUrl);
|
doc = Jsoup.parse(pageContent, channelUrl);
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
||||||
private Element el;
|
private final Element el;
|
||||||
|
|
||||||
public YoutubeChannelInfoItemExtractor(Element el) {
|
public YoutubeChannelInfoItemExtractor(Element el) {
|
||||||
this.el = el;
|
this.el = el;
|
||||||
|
|
|
@ -36,9 +36,7 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
Downloader downloader = NewPipe.getDownloader();
|
|
||||||
|
|
||||||
String pageContent = downloader.download(getCleanUrl());
|
String pageContent = downloader.download(getCleanUrl());
|
||||||
doc = Jsoup.parse(pageContent, getCleanUrl());
|
doc = Jsoup.parse(pageContent, getCleanUrl());
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
public class YoutubePlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
|
public class YoutubePlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
|
||||||
private Element el;
|
private final Element el;
|
||||||
|
|
||||||
public YoutubePlaylistInfoItemExtractor(Element el) {
|
public YoutubePlaylistInfoItemExtractor(Element el) {
|
||||||
this.el = el;
|
this.el = el;
|
||||||
|
|
|
@ -86,7 +86,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
public YoutubeStreamExtractor(StreamingService service, String url) throws IOException, ExtractionException {
|
public YoutubeStreamExtractor(StreamingService service, String url) throws IOException, ExtractionException {
|
||||||
super(service, url);
|
super(service, url);
|
||||||
fetchPage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -106,6 +105,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getName() throws ParsingException {
|
public String getName() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
String name = getStringFromMetaData("title");
|
String name = getStringFromMetaData("title");
|
||||||
if(name == null) {
|
if(name == null) {
|
||||||
// Fallback to HTML method
|
// Fallback to HTML method
|
||||||
|
@ -124,6 +124,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUploadDate() throws ParsingException {
|
public String getUploadDate() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
return doc.select("meta[itemprop=datePublished]").attr(CONTENT);
|
return doc.select("meta[itemprop=datePublished]").attr(CONTENT);
|
||||||
} catch (Exception e) {//todo: add fallback method
|
} catch (Exception e) {//todo: add fallback method
|
||||||
|
@ -134,6 +135,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getThumbnailUrl() throws ParsingException {
|
public String getThumbnailUrl() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
// Try to get high resolution thumbnail first, if it fails, use low res from the player instead
|
// Try to get high resolution thumbnail first, if it fails, use low res from the player instead
|
||||||
try {
|
try {
|
||||||
return doc.select("link[itemprop=\"thumbnailUrl\"]").first().attr("abs:href");
|
return doc.select("link[itemprop=\"thumbnailUrl\"]").first().attr("abs:href");
|
||||||
|
@ -157,6 +159,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() throws ParsingException {
|
public String getDescription() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
return doc.select("p[id=\"eow-description\"]").first().html();
|
return 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) {//todo: add fallback method <-- there is no ... as long as i know
|
||||||
|
@ -166,6 +169,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAgeLimit() throws ParsingException {
|
public int getAgeLimit() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
if (!isAgeRestricted) {
|
if (!isAgeRestricted) {
|
||||||
return NO_AGE_LIMIT;
|
return NO_AGE_LIMIT;
|
||||||
}
|
}
|
||||||
|
@ -179,6 +183,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() throws ParsingException {
|
public long getLength() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
if(playerArgs != null) {
|
if(playerArgs != null) {
|
||||||
try {
|
try {
|
||||||
long returnValue = Long.parseLong(playerArgs.get("length_seconds") + "");
|
long returnValue = Long.parseLong(playerArgs.get("length_seconds") + "");
|
||||||
|
@ -217,6 +222,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getViewCount() throws ParsingException {
|
public long getViewCount() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
return Long.parseLong(doc.select("meta[itemprop=interactionCount]").attr(CONTENT));
|
return Long.parseLong(doc.select("meta[itemprop=interactionCount]").attr(CONTENT));
|
||||||
} catch (Exception e) {//todo: find fallback method
|
} catch (Exception e) {//todo: find fallback method
|
||||||
|
@ -226,6 +232,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLikeCount() throws ParsingException {
|
public long getLikeCount() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
String likesString = "";
|
String likesString = "";
|
||||||
try {
|
try {
|
||||||
Element button = doc.select("button.like-button-renderer-like-button").first();
|
Element button = doc.select("button.like-button-renderer-like-button").first();
|
||||||
|
@ -245,6 +252,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getDislikeCount() throws ParsingException {
|
public long getDislikeCount() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
String dislikesString = "";
|
String dislikesString = "";
|
||||||
try {
|
try {
|
||||||
Element button = doc.select("button.like-button-renderer-dislike-button").first();
|
Element button = doc.select("button.like-button-renderer-dislike-button").first();
|
||||||
|
@ -265,6 +273,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderUrl() throws ParsingException {
|
public String getUploaderUrl() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
return doc.select("div[class=\"yt-user-info\"]").first().children()
|
return doc.select("div[class=\"yt-user-info\"]").first().children()
|
||||||
.select("a").first().attr("abs:href");
|
.select("a").first().attr("abs:href");
|
||||||
|
@ -276,6 +285,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String getStringFromMetaData(String field) {
|
private String getStringFromMetaData(String field) {
|
||||||
|
assertPageFetched();
|
||||||
String value = null;
|
String value = null;
|
||||||
if(playerArgs != null) {
|
if(playerArgs != null) {
|
||||||
// This can not fail
|
// This can not fail
|
||||||
|
@ -291,6 +301,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderName() throws ParsingException {
|
public String getUploaderName() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
String name = getStringFromMetaData("author");
|
String name = getStringFromMetaData("author");
|
||||||
|
|
||||||
if(name == null) {
|
if(name == null) {
|
||||||
|
@ -310,6 +321,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderAvatarUrl() throws ParsingException {
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
return doc.select("a[class*=\"yt-user-photo\"]").first()
|
return doc.select("a[class*=\"yt-user-photo\"]").first()
|
||||||
.select("img").first()
|
.select("img").first()
|
||||||
|
@ -321,6 +333,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDashMpdUrl() throws ParsingException {
|
public String getDashMpdUrl() throws ParsingException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
String dashManifestUrl;
|
String dashManifestUrl;
|
||||||
if (videoInfoPage.containsKey("dashmpd")) {
|
if (videoInfoPage.containsKey("dashmpd")) {
|
||||||
|
@ -347,6 +360,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AudioStream> getAudioStreams() throws IOException, ExtractionException {
|
public List<AudioStream> getAudioStreams() throws IOException, ExtractionException {
|
||||||
|
assertPageFetched();
|
||||||
List<AudioStream> audioStreams = new ArrayList<>();
|
List<AudioStream> audioStreams = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
for (Map.Entry<String, ItagItem> entry : getItags(ADAPTIVE_FMTS, ItagItem.ItagType.AUDIO).entrySet()) {
|
for (Map.Entry<String, ItagItem> entry : getItags(ADAPTIVE_FMTS, ItagItem.ItagType.AUDIO).entrySet()) {
|
||||||
|
@ -366,6 +380,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VideoStream> getVideoStreams() throws IOException, ExtractionException {
|
public List<VideoStream> getVideoStreams() throws IOException, ExtractionException {
|
||||||
|
assertPageFetched();
|
||||||
List<VideoStream> videoStreams = new ArrayList<>();
|
List<VideoStream> videoStreams = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
for (Map.Entry<String, ItagItem> entry : getItags(URL_ENCODED_FMT_STREAM_MAP, ItagItem.ItagType.VIDEO).entrySet()) {
|
for (Map.Entry<String, ItagItem> entry : getItags(URL_ENCODED_FMT_STREAM_MAP, ItagItem.ItagType.VIDEO).entrySet()) {
|
||||||
|
@ -385,6 +400,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VideoStream> getVideoOnlyStreams() throws IOException, ExtractionException {
|
public List<VideoStream> getVideoOnlyStreams() throws IOException, ExtractionException {
|
||||||
|
assertPageFetched();
|
||||||
List<VideoStream> videoOnlyStreams = new ArrayList<>();
|
List<VideoStream> videoOnlyStreams = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
for (Map.Entry<String, ItagItem> entry : getItags(ADAPTIVE_FMTS, ItagItem.ItagType.VIDEO_ONLY).entrySet()) {
|
for (Map.Entry<String, ItagItem> entry : getItags(ADAPTIVE_FMTS, ItagItem.ItagType.VIDEO_ONLY).entrySet()) {
|
||||||
|
@ -411,11 +427,13 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public List<Subtitles> getSubtitles(SubtitlesFormat format) throws IOException, ExtractionException {
|
public List<Subtitles> getSubtitles(SubtitlesFormat format) throws IOException, ExtractionException {
|
||||||
|
assertPageFetched();
|
||||||
if(isAgeRestricted) {
|
if(isAgeRestricted) {
|
||||||
// If the video is age restricted getPlayerConfig will fail
|
// If the video is age restricted getPlayerConfig will fail
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
JsonObject playerConfig = getPlayerConfig(getPageHtml());
|
// TODO: This should be done in onFetchPage()
|
||||||
|
JsonObject playerConfig = getPlayerConfig(getPageHtml(NewPipe.getDownloader()));
|
||||||
String playerResponse = playerConfig.getObject("args").getString("player_response");
|
String playerResponse = playerConfig.getObject("args").getString("player_response");
|
||||||
|
|
||||||
JsonObject captions;
|
JsonObject captions;
|
||||||
|
@ -459,6 +477,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamInfoItem getNextVideo() throws IOException, ExtractionException {
|
public StreamInfoItem getNextVideo() throws IOException, ExtractionException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
StreamInfoItemCollector collector = new StreamInfoItemCollector(getServiceId());
|
StreamInfoItemCollector collector = new StreamInfoItemCollector(getServiceId());
|
||||||
collector.commit(extractVideoPreviewInfo(doc.select("div[class=\"watch-sidebar-section\"]")
|
collector.commit(extractVideoPreviewInfo(doc.select("div[class=\"watch-sidebar-section\"]")
|
||||||
|
@ -472,6 +491,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamInfoItemCollector getRelatedVideos() throws IOException, ExtractionException {
|
public StreamInfoItemCollector getRelatedVideos() throws IOException, ExtractionException {
|
||||||
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
StreamInfoItemCollector collector = new StreamInfoItemCollector(getServiceId());
|
StreamInfoItemCollector collector = new StreamInfoItemCollector(getServiceId());
|
||||||
Element ul = doc.select("ul[id=\"watch-related\"]").first();
|
Element ul = doc.select("ul[id=\"watch-related\"]").first();
|
||||||
|
@ -526,30 +546,27 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
private static final String GET_VIDEO_INFO_URL = "https://www.youtube.com/get_video_info?video_id=" + "%s" +
|
private static final String GET_VIDEO_INFO_URL = "https://www.youtube.com/get_video_info?video_id=" + "%s" +
|
||||||
"&el=info&ps=default&eurl=&gl=US&hl=en";
|
"&el=info&ps=default&eurl=&gl=US&hl=en";
|
||||||
|
|
||||||
private static volatile String decryptionCode = "";
|
private volatile String decryptionCode = "";
|
||||||
|
|
||||||
private static String pageHtml = null;
|
private String pageHtml = null;
|
||||||
|
|
||||||
private String getPageHtml() throws IOException, ExtractionException{
|
private String getPageHtml(Downloader downloader) throws IOException, ExtractionException{
|
||||||
if (pageHtml == null) {
|
if (pageHtml == null) {
|
||||||
Downloader dl = NewPipe.getDownloader();
|
pageHtml = downloader.download(getCleanUrl());
|
||||||
pageHtml = dl.download(getCleanUrl());
|
|
||||||
}
|
}
|
||||||
return pageHtml;
|
return pageHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
Downloader dl = NewPipe.getDownloader();
|
String pageContent = getPageHtml(downloader);
|
||||||
|
|
||||||
String pageContent = getPageHtml();
|
|
||||||
doc = Jsoup.parse(pageContent, getCleanUrl());
|
doc = Jsoup.parse(pageContent, getCleanUrl());
|
||||||
|
|
||||||
|
|
||||||
String playerUrl;
|
String playerUrl;
|
||||||
// Check if the video is age restricted
|
// Check if the video is age restricted
|
||||||
if (pageContent.contains("<meta property=\"og:restrictions:age")) {
|
if (pageContent.contains("<meta property=\"og:restrictions:age")) {
|
||||||
String infoPageResponse = dl.download(String.format(GET_VIDEO_INFO_URL, getId()));
|
String infoPageResponse = downloader.download(String.format(GET_VIDEO_INFO_URL, getId()));
|
||||||
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
|
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
|
||||||
playerUrl = getPlayerUrlFromRestrictedVideo();
|
playerUrl = getPlayerUrlFromRestrictedVideo();
|
||||||
isAgeRestricted = true;
|
isAgeRestricted = true;
|
||||||
|
|
|
@ -42,9 +42,7 @@ public class YoutubeTrendingExtractor extends KioskExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetchPage() throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
Downloader downloader = NewPipe.getDownloader();
|
|
||||||
|
|
||||||
final String contentCountry = getContentCountry();
|
final String contentCountry = getContentCountry();
|
||||||
String url = getCleanUrl();
|
String url = getCleanUrl();
|
||||||
if(contentCountry != null && !contentCountry.isEmpty()) {
|
if(contentCountry != null && !contentCountry.isEmpty()) {
|
||||||
|
|
|
@ -236,7 +236,8 @@ public class StreamInfo extends Info {
|
||||||
* Fills out the video info fields which are common to all services.
|
* Fills out the video info fields which are common to all services.
|
||||||
* Probably needs to be overridden by subclasses
|
* Probably needs to be overridden by subclasses
|
||||||
*/
|
*/
|
||||||
public static StreamInfo getInfo(StreamExtractor extractor) throws ExtractionException {
|
private static StreamInfo getInfo(StreamExtractor extractor) throws ExtractionException, IOException {
|
||||||
|
extractor.fetchPage();
|
||||||
StreamInfo streamInfo;
|
StreamInfo streamInfo;
|
||||||
try {
|
try {
|
||||||
streamInfo = extractImportantData(extractor);
|
streamInfo = extractImportantData(extractor);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package org.schabi.newpipe.extractor.stream;
|
package org.schabi.newpipe.extractor.stream;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.Subtitles;
|
|
||||||
|
|
||||||
public enum SubtitlesFormat {
|
public enum SubtitlesFormat {
|
||||||
// YouTube subtitles formats
|
// YouTube subtitles formats
|
||||||
// TRANSCRIPT(3) is default YT format based on TTML,
|
// TRANSCRIPT(3) is default YT format based on TTML,
|
||||||
|
@ -13,8 +11,8 @@ public enum SubtitlesFormat {
|
||||||
TRANSCRIPT2 (0x3, "srv2"),
|
TRANSCRIPT2 (0x3, "srv2"),
|
||||||
TRANSCRIPT3 (0x4, "srv3");
|
TRANSCRIPT3 (0x4, "srv3");
|
||||||
|
|
||||||
private int id;
|
private final int id;
|
||||||
private String extension;
|
private final String extension;
|
||||||
|
|
||||||
SubtitlesFormat(int id, String extension) {
|
SubtitlesFormat(int id, String extension) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
|
@ -23,8 +23,8 @@ package org.schabi.newpipe.extractor.stream;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
|
|
||||||
public class VideoStream extends Stream {
|
public class VideoStream extends Stream {
|
||||||
public String resolution;
|
public final String resolution;
|
||||||
public boolean isVideoOnly;
|
public final boolean isVideoOnly;
|
||||||
|
|
||||||
|
|
||||||
public VideoStream(String url, MediaFormat format, String resolution) {
|
public VideoStream(String url, MediaFormat format, String resolution) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.io.InputStreamReader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class SoundcloudStreamExtractorDefaultTest {
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
NewPipe.init(Downloader.getInstance());
|
NewPipe.init(Downloader.getInstance());
|
||||||
extractor = (SoundcloudStreamExtractor) SoundCloud.getService().getStreamExtractor("https://soundcloud.com/liluzivert/do-what-i-want-produced-by-maaly-raw-don-cannon");
|
extractor = (SoundcloudStreamExtractor) SoundCloud.getService().getStreamExtractor("https://soundcloud.com/liluzivert/do-what-i-want-produced-by-maaly-raw-don-cannon");
|
||||||
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -41,12 +41,14 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
*/
|
*/
|
||||||
public class YoutubeStreamExtractorDefaultTest {
|
public class YoutubeStreamExtractorDefaultTest {
|
||||||
public static final String HTTPS = "https://";
|
public static final String HTTPS = "https://";
|
||||||
private StreamExtractor extractor;
|
private YoutubeStreamExtractor extractor;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
NewPipe.init(Downloader.getInstance());
|
NewPipe.init(Downloader.getInstance());
|
||||||
extractor = YouTube.getService().getStreamExtractor("https://www.youtube.com/watch?v=rYEDA3JcQqw");
|
extractor = (YoutubeStreamExtractor) YouTube.getService()
|
||||||
|
.getStreamExtractor("https://www.youtube.com/watch?v=rYEDA3JcQqw");
|
||||||
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class YoutubeStreamExtractorRestrictedTest {
|
||||||
NewPipe.init(Downloader.getInstance());
|
NewPipe.init(Downloader.getInstance());
|
||||||
extractor = (YoutubeStreamExtractor) YouTube.getService()
|
extractor = (YoutubeStreamExtractor) YouTube.getService()
|
||||||
.getStreamExtractor("https://www.youtube.com/watch?v=i6JTvzrpBy0");
|
.getStreamExtractor("https://www.youtube.com/watch?v=i6JTvzrpBy0");
|
||||||
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class YoutubeTrendingExtractorTest {
|
||||||
public void testGetStreams() throws Exception {
|
public void testGetStreams() throws Exception {
|
||||||
StreamInfoItemCollector collector = extractor.getStreams();
|
StreamInfoItemCollector collector = extractor.getStreams();
|
||||||
Utils.printErrors(collector);
|
Utils.printErrors(collector);
|
||||||
assertTrue("no streams are received", collector.getItemList().isEmpty());
|
assertFalse("no streams are received", collector.getItemList().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue