handling timestamp links in comments

This commit is contained in:
Ritvik Saraf 2019-03-02 05:12:06 +05:30
parent c0004e988a
commit 67d2b9131e
4 changed files with 114 additions and 13 deletions

View File

@ -36,7 +36,6 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
@ -81,10 +80,13 @@ public class RouterActivity extends AppCompatActivity {
protected int selectedPreviously = -1;
protected String currentUrl;
protected boolean internalRoute = false;
protected final CompositeDisposable disposables = new CompositeDisposable();
private boolean selectionIsDownload = false;
public static final String internalRouteKey = "internalRoute";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -99,6 +101,8 @@ public class RouterActivity extends AppCompatActivity {
}
}
internalRoute = getIntent().getBooleanExtra(internalRouteKey, false);
setTheme(ThemeHelper.isLightThemeSelected(this)
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
}
@ -383,8 +387,10 @@ public class RouterActivity extends AppCompatActivity {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(intent -> {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
if(!internalRoute){
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
}
startActivity(intent);
finish();

View File

@ -15,6 +15,9 @@ import org.schabi.newpipe.util.CommentTextOnTouchListener;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.hdodenhof.circleimageview.CircleImageView;
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
@ -28,7 +31,23 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
private static final int commentExpandedLines = 1000;
private String commentText;
private boolean containsLinks = false;
private String streamUrl;
private static final Pattern pattern = Pattern.compile("(\\d+:)?(\\d+)?:(\\d+)");
private final Linkify.TransformFilter timestampLink = new Linkify.TransformFilter() {
@Override
public String transformUrl(Matcher match, String url) {
int timestamp = 0;
String hours = match.group(1);
String minutes = match.group(2);
String seconds = match.group(3);
if(hours != null) timestamp += (Integer.parseInt(hours.replace(":", ""))*3600);
if(minutes != null) timestamp += (Integer.parseInt(minutes.replace(":", ""))*60);
if(seconds != null) timestamp += (Integer.parseInt(seconds));
return streamUrl + url.replace(match.group(0), "&t=" + String.valueOf(timestamp));
}
};
CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent);
@ -70,10 +89,12 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
}
});
streamUrl = item.getUrl();
itemContentView.setMaxLines(commentDefaultLines);
commentText = item.getCommentText();
itemContentView.setText(commentText);
containsLinks = linkify();
linkify();
itemContentView.setOnTouchListener(CommentTextOnTouchListener.INSTANCE);
if(itemContentView.getLineCount() == 0){
@ -100,7 +121,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
int endOfLastLine = itemContentView.getLayout().getLineEnd(commentDefaultLines - 1);
String newVal = itemContentView.getText().subSequence(0, endOfLastLine - 3) + "...";
itemContentView.setText(newVal);
if(containsLinks) linkify();
linkify();
}
}
@ -115,12 +136,12 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
private void expand() {
itemContentView.setMaxLines(commentExpandedLines);
itemContentView.setText(commentText);
if(containsLinks) linkify();
linkify();
}
private boolean linkify(){
boolean res = Linkify.addLinks(itemContentView, Linkify.WEB_URLS);
private void linkify(){
Linkify.addLinks(itemContentView, Linkify.WEB_URLS);
Linkify.addLinks(itemContentView, pattern, null, null, timestampLink);
itemContentView.setMovementMethod(null);
return res;
}
}

View File

@ -1,18 +1,38 @@
package org.schabi.newpipe.util;
import android.content.Context;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class CommentTextOnTouchListener implements View.OnTouchListener {
public static final CommentTextOnTouchListener INSTANCE = new CommentTextOnTouchListener();
private static final Pattern timestampPattern = Pattern.compile(".*&t=(\\d+)");
@Override
public boolean onTouch(View v, MotionEvent event) {
if(!(v instanceof TextView)){
@ -45,7 +65,11 @@ public class CommentTextOnTouchListener implements View.OnTouchListener {
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
boolean handled = false;
if(link[0] instanceof URLSpan){
handled = handleUrl(v.getContext(), (URLSpan) link[0]);
}
if(!handled) link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
@ -59,4 +83,46 @@ public class CommentTextOnTouchListener implements View.OnTouchListener {
return false;
}
private boolean handleUrl(Context context, URLSpan urlSpan) {
String url = urlSpan.getURL();
StreamingService service;
StreamingService.LinkType linkType;
try {
service = NewPipe.getServiceByUrl(url);
linkType = service.getLinkTypeByUrl(url);
} catch (ExtractionException e) {
return false;
}
if(linkType == StreamingService.LinkType.NONE){
return false;
}
Matcher matcher = timestampPattern.matcher(url);
if(linkType == StreamingService.LinkType.STREAM && matcher.matches()){
int seconds = Integer.parseInt(matcher.group(1));
return playOnPopup(context, url, service, seconds);
}else{
NavigationHelper.openRouterActivity(context, url);
return true;
}
}
private boolean playOnPopup(Context context, String url, StreamingService service, int seconds) {
LinkHandlerFactory factory = service.getStreamLHFactory();
String cleanUrl = null;
try {
cleanUrl = factory.getUrl(factory.getId(url));
} catch (ParsingException e) {
return false;
}
Single single = ExtractorHelper.getStreamInfo(service.getServiceId(), cleanUrl, false);
single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> {
PlayQueue playQueue = new SinglePlayQueue((StreamInfo) info);
((StreamInfo) info).setStartPosition(seconds);
NavigationHelper.enqueueOnPopupPlayer(context, playQueue, true);
});
return true;
}
}

View File

@ -21,6 +21,7 @@ import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.RouterActivity;
import org.schabi.newpipe.about.AboutActivity;
import org.schabi.newpipe.download.DownloadActivity;
import org.schabi.newpipe.extractor.NewPipe;
@ -34,11 +35,11 @@ import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
import org.schabi.newpipe.local.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
import org.schabi.newpipe.local.feed.FeedFragment;
import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
@ -422,6 +423,13 @@ public class NavigationHelper {
context.startActivity(mIntent);
}
public static void openRouterActivity(Context context, String url) {
Intent mIntent = new Intent(context, RouterActivity.class);
mIntent.setData(Uri.parse(url));
mIntent.putExtra(RouterActivity.internalRouteKey, true);
context.startActivity(mIntent);
}
public static void openAbout(Context context) {
Intent intent = new Intent(context, AboutActivity.class);
context.startActivity(intent);