Initial work: use disposables for timestamps parsing in YouTube video descriptions and YouTube comments

This commit is contained in:
TiA4f8R 2021-04-04 16:37:09 +02:00
parent f13f4cc5d2
commit da4d379b22
No known key found for this signature in database
GPG key ID: E6D3E7F5949450DD
3 changed files with 40 additions and 24 deletions

View file

@ -13,6 +13,8 @@ import android.widget.TextView;
import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.util.external_communication.InternalUrlsHandler; import org.schabi.newpipe.util.external_communication.InternalUrlsHandler;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
public class CommentTextOnTouchListener implements View.OnTouchListener { public class CommentTextOnTouchListener implements View.OnTouchListener {
public static final CommentTextOnTouchListener INSTANCE = new CommentTextOnTouchListener(); public static final CommentTextOnTouchListener INSTANCE = new CommentTextOnTouchListener();
@ -50,8 +52,8 @@ public class CommentTextOnTouchListener implements View.OnTouchListener {
if (action == MotionEvent.ACTION_UP) { if (action == MotionEvent.ACTION_UP) {
if (link[0] instanceof URLSpan) { if (link[0] instanceof URLSpan) {
final String url = ((URLSpan) link[0]).getURL(); final String url = ((URLSpan) link[0]).getURL();
if (!InternalUrlsHandler.handleUrlCommentsTimestamp(v.getContext(), if (!InternalUrlsHandler.handleUrlCommentsTimestamp(
url)) { new CompositeDisposable(), v.getContext(), url)) {
ShareUtils.openUrlInBrowser(v.getContext(), url, false); ShareUtils.openUrlInBrowser(v.getContext(), url, false);
} }
} }

View file

@ -18,6 +18,7 @@ import java.util.regex.Pattern;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.schedulers.Schedulers;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
@ -38,12 +39,15 @@ public final class InternalUrlsHandler {
* popup player will be opened when the user will click on the timestamp in the comment, * popup player will be opened when the user will click on the timestamp in the comment,
* at the time and for the video indicated in the timestamp. * at the time and for the video indicated in the timestamp.
* *
* @param disposables a field of the Activity/Fragment class that calls this method
* @param context the context to use * @param context the context to use
* @param url the URL to check if it can be handled * @param url the URL to check if it can be handled
* @return true if the URL can be handled by NewPipe, false if it cannot * @return true if the URL can be handled by NewPipe, false if it cannot
*/ */
public static boolean handleUrlCommentsTimestamp(final Context context, final String url) { public static boolean handleUrlCommentsTimestamp(final CompositeDisposable disposables,
return handleUrl(context, url, HASHTAG_TIMESTAMP_PATTERN); final Context context,
final String url) {
return handleUrl(disposables, context, url, HASHTAG_TIMESTAMP_PATTERN);
} }
/** /**
@ -54,12 +58,15 @@ public final class InternalUrlsHandler {
* player will be opened when the user will click on the timestamp in the video description, * player will be opened when the user will click on the timestamp in the video description,
* at the time and for the video indicated in the timestamp. * at the time and for the video indicated in the timestamp.
* *
* @param disposables a field of the Activity/Fragment class that calls this method
* @param context the context to use * @param context the context to use
* @param url the URL to check if it can be handled * @param url the URL to check if it can be handled
* @return true if the URL can be handled by NewPipe, false if it cannot * @return true if the URL can be handled by NewPipe, false if it cannot
*/ */
public static boolean handleUrlDescriptionTimestamp(final Context context, final String url) { public static boolean handleUrlDescriptionTimestamp(final CompositeDisposable disposables,
return handleUrl(context, url, AMPERSAND_TIMESTAMP_PATTERN); final Context context,
final String url) {
return handleUrl(disposables, context, url, AMPERSAND_TIMESTAMP_PATTERN);
} }
/** /**
@ -69,12 +76,14 @@ public final class InternalUrlsHandler {
* service URL with a timestamp, the popup player will be opened and true will be returned; * service URL with a timestamp, the popup player will be opened and true will be returned;
* else, false will be returned. * else, false will be returned.
* *
* @param disposables a field of the Activity/Fragment class that calls this method
* @param context the context to use * @param context the context to use
* @param url the URL to check if it can be handled * @param url the URL to check if it can be handled
* @param pattern the pattern * @param pattern the pattern to use
* @return true if the URL can be handled by NewPipe, false if it cannot * @return true if the URL can be handled by NewPipe, false if it cannot
*/ */
private static boolean handleUrl(final Context context, private static boolean handleUrl(final CompositeDisposable disposables,
final Context context,
final String url, final String url,
final Pattern pattern) { final Pattern pattern) {
final String matchedUrl; final String matchedUrl;
@ -102,7 +111,7 @@ public final class InternalUrlsHandler {
return false; return false;
} }
if (linkType == StreamingService.LinkType.STREAM && seconds != -1) { if (linkType == StreamingService.LinkType.STREAM && seconds != -1) {
return playOnPopup(context, matchedUrl, service, seconds); return playOnPopup(disposables, context, matchedUrl, service, seconds);
} else { } else {
NavigationHelper.openRouterActivity(context, matchedUrl); NavigationHelper.openRouterActivity(context, matchedUrl);
return true; return true;
@ -112,13 +121,15 @@ public final class InternalUrlsHandler {
/** /**
* Play a content in the floating player. * Play a content in the floating player.
* *
* @param disposables a field of the Activity/Fragment class that calls this method
* @param context the context to be used * @param context the context to be used
* @param url the URL of the content * @param url the URL of the content
* @param service the service of the content * @param service the service of the content
* @param seconds the position in seconds at which the floating player will start * @param seconds the position in seconds at which the floating player will start
* @return true if the playback of the content has successfully started or false if not * @return true if the playback of the content has successfully started or false if not
*/ */
public static boolean playOnPopup(final Context context, public static boolean playOnPopup(final CompositeDisposable disposables,
final Context context,
final String url, final String url,
final StreamingService service, final StreamingService service,
final int seconds) { final int seconds) {
@ -133,13 +144,13 @@ public final class InternalUrlsHandler {
final Single<StreamInfo> single final Single<StreamInfo> single
= ExtractorHelper.getStreamInfo(service.getServiceId(), cleanUrl, false); = ExtractorHelper.getStreamInfo(service.getServiceId(), cleanUrl, false);
single.subscribeOn(Schedulers.io()) disposables.add(single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> { .subscribe(info -> {
final PlayQueue playQueue final PlayQueue playQueue
= new SinglePlayQueue(info, seconds * 1000); = new SinglePlayQueue(info, seconds * 1000);
NavigationHelper.playOnPopupPlayer(context, playQueue, false); NavigationHelper.playOnPopupPlayer(context, playQueue, false);
}); }));
return true; return true;
} }
} }

View file

@ -23,6 +23,7 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.linkify.LinkifyPlugin; import io.noties.markwon.linkify.LinkifyPlugin;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.schedulers.Schedulers;
@ -201,7 +202,8 @@ public final class TextLinkifier {
spannableDescription.setSpan(new ClickableSpan() { spannableDescription.setSpan(new ClickableSpan() {
@Override @Override
public void onClick(@NonNull final View view) { public void onClick(@NonNull final View view) {
playOnPopup(context, contentUrl, streamingService, time); playOnPopup(new CompositeDisposable(), context, contentUrl, streamingService,
time);
} }
}, timestampStart, timestampEnd, 0); }, timestampStart, timestampEnd, 0);
} }
@ -245,7 +247,8 @@ public final class TextLinkifier {
final String url = span.getURL(); final String url = span.getURL();
final ClickableSpan clickableSpan = new ClickableSpan() { final ClickableSpan clickableSpan = new ClickableSpan() {
public void onClick(@NonNull final View view) { public void onClick(@NonNull final View view) {
if (!InternalUrlsHandler.handleUrlDescriptionTimestamp(context, url)) { if (!InternalUrlsHandler.handleUrlDescriptionTimestamp(
new CompositeDisposable(), context, url)) {
ShareUtils.openUrlInBrowser(context, url, false); ShareUtils.openUrlInBrowser(context, url, false);
} }
} }