made StreamExtractor use StreamPreviewInfoCollector

This commit is contained in:
Christian Schabesberger 2016-05-22 12:39:57 +02:00
parent a4ce6c707c
commit c5544df64c
10 changed files with 180 additions and 80 deletions

View File

@ -88,7 +88,7 @@ public class VideoInfoItemViewCreator {
} else { } else {
holder.itemViewCountView.setVisibility(View.GONE); holder.itemViewCountView.setVisibility(View.GONE);
} }
if(!info.upload_date.isEmpty()) { if(info.upload_date != null && !info.upload_date.isEmpty()) {
holder.itemUploadDateView.setText(info.upload_date + ""); holder.itemUploadDateView.setText(info.upload_date + "");
} }

View File

@ -33,13 +33,13 @@ public abstract class SearchEngine {
} }
} }
private StreamPreviewInfoCollector collector; private StreamPreviewInfoSearchCollector collector;
public SearchEngine(StreamUrlIdHandler urlIdHandler, int serviceId) { public SearchEngine(StreamUrlIdHandler urlIdHandler, int serviceId) {
collector = new StreamPreviewInfoCollector(urlIdHandler, serviceId); collector = new StreamPreviewInfoSearchCollector(urlIdHandler, serviceId);
} }
public StreamPreviewInfoCollector getStreamPreviewInfoCollector() { protected StreamPreviewInfoSearchCollector getStreamPreviewInfoSearchCollector() {
return collector; return collector;
} }
@ -48,7 +48,7 @@ public abstract class SearchEngine {
throws ExtractionException, IOException; throws ExtractionException, IOException;
//Result search(String query, int page); //Result search(String query, int page);
public abstract StreamPreviewInfoCollector search( public abstract StreamPreviewInfoSearchCollector search(
String query, int page, String contentCountry, Downloader dl) String query, int page, String contentCountry, Downloader dl)
throws ExtractionException, IOException; throws ExtractionException, IOException;
} }

View File

@ -42,6 +42,6 @@ public class SearchResult {
} }
public String suggestion = ""; public String suggestion = "";
public final List<StreamPreviewInfo> resultList = new Vector<>(); public List<StreamPreviewInfo> resultList = new Vector<>();
public List<Exception> errors = new Vector<>(); public List<Exception> errors = new Vector<>();
} }

View File

@ -29,6 +29,10 @@ import java.util.List;
public abstract class StreamExtractor { public abstract class StreamExtractor {
private int serviceId; private int serviceId;
private String url;
private StreamUrlIdHandler urlIdHandler;
private Downloader downloader;
private StreamPreviewInfoCollector previewInfoCollector;
public class ExctractorInitException extends ExtractionException { public class ExctractorInitException extends ExtractionException {
public ExctractorInitException(String message) { public ExctractorInitException(String message) {
@ -51,8 +55,26 @@ public abstract class StreamExtractor {
} }
} }
public StreamExtractor(String url, Downloader dl, int serviceId) { public StreamExtractor(StreamUrlIdHandler urlIdHandler, String url, Downloader dl, int serviceId) {
this.serviceId = serviceId; this.serviceId = serviceId;
this.urlIdHandler = urlIdHandler;
previewInfoCollector = new StreamPreviewInfoCollector(urlIdHandler, serviceId);
}
protected StreamPreviewInfoCollector getStreamPreviewInfoCollector() {
return previewInfoCollector;
}
public String getUrl() {
return url;
}
public StreamUrlIdHandler getUrlIdHandler() {
return urlIdHandler;
}
public Downloader getDownloader() {
return downloader;
} }
public abstract int getTimeStamp() throws ParsingException; public abstract int getTimeStamp() throws ParsingException;
@ -72,9 +94,8 @@ public abstract class StreamExtractor {
public abstract String getAverageRating() throws ParsingException; public abstract String getAverageRating() throws ParsingException;
public abstract int getLikeCount() throws ParsingException; public abstract int getLikeCount() throws ParsingException;
public abstract int getDislikeCount() throws ParsingException; public abstract int getDislikeCount() throws ParsingException;
public abstract StreamPreviewInfo getNextVideo() throws ParsingException; public abstract StreamPreviewInfoExtractor getNextVideo() throws ParsingException;
public abstract List<StreamPreviewInfo> getRelatedVideos() throws ParsingException; public abstract StreamPreviewInfoCollector getRelatedVideos() throws ParsingException;
public abstract StreamUrlIdHandler getUrlIdConverter();
public abstract String getPageUrl(); public abstract String getPageUrl();
public abstract StreamInfo.StreamType getStreamType() throws ParsingException; public abstract StreamInfo.StreamType getStreamType() throws ParsingException;
public int getServiceId() { public int getServiceId() {

View File

@ -85,7 +85,7 @@ public class StreamInfo extends AbstractVideoInfo {
/* ---- importand data, withoug the video can't be displayed goes here: ---- */ /* ---- importand data, withoug the video can't be displayed goes here: ---- */
// if one of these is not available an exception is ment to be thrown directly into the frontend. // if one of these is not available an exception is ment to be thrown directly into the frontend.
StreamUrlIdHandler uiconv = extractor.getUrlIdConverter(); StreamUrlIdHandler uiconv = extractor.getUrlIdHandler();
streamInfo.service_id = extractor.getServiceId(); streamInfo.service_id = extractor.getServiceId();
streamInfo.webpage_url = extractor.getPageUrl(); streamInfo.webpage_url = extractor.getPageUrl();
@ -229,12 +229,23 @@ public class StreamInfo extends AbstractVideoInfo {
streamInfo.addException(e); streamInfo.addException(e);
} }
try { try {
streamInfo.next_video = extractor.getNextVideo(); // get next video
System.out.println(extractor.getUrlIdHandler());
StreamPreviewInfoCollector c = new StreamPreviewInfoCollector(
extractor.getUrlIdHandler(), extractor.getServiceId());
c.commit(extractor.getNextVideo());
if(c.getItemList().size() != 0) {
streamInfo.next_video = c.getItemList().get(0);
}
streamInfo.errors.addAll(c.getErrors());
} catch(Exception e) { } catch(Exception e) {
streamInfo.addException(e); streamInfo.addException(e);
} }
try { try {
streamInfo.related_videos = extractor.getRelatedVideos(); // get related videos
StreamPreviewInfoCollector c = extractor.getRelatedVideos();
streamInfo.related_videos = c.getItemList();
streamInfo.errors.addAll(c.getErrors());
} catch(Exception e) { } catch(Exception e) {
streamInfo.addException(e); streamInfo.addException(e);
} }

View File

@ -2,6 +2,9 @@ package org.schabi.newpipe.extractor;
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamUrlIdHandler; import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamUrlIdHandler;
import java.util.List;
import java.util.Vector;
/** /**
* Created by Christian Schabesberger on 28.02.16. * Created by Christian Schabesberger on 28.02.16.
* *
@ -23,7 +26,8 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamUrlIdHandler;
*/ */
public class StreamPreviewInfoCollector { public class StreamPreviewInfoCollector {
private SearchResult result = new SearchResult(); private List<StreamPreviewInfo> itemList = new Vector<>();
private List<Exception> errors = new Vector<>();
private StreamUrlIdHandler urlIdHandler = null; private StreamUrlIdHandler urlIdHandler = null;
private int serviceId = -1; private int serviceId = -1;
@ -32,16 +36,16 @@ public class StreamPreviewInfoCollector {
this.serviceId = serviceId; this.serviceId = serviceId;
} }
public void setSuggestion(String suggestion) { public List<StreamPreviewInfo> getItemList() {
result.suggestion = suggestion; return itemList;
}
public List<Exception> getErrors() {
return errors;
} }
public void addError(Exception e) { public void addError(Exception e) {
result.errors.add(e); errors.add(e);
}
public SearchResult getSearchResult() {
return result;
} }
public void commit(StreamPreviewInfoExtractor extractor) throws ParsingException { public void commit(StreamPreviewInfoExtractor extractor) throws ParsingException {
@ -84,11 +88,9 @@ public class StreamPreviewInfoCollector {
} catch (Exception e) { } catch (Exception e) {
addError(e); addError(e);
} }
itemList.add(resultItem);
result.resultList.add(resultItem);
} catch (Exception e) { } catch (Exception e) {
addError(e); addError(e);
} }
} }
} }

View File

@ -0,0 +1,42 @@
package org.schabi.newpipe.extractor;
/**
* Created by Christian Schabesberger on 11.05.16.
*
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* StreamPreviewInfoSearchCollector.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/>.
*/
public class StreamPreviewInfoSearchCollector extends StreamPreviewInfoCollector {
private String suggestion = "";
public StreamPreviewInfoSearchCollector(StreamUrlIdHandler handler, int serviceId) {
super(handler, serviceId);
}
public void setSuggestion(String suggestion) {
this.suggestion = suggestion;
}
public SearchResult getSearchResult() {
SearchResult result = new SearchResult();
result.suggestion = suggestion;
result.errors = getErrors();
result.resultList = getItemList();
return result;
}
}

View File

@ -11,6 +11,7 @@ import org.schabi.newpipe.extractor.ParsingException;
import org.schabi.newpipe.extractor.SearchEngine; import org.schabi.newpipe.extractor.SearchEngine;
import org.schabi.newpipe.extractor.StreamPreviewInfoCollector; import org.schabi.newpipe.extractor.StreamPreviewInfoCollector;
import org.schabi.newpipe.extractor.StreamPreviewInfoExtractor; import org.schabi.newpipe.extractor.StreamPreviewInfoExtractor;
import org.schabi.newpipe.extractor.StreamPreviewInfoSearchCollector;
import org.schabi.newpipe.extractor.StreamUrlIdHandler; import org.schabi.newpipe.extractor.StreamUrlIdHandler;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@ -55,9 +56,9 @@ public class YoutubeSearchEngine extends SearchEngine {
} }
@Override @Override
public StreamPreviewInfoCollector search(String query, int page, String languageCode, Downloader downloader) public StreamPreviewInfoSearchCollector search(String query, int page, String languageCode, Downloader downloader)
throws IOException, ExtractionException { throws IOException, ExtractionException {
StreamPreviewInfoCollector collector = getStreamPreviewInfoCollector(); StreamPreviewInfoSearchCollector collector = getStreamPreviewInfoSearchCollector();
/* Cant use Uri.Bilder since it's android code. /* Cant use Uri.Bilder since it's android code.
// Android code is baned from the extractor side. // Android code is baned from the extractor side.

View File

@ -47,7 +47,7 @@ public class YoutubeService extends StreamingService {
throws ExtractionException, IOException { throws ExtractionException, IOException {
StreamUrlIdHandler urlIdHandler = new YoutubeStreamUrlIdHandler(); StreamUrlIdHandler urlIdHandler = new YoutubeStreamUrlIdHandler();
if(urlIdHandler.acceptUrl(url)) { if(urlIdHandler.acceptUrl(url)) {
return new YoutubeStreamExtractor(url, downloader, getServiceId()); return new YoutubeStreamExtractor(urlIdHandler, url, downloader, getServiceId());
} }
else { else {
throw new IllegalArgumentException("supplied String is not a valid Youtube URL"); throw new IllegalArgumentException("supplied String is not a valid Youtube URL");

View File

@ -8,6 +8,7 @@ import org.jsoup.nodes.Element;
import org.mozilla.javascript.Context; import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function; import org.mozilla.javascript.Function;
import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.ScriptableObject;
import org.schabi.newpipe.extractor.AbstractVideoInfo;
import org.schabi.newpipe.extractor.AudioStream; import org.schabi.newpipe.extractor.AudioStream;
import org.schabi.newpipe.extractor.ExtractionException; import org.schabi.newpipe.extractor.ExtractionException;
import org.schabi.newpipe.extractor.Downloader; import org.schabi.newpipe.extractor.Downloader;
@ -15,6 +16,8 @@ import org.schabi.newpipe.extractor.Parser;
import org.schabi.newpipe.extractor.ParsingException; import org.schabi.newpipe.extractor.ParsingException;
import org.schabi.newpipe.extractor.StreamInfo; import org.schabi.newpipe.extractor.StreamInfo;
import org.schabi.newpipe.extractor.StreamPreviewInfo; import org.schabi.newpipe.extractor.StreamPreviewInfo;
import org.schabi.newpipe.extractor.StreamPreviewInfoCollector;
import org.schabi.newpipe.extractor.StreamPreviewInfoExtractor;
import org.schabi.newpipe.extractor.StreamUrlIdHandler; import org.schabi.newpipe.extractor.StreamUrlIdHandler;
import org.schabi.newpipe.extractor.StreamExtractor; import org.schabi.newpipe.extractor.StreamExtractor;
import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.MediaFormat;
@ -181,9 +184,10 @@ public class YoutubeStreamExtractor extends StreamExtractor {
private Downloader downloader; private Downloader downloader;
public YoutubeStreamExtractor(String pageUrl, Downloader dl, int serviceId) public YoutubeStreamExtractor(StreamUrlIdHandler urlIdHandler, String pageUrl,
Downloader dl, int serviceId)
throws ExtractionException, IOException { throws ExtractionException, IOException {
super(pageUrl, dl, serviceId); super(urlIdHandler ,pageUrl, dl, serviceId);
//most common videoInfo fields are now set in our superclass, for all services //most common videoInfo fields are now set in our superclass, for all services
downloader = dl; downloader = dl;
this.pageUrl = pageUrl; this.pageUrl = pageUrl;
@ -648,7 +652,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
} }
@Override @Override
public StreamPreviewInfo getNextVideo() throws ParsingException { public StreamPreviewInfoExtractor getNextVideo() throws ParsingException {
try { try {
return extractVideoPreviewInfo(doc.select("div[class=\"watch-sidebar-section\"]").first() return extractVideoPreviewInfo(doc.select("div[class=\"watch-sidebar-section\"]").first()
.select("li").first()); .select("li").first());
@ -658,26 +662,21 @@ public class YoutubeStreamExtractor extends StreamExtractor {
} }
@Override @Override
public Vector<StreamPreviewInfo> getRelatedVideos() throws ParsingException { public StreamPreviewInfoCollector getRelatedVideos() throws ParsingException {
try { try {
Vector<StreamPreviewInfo> relatedVideos = new Vector<>(); StreamPreviewInfoCollector collector = getStreamPreviewInfoCollector();
for (Element li : doc.select("ul[id=\"watch-related\"]").first().children()) { for (Element li : doc.select("ul[id=\"watch-related\"]").first().children()) {
// first check if we have a playlist. If so leave them out // first check if we have a playlist. If so leave them out
if (li.select("a[class*=\"content-link\"]").first() != null) { if (li.select("a[class*=\"content-link\"]").first() != null) {
relatedVideos.add(extractVideoPreviewInfo(li)); collector.commit(extractVideoPreviewInfo(li));
} }
} }
return relatedVideos; return collector;
} catch(Exception e) { } catch(Exception e) {
throw new ParsingException("Could not get related videos", e); throw new ParsingException("Could not get related videos", e);
} }
} }
@Override
public StreamUrlIdHandler getUrlIdConverter() {
return new YoutubeStreamUrlIdHandler();
}
@Override @Override
public String getPageUrl() { public String getPageUrl() {
return pageUrl; return pageUrl;
@ -692,54 +691,78 @@ public class YoutubeStreamExtractor extends StreamExtractor {
/**Provides information about links to other videos on the video page, such as related videos. /**Provides information about links to other videos on the video page, such as related videos.
* This is encapsulated in a StreamPreviewInfo object, * This is encapsulated in a StreamPreviewInfo object,
* which is a subset of the fields in a full StreamInfo.*/ * which is a subset of the fields in a full StreamInfo.*/
private StreamPreviewInfo extractVideoPreviewInfo(Element li) throws ParsingException { private StreamPreviewInfoExtractor extractVideoPreviewInfo(final Element li) {
StreamPreviewInfo info = new StreamPreviewInfo(); return new StreamPreviewInfoExtractor() {
@Override
try { public AbstractVideoInfo.StreamType getStreamType() throws ParsingException {
info.webpage_url = li.select("a.content-link").first() return null;
.attr("abs:href");
info.id = Parser.matchGroup1("v=([0-9a-zA-Z-]*)", info.webpage_url);
//todo: check NullPointerException causing
info.title = li.select("span.title").first().text();
//this page causes the NullPointerException, after finding it by searching for "tjvg":
//https://www.youtube.com/watch?v=Uqg0aEhLFAg
//this line is unused
//String views = li.select("span.view-count").first().text();
//Log.i(TAG, "title:"+info.title);
//Log.i(TAG, "view count:"+views);
try {
info.view_count = Long.parseLong(li.select("span.view-count")
.first().text().replaceAll("[^\\d]", ""));
} catch (Exception e) {//related videos sometimes have no view count
info.view_count = 0;
} }
info.uploader = li.select("span.g-hovercard").first().text();
info.duration = YoutubeParsingHelper.parseDurationString( @Override
li.select("span.video-time").first().text()); public String getWebPageUrl() throws ParsingException {
return li.select("a.content-link").first().attr("abs:href");
}
Element img = li.select("img").first(); @Override
info.thumbnail_url = img.attr("abs:src"); public String getTitle() throws ParsingException {
// Sometimes youtube sends links to gif files which somehow seem to not exist //todo: check NullPointerException causing
// anymore. Items with such gif also offer a secondary image source. So we are going return li.select("span.title").first().text();
// to use that if we caught such an item. //this page causes the NullPointerException, after finding it by searching for "tjvg":
if (info.thumbnail_url.contains(".gif")) { //https://www.youtube.com/watch?v=Uqg0aEhLFAg
info.thumbnail_url = img.attr("data-thumb");
} }
if (info.thumbnail_url.startsWith("//")) {
info.thumbnail_url = "https:" + info.thumbnail_url; @Override
public int getDuration() throws ParsingException {
return YoutubeParsingHelper.parseDurationString(
li.select("span.video-time").first().text());
} }
} catch (Exception e) {
throw new ParsingException("Could not get video preview info", e); @Override
} public String getUploader() throws ParsingException {
return info; return li.select("span.g-hovercard").first().text();
}
@Override
public String getUploadDate() throws ParsingException {
return null;
}
@Override
public long getViewCount() throws ParsingException {
//this line is unused
//String views = li.select("span.view-count").first().text();
//Log.i(TAG, "title:"+info.title);
//Log.i(TAG, "view count:"+views);
try {
return Long.parseLong(li.select("span.view-count")
.first().text().replaceAll("[^\\d]", ""));
} catch (Exception e) {
//related videos sometimes have no view count
return 0;
}
}
@Override
public String getThumbnailUrl() throws ParsingException {
Element img = li.select("img").first();
String thumbnailUrl = img.attr("abs:src");
// Sometimes youtube sends links to gif files which somehow seem to not exist
// anymore. Items with such gif also offer a secondary image source. So we are going
// to use that if we caught such an item.
if (thumbnailUrl.contains(".gif")) {
thumbnailUrl = img.attr("data-thumb");
}
if (thumbnailUrl.startsWith("//")) {
thumbnailUrl = "https:" + thumbnailUrl;
}
return thumbnailUrl;
}
};
} }
private String loadDecryptionCode(String playerUrl) throws DecryptException { private String loadDecryptionCode(String playerUrl) throws DecryptException {
String decryptionFuncName; String decryptionFuncName;
String decryptionFunc; String decryptionFunc;