show channelvideos
This commit is contained in:
parent
c03b106118
commit
4164195fae
12 changed files with 334 additions and 109 deletions
|
|
@ -7,12 +7,13 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.support.design.widget.CollapsingToolbarLayout;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
|
@ -25,9 +26,11 @@ import org.schabi.newpipe.extractor.ChannelInfo;
|
|||
import org.schabi.newpipe.extractor.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.ParsingException;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamPreviewInfo;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChannelActivity extends AppCompatActivity {
|
||||
|
||||
|
|
@ -105,6 +108,16 @@ public class ChannelActivity extends AppCompatActivity {
|
|||
updateUi(info);
|
||||
}
|
||||
});
|
||||
|
||||
// look for non critical errors during extraction
|
||||
if(info != null &&
|
||||
!info.errors.isEmpty()) {
|
||||
Log.e(TAG, "OCCURRED ERRORS DURING EXTRACTION:");
|
||||
for (Throwable e : info.errors) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "------");
|
||||
}
|
||||
}
|
||||
} catch(IOException ioe) {
|
||||
postNewErrorToast(h, R.string.network_error);
|
||||
ioe.printStackTrace();
|
||||
|
|
@ -124,10 +137,12 @@ public class ChannelActivity extends AppCompatActivity {
|
|||
|
||||
|
||||
private void updateUi(final ChannelInfo info) {
|
||||
VideoInfoItemViewCreator viCreator =
|
||||
new VideoInfoItemViewCreator(LayoutInflater.from(this), this, rootView);
|
||||
CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) findViewById(R.id.channel_toolbar_layout);
|
||||
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
||||
ImageView channelBanner = (ImageView) findViewById(R.id.channel_banner_image);
|
||||
View channelContentView = (View) findViewById(R.id.channel_content_view);
|
||||
View channelContentView = findViewById(R.id.channel_content_view);
|
||||
FloatingActionButton feedButton = (FloatingActionButton) findViewById(R.id.channel_rss_fab);
|
||||
ImageView avatarView = (ImageView) findViewById(R.id.channel_avatar_view);
|
||||
ImageView haloView = (ImageView) findViewById(R.id.channel_avatar_halo);
|
||||
|
|
@ -163,6 +178,19 @@ public class ChannelActivity extends AppCompatActivity {
|
|||
} else {
|
||||
feedButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
initVideos(info, viCreator);
|
||||
}
|
||||
|
||||
private void initVideos(final ChannelInfo info, VideoInfoItemViewCreator viCreator) {
|
||||
LinearLayout streamLayout = (LinearLayout) findViewById(R.id.channel_streams_view);
|
||||
ArrayList<StreamPreviewInfo> streamsList = new ArrayList<>(info.related_streams);
|
||||
|
||||
for(final StreamPreviewInfo streamInfo : streamsList) {
|
||||
View itemView = viCreator.getViewFromVideoInfoItem(null, streamLayout, streamInfo);
|
||||
itemView = viCreator.setupView(itemView, streamInfo);
|
||||
streamLayout.addView(itemView);
|
||||
}
|
||||
}
|
||||
|
||||
private void postNewErrorToast(Handler h, final int stringResource) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
package org.schabi.newpipe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Bitmap;
|
||||
import android.view.View;
|
||||
|
||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||
|
||||
import org.schabi.newpipe.ErrorActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 01.08.16.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
|
||||
* VideoInfoItemViewCreator.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 ImageErrorLoadingListener implements ImageLoadingListener {
|
||||
|
||||
private int serviceId = -1;
|
||||
private Activity activity = null;
|
||||
private View rootView = null;
|
||||
|
||||
public ImageErrorLoadingListener(Activity activity, View rootView, int serviceId) {
|
||||
this.activity = activity;
|
||||
this.serviceId= serviceId;
|
||||
this.rootView = rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingStarted(String imageUri, View view) {}
|
||||
|
||||
@Override
|
||||
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||
ErrorActivity.reportError(activity,
|
||||
failReason.getCause(), null, rootView,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE,
|
||||
ServiceList.getNameOfService(serviceId), imageUri,
|
||||
R.string.could_not_load_image));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingCancelled(String imageUri, View view) {}
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
package org.schabi.newpipe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
|
@ -33,15 +37,20 @@ import org.schabi.newpipe.extractor.StreamPreviewInfo;
|
|||
*/
|
||||
|
||||
public class VideoInfoItemViewCreator {
|
||||
|
||||
private View rootView = null; //root view of the activty
|
||||
private Activity activity = null;
|
||||
private final LayoutInflater inflater;
|
||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
||||
private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build();
|
||||
|
||||
public VideoInfoItemViewCreator(LayoutInflater inflater) {
|
||||
public VideoInfoItemViewCreator(LayoutInflater inflater, Activity a, View rootView) {
|
||||
this.inflater = inflater;
|
||||
activity = a;
|
||||
this.rootView = rootView;
|
||||
}
|
||||
|
||||
public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, StreamPreviewInfo info) {
|
||||
public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, final StreamPreviewInfo info) {
|
||||
ViewHolder holder;
|
||||
|
||||
// generate holder
|
||||
|
|
@ -59,15 +68,7 @@ public class VideoInfoItemViewCreator {
|
|||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
// fill with information
|
||||
|
||||
/*
|
||||
if(info.thumbnail == null) {
|
||||
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
|
||||
} else {
|
||||
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
|
||||
}
|
||||
*/
|
||||
// fill holder with information
|
||||
holder.itemVideoTitleView.setText(info.title);
|
||||
if(info.uploader != null && !info.uploader.isEmpty()) {
|
||||
holder.itemUploaderView.setText(info.uploader);
|
||||
|
|
@ -100,6 +101,39 @@ public class VideoInfoItemViewCreator {
|
|||
return convertView;
|
||||
}
|
||||
|
||||
public View setupView(View convertView, final StreamPreviewInfo info) {
|
||||
convertView.setClickable(true);
|
||||
convertView.setFocusable(true);
|
||||
|
||||
|
||||
int[] attrs = new int[]{R.attr.selectableItemBackground};
|
||||
TypedArray typedArray = activity.obtainStyledAttributes(attrs);
|
||||
int backgroundResource = typedArray.getResourceId(0, 0);
|
||||
convertView.setBackgroundResource(backgroundResource);
|
||||
typedArray.recycle();
|
||||
|
||||
convertView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
Intent detailIntent = new Intent(activity, VideoItemDetailActivity.class);
|
||||
detailIntent.putExtra(VideoItemDetailFragment.VIDEO_URL, info.webpage_url);
|
||||
detailIntent.putExtra(
|
||||
VideoItemDetailFragment.STREAMING_SERVICE, info.service_id);
|
||||
activity.startActivity(detailIntent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
ImageView rthumb = (ImageView) convertView.findViewById(R.id.itemThumbnailView);
|
||||
imageLoader.displayImage(info.thumbnail_url, rthumb,
|
||||
displayImageOptions, new ImageErrorLoadingListener(activity, rootView, info.service_id));
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
public ImageView itemThumbnailView;
|
||||
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView, itemViewCountView;
|
||||
|
|
|
|||
|
|
@ -262,31 +262,13 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
private class ThumbnailLoadingListener implements ImageLoadingListener {
|
||||
@Override
|
||||
public void onLoadingStarted(String imageUri, View view) {}
|
||||
|
||||
@Override
|
||||
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||
if(getContext() != null) {
|
||||
Toast.makeText(VideoItemDetailFragment.this.getActivity(),
|
||||
R.string.could_not_load_thumbnails, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
failReason.getCause().printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {}
|
||||
|
||||
@Override
|
||||
public void onLoadingCancelled(String imageUri, View view) {}
|
||||
}
|
||||
|
||||
private void updateInfo(final StreamInfo info) {
|
||||
try {
|
||||
Context c = getContext();
|
||||
VideoInfoItemViewCreator videoItemViewCreator =
|
||||
new VideoInfoItemViewCreator(LayoutInflater.from(getActivity()));
|
||||
new VideoInfoItemViewCreator(LayoutInflater.from(getActivity()),
|
||||
getActivity(), rootView);
|
||||
|
||||
RelativeLayout textContentLayout =
|
||||
(RelativeLayout) activity.findViewById(R.id.detailTextContentLayout);
|
||||
|
|
@ -422,7 +404,7 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
});
|
||||
textContentLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
if(info.related_videos != null && !info.related_videos.isEmpty()) {
|
||||
if(info.related_streams != null && !info.related_streams.isEmpty()) {
|
||||
initSimilarVideos(info, videoItemViewCreator);
|
||||
} else {
|
||||
activity.findViewById(R.id.detailSimilarTitle).setVisibility(View.GONE);
|
||||
|
|
@ -487,10 +469,6 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
|
||||
@Override
|
||||
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||
Toast.makeText(VideoItemDetailFragment.this.getActivity(),
|
||||
R.string.could_not_load_thumbnails, Toast.LENGTH_LONG).show();
|
||||
failReason.getCause().printStackTrace();
|
||||
|
||||
ErrorActivity.reportError(getActivity(),
|
||||
failReason.getCause(), null, rootView,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE,
|
||||
|
|
@ -512,11 +490,13 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
}
|
||||
if(info.uploader_thumbnail_url != null && !info.uploader_thumbnail_url.isEmpty()) {
|
||||
imageLoader.displayImage(info.uploader_thumbnail_url,
|
||||
uploaderThumb, displayImageOptions, new ThumbnailLoadingListener());
|
||||
uploaderThumb, displayImageOptions,
|
||||
new ImageErrorLoadingListener(activity, rootView, info.service_id));
|
||||
}
|
||||
if(info.thumbnail_url != null && !info.thumbnail_url.isEmpty() && info.next_video != null) {
|
||||
imageLoader.displayImage(info.next_video.thumbnail_url,
|
||||
nextVideoThumb, displayImageOptions, new ThumbnailLoadingListener());
|
||||
nextVideoThumb, displayImageOptions,
|
||||
new ImageErrorLoadingListener(activity, rootView, info.service_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -710,38 +690,15 @@ public class VideoItemDetailFragment extends Fragment {
|
|||
|
||||
private void initSimilarVideos(final StreamInfo info, VideoInfoItemViewCreator videoItemViewCreator) {
|
||||
LinearLayout similarLayout = (LinearLayout) activity.findViewById(R.id.similarVideosView);
|
||||
ArrayList<StreamPreviewInfo> similar = new ArrayList<>(info.related_videos);
|
||||
for (final StreamPreviewInfo item : similar) {
|
||||
View similarView = videoItemViewCreator
|
||||
ArrayList<StreamPreviewInfo> similarStreamsList = new ArrayList<>(info.related_streams);
|
||||
|
||||
for (final StreamPreviewInfo item : similarStreamsList) {
|
||||
View itemView = videoItemViewCreator
|
||||
.getViewFromVideoInfoItem(null, similarLayout, item);
|
||||
|
||||
similarView.setClickable(true);
|
||||
similarView.setFocusable(true);
|
||||
int[] attrs = new int[]{R.attr.selectableItemBackground};
|
||||
TypedArray typedArray = activity.obtainStyledAttributes(attrs);
|
||||
int backgroundResource = typedArray.getResourceId(0, 0);
|
||||
similarView.setBackgroundResource(backgroundResource);
|
||||
typedArray.recycle();
|
||||
itemView = videoItemViewCreator.setupView(itemView, item);
|
||||
|
||||
similarView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
Intent detailIntent = new Intent(activity, VideoItemDetailActivity.class);
|
||||
detailIntent.putExtra(VideoItemDetailFragment.VIDEO_URL, item.webpage_url);
|
||||
detailIntent.putExtra(
|
||||
VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId);
|
||||
startActivity(detailIntent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
similarLayout.addView(similarView);
|
||||
ImageView rthumb = (ImageView)similarView.findViewById(R.id.itemThumbnailView);
|
||||
imageLoader.displayImage(item.thumbnail_url, rthumb,
|
||||
displayImageOptions, new ThumbnailLoadingListener());
|
||||
similarLayout.addView(itemView);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,8 +202,9 @@ public class VideoItemListFragment extends ListFragment {
|
|||
setListShown(true);
|
||||
updateList(result.resultList);
|
||||
if(!result.suggestion.isEmpty()) {
|
||||
|
||||
Toast.makeText(getActivity(),
|
||||
String.format(getString(R.string.did_you_mean), result.suggestion),
|
||||
String.format(getActivity().getString(R.string.did_you_mean), result.suggestion),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.schabi.newpipe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -39,12 +40,12 @@ class VideoListAdapter extends BaseAdapter {
|
|||
private Vector<StreamPreviewInfo> videoList = new Vector<>();
|
||||
private final ListView listView;
|
||||
|
||||
public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) {
|
||||
viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(context));
|
||||
public VideoListAdapter(Activity activity, VideoItemListFragment videoListFragment) {
|
||||
viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(activity), activity, null);
|
||||
this.listView = videoListFragment.getListView();
|
||||
this.listView.setDivider(null);
|
||||
this.listView.setDividerHeight(0);
|
||||
this.context = context;
|
||||
this.context = activity;
|
||||
}
|
||||
|
||||
public void addVideoList(List<StreamPreviewInfo> videos) {
|
||||
|
|
|
|||
|
|
@ -39,11 +39,15 @@ public abstract class ChannelExtractor {
|
|||
public String getUrl() { return url; }
|
||||
public UrlIdHandler getUrlIdHandler() { return urlIdHandler; }
|
||||
public Downloader getDownloader() { return downloader; }
|
||||
public StreamPreviewInfoCollector getStreamPreviewInfoCollector() {
|
||||
return previewInfoCollector;
|
||||
}
|
||||
|
||||
public abstract String getChannelName() throws ParsingException;
|
||||
public abstract String getAvatarUrl() throws ParsingException;
|
||||
public abstract String getBannerUrl() throws ParsingException;
|
||||
public abstract String getFeedUrl() throws ParsingException;
|
||||
public abstract StreamPreviewInfoCollector getStreams() throws ParsingException;
|
||||
public int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,13 @@ public class ChannelInfo {
|
|||
} catch(Exception e) {
|
||||
info.errors.add(e);
|
||||
}
|
||||
try {
|
||||
StreamPreviewInfoCollector c = extractor.getStreams();
|
||||
info.related_streams = c.getItemList();
|
||||
info.errors.addAll(c.getErrors());
|
||||
} catch(Exception e) {
|
||||
info.errors.add(e);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
|
@ -64,6 +71,7 @@ public class ChannelInfo {
|
|||
public String avatar_url = "";
|
||||
public String banner_url = "";
|
||||
public String feed_url = "";
|
||||
public List<StreamPreviewInfo> related_streams = null;
|
||||
|
||||
public List<Throwable> errors = new Vector<>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ public class StreamInfo extends AbstractVideoInfo {
|
|||
try {
|
||||
// get related videos
|
||||
StreamPreviewInfoCollector c = extractor.getRelatedVideos();
|
||||
streamInfo.related_videos = c.getItemList();
|
||||
streamInfo.related_streams = c.getItemList();
|
||||
streamInfo.errors.addAll(c.getErrors());
|
||||
} catch(Exception e) {
|
||||
streamInfo.addException(e);
|
||||
|
|
@ -281,7 +281,7 @@ public class StreamInfo extends AbstractVideoInfo {
|
|||
public int dislike_count = -1;
|
||||
public String average_rating = "";
|
||||
public StreamPreviewInfo next_video = null;
|
||||
public List<StreamPreviewInfo> related_videos = null;
|
||||
public List<StreamPreviewInfo> related_streams = null;
|
||||
//in seconds. some metadata is not passed using a StreamInfo object!
|
||||
public int start_position = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,14 @@ import java.io.StringReader;
|
|||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.schabi.newpipe.extractor.AbstractVideoInfo;
|
||||
import org.schabi.newpipe.extractor.ChannelExtractor;
|
||||
import org.schabi.newpipe.extractor.Downloader;
|
||||
import org.schabi.newpipe.extractor.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.Parser;
|
||||
import org.schabi.newpipe.extractor.ParsingException;
|
||||
import org.schabi.newpipe.extractor.StreamPreviewInfoCollector;
|
||||
import org.schabi.newpipe.extractor.StreamPreviewInfoExtractor;
|
||||
import org.schabi.newpipe.extractor.UrlIdHandler;
|
||||
|
||||
|
||||
|
|
@ -56,18 +59,24 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||
|
||||
private Downloader downloader;
|
||||
private final Document doc;
|
||||
private final String siteUrl;
|
||||
private final String channelUrl;
|
||||
private String vUrl ="";
|
||||
|
||||
|
||||
public YoutubeChannelExtractor(UrlIdHandler urlIdHandler, String url, Downloader dl, int serviceId)
|
||||
throws ExtractionException, IOException {
|
||||
super(urlIdHandler, url, dl, serviceId);
|
||||
|
||||
siteUrl = urlIdHandler.cleanUrl(url);
|
||||
Log.d(TAG, siteUrl);
|
||||
channelUrl = urlIdHandler.cleanUrl(url) ; //+ "/video?veiw=0&flow=list&sort=dd";
|
||||
downloader = dl;
|
||||
String pageContent = downloader.download(url);
|
||||
doc = Jsoup.parse(pageContent, url);
|
||||
// we first need to get the user url. Otherwise we can't find videos
|
||||
String channelPageContent = downloader.download(channelUrl);
|
||||
Document channelDoc = Jsoup.parse(channelPageContent, channelUrl);
|
||||
String userUrl = getUserUrl(channelDoc);
|
||||
|
||||
vUrl = userUrl + "/videos?veiw=0&flow=list&sort=dd";
|
||||
String pageContent = downloader.download(vUrl);
|
||||
doc = Jsoup.parse(pageContent, vUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -120,6 +129,132 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamPreviewInfoCollector getStreams() throws ParsingException {
|
||||
StreamPreviewInfoCollector collector = getStreamPreviewInfoCollector();
|
||||
Element ul = doc.select("ul[id=\"browse-items-primary\"]").first();
|
||||
|
||||
for(final Element li : ul.children()) {
|
||||
if (li.select("div[class=\"feed-item-dismissable\"]").first() != null) {
|
||||
collector.commit(new StreamPreviewInfoExtractor() {
|
||||
@Override
|
||||
public AbstractVideoInfo.StreamType getStreamType() throws ParsingException {
|
||||
return AbstractVideoInfo.StreamType.VIDEO_STREAM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWebPageUrl() throws ParsingException {
|
||||
try {
|
||||
Element el = li.select("div[class=\"feed-item-dismissable\"]").first();
|
||||
Element dl = el.select("h3").first().select("a").first();
|
||||
return dl.attr("abs:href");
|
||||
} catch (Exception e) {
|
||||
throw new ParsingException("Could not get web page url for the video", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() throws ParsingException {
|
||||
try {
|
||||
Element el = li.select("div[class=\"feed-item-dismissable\"]").first();
|
||||
Element dl = el.select("h3").first().select("a").first();
|
||||
return dl.text();
|
||||
} catch (Exception e) {
|
||||
throw new ParsingException("Could not get title", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDuration() throws ParsingException {
|
||||
try {
|
||||
return YoutubeParsingHelper.parseDurationString(
|
||||
li.select("span[class=\"video-time\"]").first().text());
|
||||
} catch(Exception e) {
|
||||
if(isLiveStream(li)) {
|
||||
// -1 for no duration
|
||||
return -1;
|
||||
} else {
|
||||
throw new ParsingException("Could not get Duration: " + getTitle(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUploader() throws ParsingException {
|
||||
return getChannelName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUploadDate() throws ParsingException {
|
||||
try {
|
||||
return li.select("div[class=\"yt-lockup-meta\"]").first()
|
||||
.select("li").first()
|
||||
.text();
|
||||
} catch(Exception e) {
|
||||
throw new ParsingException("Could not get uplaod date", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getViewCount() throws ParsingException {
|
||||
String output;
|
||||
String input;
|
||||
try {
|
||||
input = li.select("div[class=\"yt-lockup-meta\"]").first()
|
||||
.select("li").get(1)
|
||||
.text();
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
if(isLiveStream(li)) {
|
||||
// -1 for no view count
|
||||
return -1;
|
||||
} else {
|
||||
throw new ParsingException(
|
||||
"Could not parse yt-lockup-meta although available: " + getTitle(), e);
|
||||
}
|
||||
}
|
||||
|
||||
output = Parser.matchGroup1("([0-9,\\. ]*)", input)
|
||||
.replace(" ", "")
|
||||
.replace(".", "")
|
||||
.replace(",", "");
|
||||
|
||||
try {
|
||||
return Long.parseLong(output);
|
||||
} catch (NumberFormatException e) {
|
||||
// if this happens the video probably has no views
|
||||
if(!input.isEmpty()) {
|
||||
return 0;
|
||||
} else {
|
||||
throw new ParsingException("Could not handle input: " + input, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThumbnailUrl() throws ParsingException {
|
||||
try {
|
||||
String url;
|
||||
Element te = li.select("span[class=\"yt-thumb-clip\"]").first()
|
||||
.select("img").first();
|
||||
url = te.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've caught such an item.
|
||||
if (url.contains(".gif")) {
|
||||
url = te.attr("abs:data-thumb");
|
||||
}
|
||||
return url;
|
||||
} catch (Exception e) {
|
||||
throw new ParsingException("Could not get thumbnail url", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return collector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeedUrl() throws ParsingException {
|
||||
try {
|
||||
|
|
@ -129,8 +264,21 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||
}
|
||||
}
|
||||
|
||||
private String getUserUrl() throws ParsingException {
|
||||
return doc.select("span[class=\"qualified-channel-title-text\"]").first()
|
||||
private String getUserUrl(Document d) throws ParsingException {
|
||||
return d.select("span[class=\"qualified-channel-title-text\"]").first()
|
||||
.select("a").first().attr("abs:href");
|
||||
}
|
||||
|
||||
private boolean isLiveStream(Element item) {
|
||||
Element bla = item.select("span[class*=\"yt-badge-live\"]").first();
|
||||
|
||||
if(bla == null) {
|
||||
// sometimes livestreams dont have badges but sill are live streams
|
||||
// if video time is not available we most likly have an offline livestream
|
||||
if(item.select("span[class*=\"video-time\"]").first() == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return bla != null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,8 +66,6 @@ public class YoutubeStreamPreviewInfoExtractor implements StreamPreviewInfoExtra
|
|||
} else {
|
||||
throw new ParsingException("Could not get Duration: " + getTitle(), e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue