mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	handling timestamp links in comments
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ritvik Saraf
					Ritvik Saraf