Merge branch 'dev' of https://github.com/TeamNewPipe/NewPipe into feature/notifications
This commit is contained in:
commit
fb0473da39
84 changed files with 830 additions and 359 deletions
|
|
@ -11,6 +11,8 @@ import androidx.core.app.NotificationManagerCompat;
|
|||
import androidx.multidex.MultiDexApplication;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.jakewharton.processphoenix.ProcessPhoenix;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.config.ACRAConfigurationException;
|
||||
import org.acra.config.CoreConfiguration;
|
||||
|
|
@ -86,6 +88,12 @@ public class App extends MultiDexApplication {
|
|||
|
||||
app = this;
|
||||
|
||||
if (ProcessPhoenix.isPhoenixProcess(this)) {
|
||||
Log.i(TAG, "This is a phoenix process! "
|
||||
+ "Aborting initialization of App[onCreate]");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize settings first because others inits can use its values
|
||||
NewPipeSettings.initSettings(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import leakcanary.AppWatcher;
|
|||
|
||||
public abstract class BaseFragment extends Fragment {
|
||||
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
||||
protected final boolean DEBUG = MainActivity.DEBUG;
|
||||
protected static final boolean DEBUG = MainActivity.DEBUG;
|
||||
protected AppCompatActivity activity;
|
||||
//These values are used for controlling fragments when they are part of the frontpage
|
||||
@State
|
||||
|
|
|
|||
|
|
@ -170,6 +170,10 @@ class AboutActivity : AppCompatActivity() {
|
|||
"PrettyTime", "2012 - 2020", "Lincoln Baxter, III",
|
||||
"https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2
|
||||
),
|
||||
SoftwareComponent(
|
||||
"ProcessPhoenix", "2015", "Jake Wharton",
|
||||
"https://github.com/JakeWharton/ProcessPhoenix", StandardLicenses.APACHE2
|
||||
),
|
||||
SoftwareComponent(
|
||||
"RxAndroid", "2015", "The RxAndroid authors",
|
||||
"https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2
|
||||
|
|
|
|||
|
|
@ -121,27 +121,14 @@ class ErrorPanelHelper(
|
|||
ErrorActivity.reportError(context, errorInfo)
|
||||
}
|
||||
|
||||
errorTextView.setText(
|
||||
when (errorInfo.throwable) {
|
||||
is AgeRestrictedContentException -> R.string.restricted_video_no_stream
|
||||
is GeographicRestrictionException -> R.string.georestricted_content
|
||||
is PaidContentException -> R.string.paid_content
|
||||
is PrivateContentException -> R.string.private_content
|
||||
is SoundCloudGoPlusContentException -> R.string.soundcloud_go_plus_content
|
||||
is YoutubeMusicPremiumContentException -> R.string.youtube_music_premium_content
|
||||
is ContentNotAvailableException -> R.string.content_not_available
|
||||
is ContentNotSupportedException -> R.string.content_not_supported
|
||||
else -> {
|
||||
// show retry button only for content which is not unavailable or unsupported
|
||||
errorRetryButton.isVisible = true
|
||||
if (errorInfo.throwable != null && errorInfo.throwable!!.isNetworkRelated) {
|
||||
R.string.network_error
|
||||
} else {
|
||||
R.string.error_snackbar_message
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
errorTextView.setText(getExceptionDescription(errorInfo.throwable))
|
||||
|
||||
if (errorInfo.throwable !is ContentNotAvailableException &&
|
||||
errorInfo.throwable !is ContentNotSupportedException
|
||||
) {
|
||||
// show retry button only for content which is not unavailable or unsupported
|
||||
errorRetryButton.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
setRootVisible()
|
||||
|
|
@ -189,5 +176,27 @@ class ErrorPanelHelper(
|
|||
companion object {
|
||||
val TAG: String = ErrorPanelHelper::class.simpleName!!
|
||||
val DEBUG: Boolean = MainActivity.DEBUG
|
||||
|
||||
@StringRes
|
||||
public fun getExceptionDescription(throwable: Throwable?): Int {
|
||||
return when (throwable) {
|
||||
is AgeRestrictedContentException -> R.string.restricted_video_no_stream
|
||||
is GeographicRestrictionException -> R.string.georestricted_content
|
||||
is PaidContentException -> R.string.paid_content
|
||||
is PrivateContentException -> R.string.private_content
|
||||
is SoundCloudGoPlusContentException -> R.string.soundcloud_go_plus_content
|
||||
is YoutubeMusicPremiumContentException -> R.string.youtube_music_premium_content
|
||||
is ContentNotAvailableException -> R.string.content_not_available
|
||||
is ContentNotSupportedException -> R.string.content_not_supported
|
||||
else -> {
|
||||
// show retry button only for content which is not unavailable or unsupported
|
||||
if (throwable != null && throwable.isNetworkRelated) {
|
||||
R.string.network_error
|
||||
} else {
|
||||
R.string.error_snackbar_message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.schabi.newpipe.error;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
|
|
@ -66,6 +67,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||
private ActivityRecaptchaBinding recaptchaBinding;
|
||||
private String foundCookies = "";
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
ThemeHelper.setTheme(this);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
|||
import org.schabi.newpipe.local.dialog.PlaylistCreationDialog;
|
||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||
import org.schabi.newpipe.player.MainPlayer;
|
||||
import org.schabi.newpipe.player.MainPlayer.PlayerType;
|
||||
import org.schabi.newpipe.player.Player;
|
||||
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
||||
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
|
||||
|
|
@ -423,7 +424,7 @@ public final class VideoDetailFragment
|
|||
showRelatedItems = sharedPreferences.getBoolean(key, true);
|
||||
tabSettingsChanged = true;
|
||||
} else if (key.equals(getString(R.string.show_description_key))) {
|
||||
showComments = sharedPreferences.getBoolean(key, true);
|
||||
showDescription = sharedPreferences.getBoolean(key, true);
|
||||
tabSettingsChanged = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -742,20 +743,19 @@ public final class VideoDetailFragment
|
|||
&& player.getPlayQueue() != null
|
||||
&& player.videoPlayerSelected()
|
||||
&& player.getPlayQueue().previous()) {
|
||||
return true;
|
||||
return true; // no code here, as previous() was used in the if
|
||||
}
|
||||
|
||||
// That means that we are on the start of the stack,
|
||||
// return false to let the MainActivity handle the onBack
|
||||
if (stack.size() <= 1) {
|
||||
restoreDefaultOrientation();
|
||||
|
||||
return false;
|
||||
return false; // let MainActivity handle the onBack (e.g. to minimize the mini player)
|
||||
}
|
||||
|
||||
// Remove top
|
||||
stack.pop();
|
||||
// Get stack item from the new top
|
||||
assert stack.peek() != null;
|
||||
setupFromHistoryItem(stack.peek());
|
||||
setupFromHistoryItem(Objects.requireNonNull(stack.peek()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1096,8 +1096,8 @@ public final class VideoDetailFragment
|
|||
toggleFullscreenIfInFullscreenMode();
|
||||
|
||||
final PlayQueue queue = setupPlayQueueForIntent(append);
|
||||
if (append) {
|
||||
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
|
||||
if (append) { //resumePlayback: false
|
||||
NavigationHelper.enqueueOnPlayer(activity, queue, PlayerType.POPUP);
|
||||
} else {
|
||||
replaceQueueIfUserConfirms(() -> NavigationHelper
|
||||
.playOnPopupPlayer(activity, queue, true));
|
||||
|
|
@ -1155,7 +1155,7 @@ public final class VideoDetailFragment
|
|||
|
||||
final PlayQueue queue = setupPlayQueueForIntent(append);
|
||||
if (append) {
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
|
||||
NavigationHelper.enqueueOnPlayer(activity, queue, PlayerType.AUDIO);
|
||||
} else {
|
||||
replaceQueueIfUserConfirms(() -> NavigationHelper
|
||||
.playOnBackgroundPlayer(activity, queue, true));
|
||||
|
|
@ -1181,7 +1181,7 @@ public final class VideoDetailFragment
|
|||
addVideoPlayerView();
|
||||
|
||||
final Intent playerIntent = NavigationHelper.getPlayerIntent(requireContext(),
|
||||
MainPlayer.class, queue, true, autoPlayEnabled);
|
||||
MainPlayer.class, queue, autoPlayEnabled);
|
||||
ContextCompat.startForegroundService(activity, playerIntent);
|
||||
}
|
||||
|
||||
|
|
@ -1432,17 +1432,15 @@ public final class VideoDetailFragment
|
|||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void restoreDefaultOrientation() {
|
||||
if (!isPlayerAvailable() || !player.videoPlayerSelected() || activity == null) {
|
||||
return;
|
||||
if (isPlayerAvailable() && player.videoPlayerSelected()) {
|
||||
toggleFullscreenIfInFullscreenMode();
|
||||
}
|
||||
|
||||
toggleFullscreenIfInFullscreenMode();
|
||||
|
||||
// This will show systemUI and pause the player.
|
||||
// User can tap on Play button and video will be in fullscreen mode again
|
||||
// Note for tablet: trying to avoid orientation changes since it's not easy
|
||||
// to physically rotate the tablet every time
|
||||
if (!DeviceUtils.isTablet(activity)) {
|
||||
if (activity != null && !DeviceUtils.isTablet(activity)) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -350,12 +350,16 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||
if (context == null || context.getResources() == null || activity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<StreamDialogEntry> entries = new ArrayList<>();
|
||||
|
||||
if (PlayerHolder.getInstance().getType() != null) {
|
||||
if (PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
entries.add(StreamDialogEntry.enqueue);
|
||||
|
||||
if (PlayerHolder.getInstance().getQueueSize() > 1) {
|
||||
entries.add(StreamDialogEntry.enqueue_next);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.getStreamType() == StreamType.AUDIO_STREAM) {
|
||||
entries.addAll(Arrays.asList(
|
||||
StreamDialogEntry.start_here_on_background,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
|||
import org.schabi.newpipe.ktx.AnimationType;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionManager;
|
||||
import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
|
||||
import org.schabi.newpipe.player.MainPlayer.PlayerType;
|
||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
|
|
@ -550,12 +551,12 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||
.playOnBackgroundPlayer(activity, getPlayQueue(), false));
|
||||
|
||||
playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> {
|
||||
NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true);
|
||||
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.POPUP);
|
||||
return true;
|
||||
});
|
||||
|
||||
playlistControlBinding.playlistCtrlPlayBgButton.setOnLongClickListener(view -> {
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true);
|
||||
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.AUDIO);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
|
|||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||
import org.schabi.newpipe.player.MainPlayer.PlayerType;
|
||||
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||
|
|
@ -148,9 +149,14 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||
|
||||
final ArrayList<StreamDialogEntry> entries = new ArrayList<>();
|
||||
|
||||
if (PlayerHolder.getInstance().getType() != null) {
|
||||
if (PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
entries.add(StreamDialogEntry.enqueue);
|
||||
|
||||
if (PlayerHolder.getInstance().getQueueSize() > 1) {
|
||||
entries.add(StreamDialogEntry.enqueue_next);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.getStreamType() == StreamType.AUDIO_STREAM) {
|
||||
entries.addAll(Arrays.asList(
|
||||
StreamDialogEntry.start_here_on_background,
|
||||
|
|
@ -347,12 +353,12 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue(), false));
|
||||
|
||||
playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> {
|
||||
NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true);
|
||||
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.POPUP);
|
||||
return true;
|
||||
});
|
||||
|
||||
playlistControlBinding.playlistCtrlPlayBgButton.setOnLongClickListener(view -> {
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true);
|
||||
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.AUDIO);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
||||
searchBinding = FragmentSearchBinding.bind(rootView);
|
||||
super.onViewCreated(rootView, savedInstanceState);
|
||||
showSearchOnStart();
|
||||
initSearchListeners();
|
||||
|
|
@ -341,7 +342,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
@Override
|
||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||
super.initViews(rootView, savedInstanceState);
|
||||
searchBinding = FragmentSearchBinding.bind(rootView);
|
||||
|
||||
searchBinding.suggestionsList.setAdapter(suggestionListAdapter);
|
||||
new ItemTouchHelper(new ItemTouchHelper.Callback() {
|
||||
|
|
@ -807,18 +807,21 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(listNotification -> {
|
||||
if (listNotification.isOnNext()) {
|
||||
if (listNotification.getValue() != null) {
|
||||
handleSuggestions(listNotification.getValue());
|
||||
}
|
||||
} else if (listNotification.isOnError()
|
||||
&& listNotification.getError() != null
|
||||
&& !ExceptionUtils.isInterruptedCaused(listNotification.getError())) {
|
||||
showSnackBarError(new ErrorInfo(listNotification.getError(),
|
||||
UserAction.GET_SUGGESTIONS, searchString, serviceId));
|
||||
}
|
||||
});
|
||||
.subscribe(
|
||||
listNotification -> {
|
||||
if (listNotification.isOnNext()) {
|
||||
if (listNotification.getValue() != null) {
|
||||
handleSuggestions(listNotification.getValue());
|
||||
}
|
||||
} else if (listNotification.isOnError()
|
||||
&& listNotification.getError() != null
|
||||
&& !ExceptionUtils.isInterruptedCaused(
|
||||
listNotification.getError())) {
|
||||
showSnackBarError(new ErrorInfo(listNotification.getError(),
|
||||
UserAction.GET_SUGGESTIONS, searchString, serviceId));
|
||||
}
|
||||
}, throwable -> showSnackBarError(new ErrorInfo(
|
||||
throwable, UserAction.GET_SUGGESTIONS, searchString, serviceId)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -326,9 +326,14 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
|||
if (context == null || context.resources == null || activity == null) return
|
||||
|
||||
val entries = ArrayList<StreamDialogEntry>()
|
||||
if (PlayerHolder.getInstance().getType() != null) {
|
||||
if (PlayerHolder.getInstance().isPlayerOpen) {
|
||||
entries.add(StreamDialogEntry.enqueue)
|
||||
|
||||
if (PlayerHolder.getInstance().queueSize > 1) {
|
||||
entries.add(StreamDialogEntry.enqueue_next)
|
||||
}
|
||||
}
|
||||
|
||||
if (item.streamType == StreamType.AUDIO_STREAM) {
|
||||
entries.addAll(
|
||||
listOf(
|
||||
|
|
|
|||
|
|
@ -338,9 +338,14 @@ public class StatisticsPlaylistFragment
|
|||
|
||||
final ArrayList<StreamDialogEntry> entries = new ArrayList<>();
|
||||
|
||||
if (PlayerHolder.getInstance().getType() != null) {
|
||||
if (PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
entries.add(StreamDialogEntry.enqueue);
|
||||
|
||||
if (PlayerHolder.getInstance().getQueueSize() > 1) {
|
||||
entries.add(StreamDialogEntry.enqueue_next);
|
||||
}
|
||||
}
|
||||
|
||||
if (infoItem.getStreamType() == StreamType.AUDIO_STREAM) {
|
||||
entries.addAll(Arrays.asList(
|
||||
StreamDialogEntry.start_here_on_background,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
|
|||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.local.BaseLocalListFragment;
|
||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||
import org.schabi.newpipe.player.MainPlayer.PlayerType;
|
||||
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||
|
|
@ -493,12 +494,12 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue(), false));
|
||||
|
||||
playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> {
|
||||
NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true);
|
||||
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.POPUP);
|
||||
return true;
|
||||
});
|
||||
|
||||
playlistControlBinding.playlistCtrlPlayBgButton.setOnLongClickListener(view -> {
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true);
|
||||
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.AUDIO);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
@ -752,8 +753,12 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||
|
||||
final ArrayList<StreamDialogEntry> entries = new ArrayList<>();
|
||||
|
||||
if (PlayerHolder.getInstance().getType() != null) {
|
||||
if (PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
entries.add(StreamDialogEntry.enqueue);
|
||||
|
||||
if (PlayerHolder.getInstance().getQueueSize() > 1) {
|
||||
entries.add(StreamDialogEntry.enqueue_next);
|
||||
}
|
||||
}
|
||||
if (infoItem.getStreamType() == StreamType.AUDIO_STREAM) {
|
||||
entries.addAll(Arrays.asList(
|
||||
|
|
|
|||
|
|
@ -226,10 +226,10 @@ public final class Player implements
|
|||
public static final String REPEAT_MODE = "repeat_mode";
|
||||
public static final String PLAYBACK_QUALITY = "playback_quality";
|
||||
public static final String PLAY_QUEUE_KEY = "play_queue_key";
|
||||
public static final String APPEND_ONLY = "append_only";
|
||||
public static final String ENQUEUE = "enqueue";
|
||||
public static final String ENQUEUE_NEXT = "enqueue_next";
|
||||
public static final String RESUME_PLAYBACK = "resume_playback";
|
||||
public static final String PLAY_WHEN_READY = "play_when_ready";
|
||||
public static final String SELECT_ON_APPEND = "select_on_append";
|
||||
public static final String PLAYER_TYPE = "player_type";
|
||||
public static final String IS_MUTED = "is_muted";
|
||||
|
||||
|
|
@ -238,7 +238,7 @@ public final class Player implements
|
|||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public static final int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds
|
||||
public static final int PROGRESS_LOOP_INTERVAL_MILLIS = 500; // 500 millis
|
||||
public static final int PROGRESS_LOOP_INTERVAL_MILLIS = 1000; // 1 second
|
||||
public static final int DEFAULT_CONTROLS_DURATION = 300; // 300 millis
|
||||
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
|
||||
public static final int DPAD_CONTROLS_HIDE_TIME = 7000; // 7 Seconds
|
||||
|
|
@ -608,16 +608,16 @@ public final class Player implements
|
|||
setPlaybackQuality(intent.getStringExtra(PLAYBACK_QUALITY));
|
||||
}
|
||||
|
||||
// Resolve append intents
|
||||
if (intent.getBooleanExtra(APPEND_ONLY, false) && playQueue != null) {
|
||||
final int sizeBeforeAppend = playQueue.size();
|
||||
// Resolve enqueue intents
|
||||
if (intent.getBooleanExtra(ENQUEUE, false) && playQueue != null) {
|
||||
playQueue.append(newQueue.getStreams());
|
||||
return;
|
||||
|
||||
if ((intent.getBooleanExtra(SELECT_ON_APPEND, false)
|
||||
|| currentState == STATE_COMPLETED) && newQueue.getStreams().size() > 0) {
|
||||
playQueue.setIndex(sizeBeforeAppend);
|
||||
}
|
||||
|
||||
// Resolve enqueue next intents
|
||||
} else if (intent.getBooleanExtra(ENQUEUE_NEXT, false) && playQueue != null) {
|
||||
final int currentIndex = playQueue.getIndex();
|
||||
playQueue.append(newQueue.getStreams());
|
||||
playQueue.move(playQueue.size() - 1, currentIndex + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2326,7 +2326,7 @@ public final class Player implements
|
|||
Log.d(TAG, "ExoPlayer - onRepeatModeChanged() called with: "
|
||||
+ "repeatMode = [" + repeatMode + "]");
|
||||
}
|
||||
setRepeatModeButton(((AppCompatImageButton) binding.repeatButton), repeatMode);
|
||||
setRepeatModeButton(binding.repeatButton, repeatMode);
|
||||
onShuffleOrRepeatModeChanged();
|
||||
}
|
||||
|
||||
|
|
@ -3189,7 +3189,7 @@ public final class Player implements
|
|||
private StreamSegmentAdapter.StreamSegmentListener getStreamSegmentListener() {
|
||||
return (item, seconds) -> {
|
||||
segmentAdapter.selectSegment(item);
|
||||
seekTo(seconds * 1000);
|
||||
seekTo(seconds * 1000L);
|
||||
triggerProgressUpdate();
|
||||
};
|
||||
}
|
||||
|
|
@ -3199,7 +3199,7 @@ public final class Player implements
|
|||
final List<StreamSegment> segments = currentMetadata.getMetadata().getStreamSegments();
|
||||
|
||||
for (int i = 0; i < segments.size(); i++) {
|
||||
if (segments.get(i).getStartTimeSeconds() * 1000 > playbackPosition) {
|
||||
if (segments.get(i).getStartTimeSeconds() * 1000L > playbackPosition) {
|
||||
break;
|
||||
}
|
||||
nearestPosition++;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@ public final class PlayerHolder {
|
|||
return player != null;
|
||||
}
|
||||
|
||||
public int getQueueSize() {
|
||||
return isPlayerOpen() ? player.getPlayQueue().size() : 0;
|
||||
}
|
||||
|
||||
public void setListener(@Nullable final PlayerServiceExtendedEventListener newListener) {
|
||||
listener = newListener;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
|
|||
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
|
||||
import org.schabi.newpipe.player.MainPlayer;
|
||||
import org.schabi.newpipe.player.MainPlayer.PlayerType;
|
||||
import org.schabi.newpipe.player.NotificationUtil;
|
||||
import org.schabi.newpipe.player.PlayQueueActivity;
|
||||
import org.schabi.newpipe.player.Player;
|
||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||
|
|
@ -58,9 +60,12 @@ import java.util.ArrayList;
|
|||
|
||||
import static org.schabi.newpipe.util.external_communication.ShareUtils.installApp;
|
||||
|
||||
import com.jakewharton.processphoenix.ProcessPhoenix;
|
||||
|
||||
public final class NavigationHelper {
|
||||
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
|
||||
public static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
|
||||
private static final String TAG = NotificationUtil.class.getSimpleName();
|
||||
|
||||
private NavigationHelper() {
|
||||
}
|
||||
|
|
@ -68,12 +73,11 @@ public final class NavigationHelper {
|
|||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Players
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/* INTENT */
|
||||
@NonNull
|
||||
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
||||
@NonNull final Class<T> targetClazz,
|
||||
@Nullable final PlayQueue playQueue,
|
||||
final boolean resumePlayback) {
|
||||
@Nullable final PlayQueue playQueue) {
|
||||
final Intent intent = new Intent(context, targetClazz);
|
||||
|
||||
if (playQueue != null) {
|
||||
|
|
@ -82,7 +86,6 @@ public final class NavigationHelper {
|
|||
intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
|
||||
}
|
||||
}
|
||||
intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
|
||||
intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.VIDEO.ordinal());
|
||||
|
||||
return intent;
|
||||
|
|
@ -92,23 +95,28 @@ public final class NavigationHelper {
|
|||
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
||||
@NonNull final Class<T> targetClazz,
|
||||
@Nullable final PlayQueue playQueue,
|
||||
final boolean resumePlayback,
|
||||
final boolean playWhenReady) {
|
||||
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
|
||||
return getPlayerIntent(context, targetClazz, playQueue)
|
||||
.putExtra(Player.PLAY_WHEN_READY, playWhenReady);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> Intent getPlayerEnqueueIntent(@NonNull final Context context,
|
||||
@NonNull final Class<T> targetClazz,
|
||||
@Nullable final PlayQueue playQueue,
|
||||
final boolean selectOnAppend,
|
||||
final boolean resumePlayback) {
|
||||
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
|
||||
.putExtra(Player.APPEND_ONLY, true)
|
||||
.putExtra(Player.SELECT_ON_APPEND, selectOnAppend);
|
||||
@Nullable final PlayQueue playQueue) {
|
||||
return getPlayerIntent(context, targetClazz, playQueue)
|
||||
.putExtra(Player.ENQUEUE, true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> Intent getPlayerEnqueueNextIntent(@NonNull final Context context,
|
||||
@NonNull final Class<T> targetClazz,
|
||||
@Nullable final PlayQueue playQueue) {
|
||||
return getPlayerIntent(context, targetClazz, playQueue)
|
||||
.putExtra(Player.ENQUEUE_NEXT, true);
|
||||
}
|
||||
|
||||
/* PLAY */
|
||||
public static void playOnMainPlayer(final AppCompatActivity activity,
|
||||
@NonNull final PlayQueue playQueue) {
|
||||
final PlayQueueItem item = playQueue.getItem();
|
||||
|
|
@ -154,56 +162,38 @@ public final class NavigationHelper {
|
|||
ContextCompat.startForegroundService(context, intent);
|
||||
}
|
||||
|
||||
public static void enqueueOnVideoPlayer(final Context context, final PlayQueue queue,
|
||||
final boolean resumePlayback) {
|
||||
enqueueOnVideoPlayer(context, queue, false, resumePlayback);
|
||||
}
|
||||
|
||||
public static void enqueueOnVideoPlayer(final Context context, final PlayQueue queue,
|
||||
final boolean selectOnAppend,
|
||||
final boolean resumePlayback) {
|
||||
|
||||
/* ENQUEUE */
|
||||
public static void enqueueOnPlayer(final Context context,
|
||||
final PlayQueue queue,
|
||||
final PlayerType playerType) {
|
||||
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
|
||||
final Intent intent = getPlayerEnqueueIntent(
|
||||
context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
|
||||
final Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue);
|
||||
|
||||
intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.VIDEO.ordinal());
|
||||
intent.putExtra(Player.PLAYER_TYPE, playerType.ordinal());
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
}
|
||||
|
||||
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue,
|
||||
final boolean resumePlayback) {
|
||||
enqueueOnPopupPlayer(context, queue, false, resumePlayback);
|
||||
}
|
||||
|
||||
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue,
|
||||
final boolean selectOnAppend,
|
||||
final boolean resumePlayback) {
|
||||
if (!PermissionHelper.isPopupEnabled(context)) {
|
||||
PermissionHelper.showPopupEnablementToast(context);
|
||||
return;
|
||||
public static void enqueueOnPlayer(final Context context, final PlayQueue queue) {
|
||||
PlayerType playerType = PlayerHolder.getInstance().getType();
|
||||
if (!PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
Log.e(TAG, "Enqueueing but no player is open; defaulting to background player");
|
||||
playerType = MainPlayer.PlayerType.AUDIO;
|
||||
}
|
||||
|
||||
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
|
||||
final Intent intent = getPlayerEnqueueIntent(
|
||||
context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
|
||||
intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.POPUP.ordinal());
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
enqueueOnPlayer(context, queue, playerType);
|
||||
}
|
||||
|
||||
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue,
|
||||
final boolean resumePlayback) {
|
||||
enqueueOnBackgroundPlayer(context, queue, false, resumePlayback);
|
||||
}
|
||||
/* ENQUEUE NEXT */
|
||||
public static void enqueueNextOnPlayer(final Context context, final PlayQueue queue) {
|
||||
PlayerType playerType = PlayerHolder.getInstance().getType();
|
||||
if (!PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
Log.e(TAG, "Enqueueing next but no player is open; defaulting to background player");
|
||||
playerType = MainPlayer.PlayerType.AUDIO;
|
||||
}
|
||||
Toast.makeText(context, R.string.enqueued_next, Toast.LENGTH_SHORT).show();
|
||||
final Intent intent = getPlayerEnqueueNextIntent(context, MainPlayer.class, queue);
|
||||
|
||||
public static void enqueueOnBackgroundPlayer(final Context context,
|
||||
final PlayQueue queue,
|
||||
final boolean selectOnAppend,
|
||||
final boolean resumePlayback) {
|
||||
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
|
||||
final Intent intent = getPlayerEnqueueIntent(
|
||||
context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
|
||||
intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.AUDIO.ordinal());
|
||||
intent.putExtra(Player.PLAYER_TYPE, playerType.ordinal());
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
}
|
||||
|
||||
|
|
@ -346,7 +336,7 @@ public final class NavigationHelper {
|
|||
|
||||
final boolean autoPlay;
|
||||
@Nullable final MainPlayer.PlayerType playerType = PlayerHolder.getInstance().getType();
|
||||
if (playerType == null) {
|
||||
if (!PlayerHolder.getInstance().isPlayerOpen()) {
|
||||
// no player open
|
||||
autoPlay = PlayerHelper.isAutoplayAllowedByUser(context);
|
||||
} else if (switchingPlayers) {
|
||||
|
|
@ -360,7 +350,7 @@ public final class NavigationHelper {
|
|||
autoPlay = false;
|
||||
}
|
||||
|
||||
final RunnableWithVideoDetailFragment onVideoDetailFragmentReady = (detailFragment) -> {
|
||||
final RunnableWithVideoDetailFragment onVideoDetailFragmentReady = detailFragment -> {
|
||||
expandMainPlayer(detailFragment.requireActivity());
|
||||
detailFragment.setAutoPlay(autoPlay);
|
||||
if (switchingPlayers) {
|
||||
|
|
@ -613,8 +603,7 @@ public final class NavigationHelper {
|
|||
*/
|
||||
public static void restartApp(final Activity activity) {
|
||||
NewPipeDatabase.close();
|
||||
activity.finishAffinity();
|
||||
final Intent intent = new Intent(activity, MainActivity.class);
|
||||
activity.startActivity(intent);
|
||||
|
||||
ProcessPhoenix.triggerRebirth(activity.getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public final class PermissionHelper {
|
|||
|
||||
public static boolean isPopupEnabled(final Context context) {
|
||||
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
||||
|| PermissionHelper.checkSystemAlertWindowPermission(context);
|
||||
|| checkSystemAlertWindowPermission(context);
|
||||
}
|
||||
|
||||
public static void showPopupEnablementToast(final Context context) {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
|||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||
import org.schabi.newpipe.local.dialog.PlaylistCreationDialog;
|
||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||
import org.schabi.newpipe.player.MainPlayer;
|
||||
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||
import org.schabi.newpipe.util.external_communication.KoreUtils;
|
||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||
|
|
@ -25,8 +23,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
import static org.schabi.newpipe.player.MainPlayer.PlayerType.AUDIO;
|
||||
import static org.schabi.newpipe.player.MainPlayer.PlayerType.POPUP;
|
||||
|
||||
public enum StreamDialogEntry {
|
||||
//////////////////////////////////////
|
||||
|
|
@ -43,7 +39,7 @@ public enum StreamDialogEntry {
|
|||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
NewPipeDatabase.getInstance(fragment.getContext()).streamDAO()
|
||||
NewPipeDatabase.getInstance(fragment.requireContext()).streamDAO()
|
||||
.setUploaderUrl(serviceId, url, result.getUploaderUrl())
|
||||
.subscribeOn(Schedulers.io()).subscribe();
|
||||
openChannelFragment(fragment, item, result.getUploaderUrl());
|
||||
|
|
@ -64,18 +60,11 @@ public enum StreamDialogEntry {
|
|||
* Info: Add this entry within showStreamDialog.
|
||||
*/
|
||||
enqueue(R.string.enqueue_stream, (fragment, item) -> {
|
||||
final MainPlayer.PlayerType type = PlayerHolder.getInstance().getType();
|
||||
NavigationHelper.enqueueOnPlayer(fragment.getContext(), new SinglePlayQueue(item));
|
||||
}),
|
||||
|
||||
if (type == AUDIO) {
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(fragment.getContext(),
|
||||
new SinglePlayQueue(item), false);
|
||||
} else if (type == POPUP) {
|
||||
NavigationHelper.enqueueOnPopupPlayer(fragment.getContext(),
|
||||
new SinglePlayQueue(item), false);
|
||||
} else /* type == VIDEO */ {
|
||||
NavigationHelper.enqueueOnVideoPlayer(fragment.getContext(),
|
||||
new SinglePlayQueue(item), false);
|
||||
}
|
||||
enqueue_next(R.string.enqueue_next_stream, (fragment, item) -> {
|
||||
NavigationHelper.enqueueNextOnPlayer(fragment.getContext(), new SinglePlayQueue(item));
|
||||
}),
|
||||
|
||||
start_here_on_background(R.string.start_here_on_background, (fragment, item) ->
|
||||
|
|
@ -108,16 +97,16 @@ public enum StreamDialogEntry {
|
|||
try {
|
||||
NavigationHelper.playWithKore(fragment.requireContext(), videoUrl);
|
||||
} catch (final Exception e) {
|
||||
KoreUtils.showInstallKoreDialog(fragment.getActivity());
|
||||
KoreUtils.showInstallKoreDialog(fragment.requireActivity());
|
||||
}
|
||||
}),
|
||||
|
||||
share(R.string.share, (fragment, item) ->
|
||||
ShareUtils.shareText(fragment.getContext(), item.getName(), item.getUrl(),
|
||||
ShareUtils.shareText(fragment.requireContext(), item.getName(), item.getUrl(),
|
||||
item.getThumbnailUrl())),
|
||||
|
||||
open_in_browser(R.string.open_in_browser, (fragment, item) ->
|
||||
ShareUtils.openUrlInBrowser(fragment.getContext(), item.getUrl())),
|
||||
ShareUtils.openUrlInBrowser(fragment.requireContext(), item.getUrl())),
|
||||
|
||||
|
||||
mark_as_watched(R.string.mark_as_watched, (fragment, item) -> {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
package org.schabi.newpipe.util.external_communication;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.error.ErrorPanelHelper;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
|
|
@ -24,6 +29,9 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public final class InternalUrlsHandler {
|
||||
private static final String TAG = InternalUrlsHandler.class.getSimpleName();
|
||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||
|
||||
private static final Pattern AMPERSAND_TIMESTAMP_PATTERN = Pattern.compile("(.*)&t=(\\d+)");
|
||||
private static final Pattern HASHTAG_TIMESTAMP_PATTERN =
|
||||
Pattern.compile("(.*)#timestamp=(\\d+)");
|
||||
|
|
@ -93,7 +101,12 @@ public final class InternalUrlsHandler {
|
|||
return false;
|
||||
}
|
||||
final String matchedUrl = matcher.group(1);
|
||||
final int seconds = Integer.parseInt(matcher.group(2));
|
||||
final int seconds;
|
||||
if (matcher.group(2) == null) {
|
||||
seconds = -1;
|
||||
} else {
|
||||
seconds = Integer.parseInt(matcher.group(2));
|
||||
}
|
||||
|
||||
final StreamingService service;
|
||||
final StreamingService.LinkType linkType;
|
||||
|
|
@ -146,8 +159,18 @@ public final class InternalUrlsHandler {
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(info -> {
|
||||
final PlayQueue playQueue
|
||||
= new SinglePlayQueue(info, seconds * 1000);
|
||||
= new SinglePlayQueue(info, seconds * 1000L);
|
||||
NavigationHelper.playOnPopupPlayer(context, playQueue, false);
|
||||
}, throwable -> {
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, "Could not play on popup: " + url, throwable);
|
||||
}
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.player_stream_failure)
|
||||
.setMessage(
|
||||
ErrorPanelHelper.Companion.getExceptionDescription(throwable))
|
||||
.setPositiveButton(R.string.ok, (v, b) -> { })
|
||||
.show();
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue