merged upstream/dev, changes for peertube support
This commit is contained in:
commit
d90b1ca5be
187 changed files with 6831 additions and 3208 deletions
|
|
@ -0,0 +1,128 @@
|
|||
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)){
|
||||
return false;
|
||||
}
|
||||
TextView widget = (TextView) v;
|
||||
Object text = widget.getText();
|
||||
if (text instanceof Spanned) {
|
||||
Spannable buffer = (Spannable) text;
|
||||
|
||||
int action = event.getAction();
|
||||
|
||||
if (action == MotionEvent.ACTION_UP
|
||||
|| action == MotionEvent.ACTION_DOWN) {
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
|
||||
x -= widget.getTotalPaddingLeft();
|
||||
y -= widget.getTotalPaddingTop();
|
||||
|
||||
x += widget.getScrollX();
|
||||
y += widget.getScrollY();
|
||||
|
||||
Layout layout = widget.getLayout();
|
||||
int line = layout.getLineForVertical(y);
|
||||
int off = layout.getOffsetForHorizontal(line, x);
|
||||
|
||||
ClickableSpan[] link = buffer.getSpans(off, off,
|
||||
ClickableSpan.class);
|
||||
|
||||
if (link.length != 0) {
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
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]),
|
||||
buffer.getSpanEnd(link[0]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import org.schabi.newpipe.extractor.Info;
|
|||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.SuggestionExtractor;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfo;
|
||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||
|
|
@ -47,6 +48,7 @@ import org.schabi.newpipe.report.UserAction;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
|
|
@ -96,10 +98,13 @@ public final class ExtractorHelper {
|
|||
public static Single<List<String>> suggestionsFor(final int serviceId,
|
||||
final String query) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(() ->
|
||||
NewPipe.getService(serviceId)
|
||||
.getSuggestionExtractor()
|
||||
.suggestionList(query));
|
||||
return Single.fromCallable(() -> {
|
||||
SuggestionExtractor extractor = NewPipe.getService(serviceId)
|
||||
.getSuggestionExtractor();
|
||||
return extractor != null
|
||||
? extractor.suggestionList(query)
|
||||
: Collections.emptyList();
|
||||
});
|
||||
}
|
||||
|
||||
public static Single<StreamInfo> getStreamInfo(final int serviceId,
|
||||
|
|
|
|||
10
app/src/main/java/org/schabi/newpipe/util/FireTvUtils.java
Normal file
10
app/src/main/java/org/schabi/newpipe/util/FireTvUtils.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import org.schabi.newpipe.App;
|
||||
|
||||
public class FireTvUtils {
|
||||
public static boolean isFireTv(){
|
||||
final String AMAZON_FEATURE_FIRE_TV = "amazon.hardware.fire_tv";
|
||||
return App.getApp().getPackageManager().hasSystemFeature(AMAZON_FEATURE_FIRE_TV);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,8 @@ public class KioskTranslator {
|
|||
return c.getString(R.string.top_50);
|
||||
case "New & hot":
|
||||
return c.getString(R.string.new_and_hot);
|
||||
case "conferences":
|
||||
return c.getString(R.string.conferences);
|
||||
default:
|
||||
return kioskId;
|
||||
}
|
||||
|
|
@ -48,6 +50,8 @@ public class KioskTranslator {
|
|||
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_local);
|
||||
case "Recently added":
|
||||
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_recent);
|
||||
case "conferences":
|
||||
return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ public class SecondaryStreamHelper<T extends Stream> {
|
|||
* @return selected audio stream or null if a candidate was not found
|
||||
*/
|
||||
public static AudioStream getAudioStreamFor(@NonNull List<AudioStream> audioStreams, @NonNull VideoStream videoStream) {
|
||||
// TODO: check if m4v and m4a selected streams are DASH compliant
|
||||
switch (videoStream.getFormat()) {
|
||||
case WEBM:
|
||||
case MPEG_4:
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ import org.schabi.newpipe.extractor.NewPipe;
|
|||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||
|
|
@ -30,6 +28,8 @@ public class ServiceHelper {
|
|||
return R.drawable.place_holder_cloud;
|
||||
case 2:
|
||||
return R.drawable.place_holder_peertube;
|
||||
case 3:
|
||||
return R.drawable.place_holder_gadse;
|
||||
default:
|
||||
return R.drawable.place_holder_circle;
|
||||
}
|
||||
|
|
@ -43,6 +43,8 @@ public class ServiceHelper {
|
|||
case "playlists": return c.getString(R.string.playlists);
|
||||
case "tracks": return c.getString(R.string.tracks);
|
||||
case "users": return c.getString(R.string.users);
|
||||
case "conferences" : return c.getString(R.string.conferences);
|
||||
case "events" : return c.getString(R.string.events);
|
||||
default: return filter;
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +136,7 @@ public class ServiceHelper {
|
|||
}
|
||||
|
||||
public static void initService(Context context, int serviceId) {
|
||||
if(serviceId == 2){
|
||||
if(serviceId == ServiceList.PeerTube.getServiceId()){
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String peerTubeInstanceUrl = sharedPreferences.getString(context.getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl());
|
||||
String peerTubeInstanceName = sharedPreferences.getString(context.getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName());
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ import io.reactivex.schedulers.Schedulers;
|
|||
import us.shandian.giga.util.Utility;
|
||||
|
||||
/**
|
||||
* A list adapter for a list of {@link Stream streams}, currently supporting {@link VideoStream} and {@link AudioStream}.
|
||||
* A list adapter for a list of {@link Stream streams},
|
||||
* currently supporting {@link VideoStream}, {@link AudioStream} and {@link SubtitlesStream}
|
||||
*/
|
||||
public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseAdapter {
|
||||
private final Context context;
|
||||
|
|
@ -110,7 +111,10 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
|
|||
}
|
||||
}
|
||||
} else if (stream instanceof AudioStream) {
|
||||
qualityString = ((AudioStream) stream).getAverageBitrate() + "kbps";
|
||||
AudioStream audioStream = ((AudioStream) stream);
|
||||
qualityString = audioStream.getAverageBitrate() > 0
|
||||
? audioStream.getAverageBitrate() + "kbps"
|
||||
: audioStream.getFormat().getName();
|
||||
} else if (stream instanceof SubtitlesStream) {
|
||||
qualityString = ((SubtitlesStream) stream).getDisplayLanguageName();
|
||||
if (((SubtitlesStream) stream).isAutoGenerated()) {
|
||||
|
|
@ -154,8 +158,10 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
|
|||
private final long[] streamSizes;
|
||||
private final String unknownSize;
|
||||
|
||||
public StreamSizeWrapper(List<T> streamsList, Context context) {
|
||||
this.streamsList = streamsList;
|
||||
public StreamSizeWrapper(List<T> sL, Context context) {
|
||||
this.streamsList = sL != null
|
||||
? sL
|
||||
: Collections.emptyList();
|
||||
this.streamSizes = new long[streamsList.size()];
|
||||
this.unknownSize = context == null ? "--.-" : context.getString(R.string.unknown_content);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import android.view.ContextThemeWrapper;
|
|||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
|
||||
|
|
@ -136,15 +137,16 @@ public class ThemeHelper {
|
|||
else if (selectedTheme.equals(blackTheme)) themeName = "BlackTheme";
|
||||
else if (selectedTheme.equals(darkTheme)) themeName = "DarkTheme";
|
||||
|
||||
switch (serviceId) {
|
||||
case 2:
|
||||
//service name for peertube depends on the instance
|
||||
themeName += ".PeerTube";
|
||||
break;
|
||||
default:
|
||||
themeName += "." + service.getServiceInfo().getName();
|
||||
if(serviceId == ServiceList.PeerTube.getServiceId()){
|
||||
//service name for peertube depends on the instance
|
||||
themeName += ".PeerTube";
|
||||
}else{
|
||||
themeName += "." + service.getServiceInfo().getName();
|
||||
}
|
||||
int resourceId = context.getResources().getIdentifier(themeName, "style", context.getPackageName());
|
||||
|
||||
int resourceId = context
|
||||
.getResources()
|
||||
.getIdentifier(themeName, "style", context.getPackageName());
|
||||
|
||||
if (resourceId > 0) {
|
||||
return resourceId;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue