diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java index baeaef813..72d54fbbd 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java @@ -88,7 +88,7 @@ public class VideoInfoItemViewCreator { } else { 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 + " • "); } diff --git a/app/src/main/java/org/schabi/newpipe/extractor/SearchEngine.java b/app/src/main/java/org/schabi/newpipe/extractor/SearchEngine.java index 851025c28..80532157e 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/SearchEngine.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/SearchEngine.java @@ -33,13 +33,13 @@ public abstract class SearchEngine { } } - private StreamPreviewInfoCollector collector; + private StreamPreviewInfoSearchCollector collector; public SearchEngine(StreamUrlIdHandler urlIdHandler, int serviceId) { - collector = new StreamPreviewInfoCollector(urlIdHandler, serviceId); + collector = new StreamPreviewInfoSearchCollector(urlIdHandler, serviceId); } - public StreamPreviewInfoCollector getStreamPreviewInfoCollector() { + protected StreamPreviewInfoSearchCollector getStreamPreviewInfoSearchCollector() { return collector; } @@ -48,7 +48,7 @@ public abstract class SearchEngine { throws ExtractionException, IOException; //Result search(String query, int page); - public abstract StreamPreviewInfoCollector search( + public abstract StreamPreviewInfoSearchCollector search( String query, int page, String contentCountry, Downloader dl) throws ExtractionException, IOException; } diff --git a/app/src/main/java/org/schabi/newpipe/extractor/SearchResult.java b/app/src/main/java/org/schabi/newpipe/extractor/SearchResult.java index d21e2ba62..36150d68b 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/SearchResult.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/SearchResult.java @@ -42,6 +42,6 @@ public class SearchResult { } public String suggestion = ""; - public final List resultList = new Vector<>(); + public List resultList = new Vector<>(); public List errors = new Vector<>(); } diff --git a/app/src/main/java/org/schabi/newpipe/extractor/StreamExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/StreamExtractor.java index a3aed0363..eddac4ce5 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/StreamExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/StreamExtractor.java @@ -29,6 +29,10 @@ import java.util.List; public abstract class StreamExtractor { private int serviceId; + private String url; + private StreamUrlIdHandler urlIdHandler; + private Downloader downloader; + private StreamPreviewInfoCollector previewInfoCollector; public class ExctractorInitException extends ExtractionException { 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.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; @@ -72,9 +94,8 @@ public abstract class StreamExtractor { public abstract String getAverageRating() throws ParsingException; public abstract int getLikeCount() throws ParsingException; public abstract int getDislikeCount() throws ParsingException; - public abstract StreamPreviewInfo getNextVideo() throws ParsingException; - public abstract List getRelatedVideos() throws ParsingException; - public abstract StreamUrlIdHandler getUrlIdConverter(); + public abstract StreamPreviewInfoExtractor getNextVideo() throws ParsingException; + public abstract StreamPreviewInfoCollector getRelatedVideos() throws ParsingException; public abstract String getPageUrl(); public abstract StreamInfo.StreamType getStreamType() throws ParsingException; public int getServiceId() { diff --git a/app/src/main/java/org/schabi/newpipe/extractor/StreamInfo.java b/app/src/main/java/org/schabi/newpipe/extractor/StreamInfo.java index 2090ef538..cd7a51741 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/StreamInfo.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/StreamInfo.java @@ -85,7 +85,7 @@ public class StreamInfo extends AbstractVideoInfo { /* ---- 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. - StreamUrlIdHandler uiconv = extractor.getUrlIdConverter(); + StreamUrlIdHandler uiconv = extractor.getUrlIdHandler(); streamInfo.service_id = extractor.getServiceId(); streamInfo.webpage_url = extractor.getPageUrl(); @@ -229,12 +229,23 @@ public class StreamInfo extends AbstractVideoInfo { streamInfo.addException(e); } 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) { streamInfo.addException(e); } 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) { streamInfo.addException(e); } diff --git a/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoCollector.java b/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoCollector.java index 70c2feb77..7e100960c 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoCollector.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoCollector.java @@ -2,6 +2,9 @@ package org.schabi.newpipe.extractor; import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamUrlIdHandler; +import java.util.List; +import java.util.Vector; + /** * Created by Christian Schabesberger on 28.02.16. * @@ -23,7 +26,8 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamUrlIdHandler; */ public class StreamPreviewInfoCollector { - private SearchResult result = new SearchResult(); + private List itemList = new Vector<>(); + private List errors = new Vector<>(); private StreamUrlIdHandler urlIdHandler = null; private int serviceId = -1; @@ -32,16 +36,16 @@ public class StreamPreviewInfoCollector { this.serviceId = serviceId; } - public void setSuggestion(String suggestion) { - result.suggestion = suggestion; + public List getItemList() { + return itemList; + } + + public List getErrors() { + return errors; } public void addError(Exception e) { - result.errors.add(e); - } - - public SearchResult getSearchResult() { - return result; + errors.add(e); } public void commit(StreamPreviewInfoExtractor extractor) throws ParsingException { @@ -84,11 +88,9 @@ public class StreamPreviewInfoCollector { } catch (Exception e) { addError(e); } - - result.resultList.add(resultItem); + itemList.add(resultItem); } catch (Exception e) { addError(e); } - } } diff --git a/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoSearchCollector.java b/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoSearchCollector.java new file mode 100644 index 000000000..e0f02f461 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/extractor/StreamPreviewInfoSearchCollector.java @@ -0,0 +1,42 @@ +package org.schabi.newpipe.extractor; + +/** + * Created by Christian Schabesberger on 11.05.16. + * + * Copyright (C) Christian Schabesberger 2016 + * 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 . + */ + +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; + } +} diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSearchEngine.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSearchEngine.java index bd1f5107c..3fedc1e6b 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSearchEngine.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSearchEngine.java @@ -11,6 +11,7 @@ import org.schabi.newpipe.extractor.ParsingException; import org.schabi.newpipe.extractor.SearchEngine; import org.schabi.newpipe.extractor.StreamPreviewInfoCollector; import org.schabi.newpipe.extractor.StreamPreviewInfoExtractor; +import org.schabi.newpipe.extractor.StreamPreviewInfoSearchCollector; import org.schabi.newpipe.extractor.StreamUrlIdHandler; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -55,9 +56,9 @@ public class YoutubeSearchEngine extends SearchEngine { } @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 { - StreamPreviewInfoCollector collector = getStreamPreviewInfoCollector(); + StreamPreviewInfoSearchCollector collector = getStreamPreviewInfoSearchCollector(); /* Cant use Uri.Bilder since it's android code. // Android code is baned from the extractor side. diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeService.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeService.java index 94f9fb28e..f2d56bcab 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeService.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeService.java @@ -47,7 +47,7 @@ public class YoutubeService extends StreamingService { throws ExtractionException, IOException { StreamUrlIdHandler urlIdHandler = new YoutubeStreamUrlIdHandler(); if(urlIdHandler.acceptUrl(url)) { - return new YoutubeStreamExtractor(url, downloader, getServiceId()); + return new YoutubeStreamExtractor(urlIdHandler, url, downloader, getServiceId()); } else { throw new IllegalArgumentException("supplied String is not a valid Youtube URL"); diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java index 2f1b45785..19ed93262 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java @@ -8,6 +8,7 @@ import org.jsoup.nodes.Element; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.ScriptableObject; +import org.schabi.newpipe.extractor.AbstractVideoInfo; import org.schabi.newpipe.extractor.AudioStream; import org.schabi.newpipe.extractor.ExtractionException; 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.StreamInfo; 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.StreamExtractor; import org.schabi.newpipe.extractor.MediaFormat; @@ -181,9 +184,10 @@ public class YoutubeStreamExtractor extends StreamExtractor { private Downloader downloader; - public YoutubeStreamExtractor(String pageUrl, Downloader dl, int serviceId) + public YoutubeStreamExtractor(StreamUrlIdHandler urlIdHandler, String pageUrl, + Downloader dl, int serviceId) 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 downloader = dl; this.pageUrl = pageUrl; @@ -648,7 +652,7 @@ public class YoutubeStreamExtractor extends StreamExtractor { } @Override - public StreamPreviewInfo getNextVideo() throws ParsingException { + public StreamPreviewInfoExtractor getNextVideo() throws ParsingException { try { return extractVideoPreviewInfo(doc.select("div[class=\"watch-sidebar-section\"]").first() .select("li").first()); @@ -658,26 +662,21 @@ public class YoutubeStreamExtractor extends StreamExtractor { } @Override - public Vector getRelatedVideos() throws ParsingException { + public StreamPreviewInfoCollector getRelatedVideos() throws ParsingException { try { - Vector relatedVideos = new Vector<>(); + StreamPreviewInfoCollector collector = getStreamPreviewInfoCollector(); for (Element li : doc.select("ul[id=\"watch-related\"]").first().children()) { // first check if we have a playlist. If so leave them out if (li.select("a[class*=\"content-link\"]").first() != null) { - relatedVideos.add(extractVideoPreviewInfo(li)); + collector.commit(extractVideoPreviewInfo(li)); } } - return relatedVideos; + return collector; } catch(Exception e) { throw new ParsingException("Could not get related videos", e); } } - @Override - public StreamUrlIdHandler getUrlIdConverter() { - return new YoutubeStreamUrlIdHandler(); - } - @Override public String getPageUrl() { 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. * This is encapsulated in a StreamPreviewInfo object, * which is a subset of the fields in a full StreamInfo.*/ - private StreamPreviewInfo extractVideoPreviewInfo(Element li) throws ParsingException { - StreamPreviewInfo info = new StreamPreviewInfo(); - - try { - info.webpage_url = li.select("a.content-link").first() - .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; + private StreamPreviewInfoExtractor extractVideoPreviewInfo(final Element li) { + return new StreamPreviewInfoExtractor() { + @Override + public AbstractVideoInfo.StreamType getStreamType() throws ParsingException { + return null; } - info.uploader = li.select("span.g-hovercard").first().text(); - info.duration = YoutubeParsingHelper.parseDurationString( - li.select("span.video-time").first().text()); + @Override + public String getWebPageUrl() throws ParsingException { + return li.select("a.content-link").first().attr("abs:href"); + } - Element img = li.select("img").first(); - info.thumbnail_url = 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 (info.thumbnail_url.contains(".gif")) { - info.thumbnail_url = img.attr("data-thumb"); + @Override + public String getTitle() throws ParsingException { + //todo: check NullPointerException causing + return 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 } - 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); - } - return info; + + @Override + public String getUploader() throws ParsingException { + 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 { String decryptionFuncName; String decryptionFunc;