Update extractor and refactored NewPipe

This commit is contained in:
Mauricio Colli 2017-09-03 03:04:18 -03:00
parent bddd9b3409
commit 146d4a8365
254 changed files with 7836 additions and 7302 deletions

View file

@ -1,6 +1,24 @@
/*
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
* BackgroundPlayer.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.player;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
@ -22,7 +40,7 @@ import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.stream_info.AudioStream;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ThemeHelper;
@ -66,7 +84,6 @@ public class BackgroundPlayer extends Service {
private RemoteViews bigNotRemoteView;
private final String setAlphaMethodName = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) ? "setImageAlpha" : "setAlpha";
/*//////////////////////////////////////////////////////////////////////////
// Service's LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@ -159,7 +176,7 @@ public class BackgroundPlayer extends Service {
//if (videoThumbnail != null) remoteViews.setImageViewBitmap(R.id.notificationCover, videoThumbnail);
///else remoteViews.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
remoteViews.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getChannelName());
remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));

View file

@ -1,3 +1,22 @@
/*
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
* BasePlayer.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.player;
import android.animation.Animator;
@ -49,6 +68,7 @@ import com.google.android.exoplayer2.util.Util;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.R;
import java.io.File;
@ -65,6 +85,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class BasePlayer implements Player.EventListener, AudioManager.OnAudioFocusChangeListener {
// TODO: Check api version for deprecated audio manager methods
public static final boolean DEBUG = false;
public static final String TAG = "BasePlayer";
@ -90,8 +112,8 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
protected String videoUrl = "";
protected String videoTitle = "";
protected String videoThumbnailUrl = "";
protected int videoStartPos = -1;
protected String channelName = "";
protected long videoStartPos = -1;
protected String uploaderName = "";
/*//////////////////////////////////////////////////////////////////////////
// Player
@ -139,7 +161,7 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
private void initExoPlayerCache() {
if (cacheDataSourceFactory == null) {
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, context.getPackageName()), bandwidthMeter);
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(context, Downloader.USER_AGENT, bandwidthMeter);
File cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
if (!cacheDir.exists()) {
//noinspection ResultOfMethodCallIgnored
@ -183,8 +205,8 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
videoUrl = intent.getStringExtra(VIDEO_URL);
videoTitle = intent.getStringExtra(VIDEO_TITLE);
videoThumbnailUrl = intent.getStringExtra(VIDEO_THUMBNAIL_URL);
videoStartPos = intent.getIntExtra(START_POSITION, -1);
channelName = intent.getStringExtra(CHANNEL_NAME);
videoStartPos = intent.getLongExtra(START_POSITION, -1L);
uploaderName = intent.getStringExtra(CHANNEL_NAME);
setPlaybackSpeed(intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed()));
initThumbnail();
@ -200,7 +222,8 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
if (simpleExoPlayer == null) return;
if (DEBUG) Log.d(TAG, "onLoadingComplete() called with: imageUri = [" + imageUri + "], view = [" + view + "], loadedImage = [" + loadedImage + "]");
if (DEBUG)
Log.d(TAG, "onLoadingComplete() called with: imageUri = [" + imageUri + "], view = [" + view + "], loadedImage = [" + loadedImage + "]");
videoThumbnail = loadedImage;
onThumbnailReceived(loadedImage);
}
@ -236,6 +259,10 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
simpleExoPlayer.release();
}
if (progressLoop != null && isProgressLoopRunning.get()) stopProgressLoop();
if (audioManager != null) {
audioManager.abandonAudioFocus(this);
audioManager = null;
}
}
public void destroy() {
@ -327,12 +354,8 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
}
private boolean isResumeAfterAudioFocusGain() {
if (this.sharedPreferences == null || this.context == null) return false;
return this.sharedPreferences.getBoolean(
this.context.getString(R.string.resume_on_audio_focus_gain_key),
false
);
return sharedPreferences != null && context != null
&& sharedPreferences.getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), false);
}
protected void onAudioFocusGain() {
@ -473,7 +496,8 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (DEBUG) Log.d(TAG, "onPlayerStateChanged() called with: playWhenReady = [" + playWhenReady + "], playbackState = [" + playbackState + "]");
if (DEBUG)
Log.d(TAG, "onPlayerStateChanged() called with: playWhenReady = [" + playWhenReady + "], playbackState = [" + playbackState + "]");
if (getCurrentState() == STATE_PAUSED_SEEK) {
if (DEBUG) Log.d(TAG, "onPlayerStateChanged() currently on PausedSeek");
return;
@ -516,7 +540,9 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
// General Player
//////////////////////////////////////////////////////////////////////////*/
public abstract void onError(Exception exception);
public void onError(Exception exception){
destroy();
}
public void onPrepared(boolean playWhenReady) {
if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]");
@ -565,7 +591,8 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
public void seekBy(int milliSeconds) {
if (DEBUG) Log.d(TAG, "seekBy() called with: milliSeconds = [" + milliSeconds + "]");
if (simpleExoPlayer == null || (isCompleted() && milliSeconds > 0) || ((milliSeconds < 0 && simpleExoPlayer.getCurrentPosition() == 0))) return;
if (simpleExoPlayer == null || (isCompleted() && milliSeconds > 0) || ((milliSeconds < 0 && simpleExoPlayer.getCurrentPosition() == 0)))
return;
int progress = (int) (simpleExoPlayer.getCurrentPosition() + milliSeconds);
if (progress < 0) progress = 0;
simpleExoPlayer.seekTo(progress);
@ -693,11 +720,11 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
this.videoUrl = videoUrl;
}
public int getVideoStartPos() {
public long getVideoStartPos() {
return videoStartPos;
}
public void setVideoStartPos(int videoStartPos) {
public void setVideoStartPos(long videoStartPos) {
this.videoStartPos = videoStartPos;
}
@ -709,12 +736,12 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
this.videoTitle = videoTitle;
}
public String getChannelName() {
return channelName;
public String getUploaderName() {
return uploaderName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
public void setUploaderName(String uploaderName) {
this.uploaderName = uploaderName;
}
public boolean isCompleted() {

View file

@ -1,3 +1,22 @@
/*
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
* MainVideoPlayer.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.player;
import android.app.Activity;
@ -169,14 +188,14 @@ public class MainVideoPlayer extends Activity {
@Override
public void initViews(View rootView) {
super.initViews(rootView);
this.titleTextView = (TextView) rootView.findViewById(R.id.titleTextView);
this.channelTextView = (TextView) rootView.findViewById(R.id.channelTextView);
this.volumeTextView = (TextView) rootView.findViewById(R.id.volumeTextView);
this.brightnessTextView = (TextView) rootView.findViewById(R.id.brightnessTextView);
this.repeatButton = (ImageButton) rootView.findViewById(R.id.repeatButton);
this.titleTextView = rootView.findViewById(R.id.titleTextView);
this.channelTextView = rootView.findViewById(R.id.channelTextView);
this.volumeTextView = rootView.findViewById(R.id.volumeTextView);
this.brightnessTextView = rootView.findViewById(R.id.brightnessTextView);
this.repeatButton = rootView.findViewById(R.id.repeatButton);
this.screenRotationButton = (ImageButton) rootView.findViewById(R.id.screenRotationButton);
this.playPauseButton = (ImageButton) rootView.findViewById(R.id.playPauseButton);
this.screenRotationButton = rootView.findViewById(R.id.screenRotationButton);
this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
// Due to a bug on lower API, lets set the alpha instead of using a drawable
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) repeatButton.setImageAlpha(77);
@ -205,7 +224,7 @@ public class MainVideoPlayer extends Activity {
public void handleIntent(Intent intent) {
super.handleIntent(intent);
titleTextView.setText(getVideoTitle());
channelTextView.setText(getChannelName());
channelTextView.setText(getUploaderName());
}
@Override

View file

@ -1,3 +1,22 @@
/*
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
* PopupVideoPlayer.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.player;
import android.annotation.SuppressLint;
@ -15,6 +34,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.util.DisplayMetrics;
import android.util.Log;
@ -38,13 +58,29 @@ import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.Utils;
import org.schabi.newpipe.workers.StreamExtractorWorker;
import java.io.IOException;
import java.util.ArrayList;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
@ -87,7 +123,7 @@ public class PopupVideoPlayer extends Service {
private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build();
private VideoPlayerImpl playerImpl;
private StreamExtractorWorker currentExtractorWorker;
private Disposable currentWorker;
/*//////////////////////////////////////////////////////////////////////////
// Service LifeCycle
@ -105,15 +141,33 @@ public class PopupVideoPlayer extends Service {
@Override
@SuppressWarnings("unchecked")
public int onStartCommand(final Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "], flags = [" + flags + "], startId = [" + startId + "]");
if (DEBUG)
Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "], flags = [" + flags + "], startId = [" + startId + "]");
if (playerImpl.getPlayer() == null) initPopup();
if (!playerImpl.isPlaying()) playerImpl.getPlayer().setPlayWhenReady(true);
if (imageLoader != null) imageLoader.clearMemoryCache();
if (intent.getStringExtra(Constants.KEY_URL) != null) {
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
final String url = intent.getStringExtra(Constants.KEY_URL);
playerImpl.setStartedFromNewPipe(false);
currentExtractorWorker = new StreamExtractorWorker(this, 0, intent.getStringExtra(Constants.KEY_URL), new FetcherRunnable(this));
currentExtractorWorker.start();
final FetcherHandler fetcherRunnable = new FetcherHandler(this, serviceId, url);
currentWorker = ExtractorHelper.getStreamInfo(serviceId,url,false)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<StreamInfo>() {
@Override
public void accept(@NonNull StreamInfo info) throws Exception {
fetcherRunnable.onReceive(info);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
fetcherRunnable.onError(throwable);
}
});
} else {
playerImpl.setStartedFromNewPipe(true);
playerImpl.handleIntent(intent);
@ -137,11 +191,7 @@ public class PopupVideoPlayer extends Service {
if (playerImpl.getRootView() != null) windowManager.removeView(playerImpl.getRootView());
}
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
if (currentExtractorWorker != null) {
currentExtractorWorker.cancel();
currentExtractorWorker = null;
}
if (currentWorker != null) currentWorker.dispose();
savePositionAndSize();
}
@ -204,7 +254,7 @@ public class PopupVideoPlayer extends Service {
else notRemoteView.setImageViewBitmap(R.id.notificationCover, playerImpl.getVideoThumbnail());
notRemoteView.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle());
notRemoteView.setTextViewText(R.id.notificationArtist, playerImpl.getChannelName());
notRemoteView.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName());
notRemoteView.setOnClickPendingIntent(R.id.notificationPlayPause,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
@ -275,9 +325,11 @@ public class PopupVideoPlayer extends Service {
//////////////////////////////////////////////////////////////////////////*/
private void checkPositionBounds() {
if (windowLayoutParams.x > screenWidth - windowLayoutParams.width) windowLayoutParams.x = (int) (screenWidth - windowLayoutParams.width);
if (windowLayoutParams.x > screenWidth - windowLayoutParams.width)
windowLayoutParams.x = (int) (screenWidth - windowLayoutParams.width);
if (windowLayoutParams.x < 0) windowLayoutParams.x = 0;
if (windowLayoutParams.y > screenHeight - windowLayoutParams.height) windowLayoutParams.y = (int) (screenHeight - windowLayoutParams.height);
if (windowLayoutParams.y > screenHeight - windowLayoutParams.height)
windowLayoutParams.y = (int) (screenHeight - windowLayoutParams.height);
if (windowLayoutParams.y < 0) windowLayoutParams.y = 0;
}
@ -352,7 +404,7 @@ public class PopupVideoPlayer extends Service {
@Override
public void initViews(View rootView) {
super.initViews(rootView);
resizingIndicator = (TextView) rootView.findViewById(R.id.resizing_indicator);
resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
}
@Override
@ -431,6 +483,7 @@ public class PopupVideoPlayer extends Service {
hideControls(100, 0);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Broadcast Receiver
//////////////////////////////////////////////////////////////////////////*/
@ -527,7 +580,8 @@ public class PopupVideoPlayer extends Service {
@Override
public boolean onDoubleTap(MotionEvent e) {
if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
if (DEBUG)
Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
if (!playerImpl.isPlaying()) return false;
if (e.getX() > popupWidth / 2) playerImpl.onFastForward();
else playerImpl.onFastRewind();
@ -621,7 +675,8 @@ public class PopupVideoPlayer extends Service {
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if (DEBUG) Log.d(TAG, "onTouch() ACTION_UP > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
if (DEBUG)
Log.d(TAG, "onTouch() ACTION_UP > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
if (isMoving) {
isMoving = false;
onScrollEnd();
@ -640,32 +695,36 @@ public class PopupVideoPlayer extends Service {
}
/**
* Fetcher used if open by a link out of NewPipe
* Fetcher handler used if open by a link out of NewPipe
*/
private class FetcherRunnable implements StreamExtractorWorker.OnStreamInfoReceivedListener {
private class FetcherHandler {
private final int serviceId;
private final String url;
private final Context context;
private final Handler mainHandler;
FetcherRunnable(Context context) {
FetcherHandler(Context context, int serviceId, String url) {
this.mainHandler = new Handler(PopupVideoPlayer.this.getMainLooper());
this.context = context;
this.url = url;
this.serviceId = serviceId;
}
@Override
public void onReceive(StreamInfo info) {
playerImpl.setVideoTitle(info.title);
playerImpl.setVideoUrl(info.webpage_url);
playerImpl.setVideoTitle(info.name);
playerImpl.setVideoUrl(info.url);
playerImpl.setVideoThumbnailUrl(info.thumbnail_url);
playerImpl.setChannelName(info.uploader);
playerImpl.setUploaderName(info.uploader_name);
playerImpl.setVideoStreamsList(Utils.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false));
playerImpl.setAudioStream(Utils.getHighestQualityAudio(info.audio_streams));
playerImpl.setVideoStreamsList(new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false)));
playerImpl.setAudioStream(ListHelper.getHighestQualityAudio(info.audio_streams));
int defaultResolution = Utils.getPopupDefaultResolution(context, playerImpl.getVideoStreamsList());
int defaultResolution = ListHelper.getPopupDefaultResolutionIndex(context, playerImpl.getVideoStreamsList());
playerImpl.setSelectedIndexStream(defaultResolution);
if (DEBUG) {
Log.d(TAG, "FetcherRunnable.StreamExtractor: chosen = "
Log.d(TAG, "FetcherHandler.StreamExtractor: chosen = "
+ MediaFormat.getNameById(info.video_streams.get(defaultResolution).format) + " "
+ info.video_streams.get(defaultResolution).resolution + " > "
+ info.video_streams.get(defaultResolution).url);
@ -686,7 +745,7 @@ public class PopupVideoPlayer extends Service {
@Override
public void onLoadingComplete(final String imageUri, View view, final Bitmap loadedImage) {
if (playerImpl == null || playerImpl.getPlayer() == null) return;
if (DEBUG) Log.d(TAG, "FetcherRunnable.imageLoader.onLoadingComplete() called with: imageUri = [" + imageUri + "]");
if (DEBUG) Log.d(TAG, "FetcherHandler.imageLoader.onLoadingComplete() called with: imageUri = [" + imageUri + "]");
mainHandler.post(new Runnable() {
@Override
public void run() {
@ -699,70 +758,40 @@ public class PopupVideoPlayer extends Service {
});
}
@Override
public void onError(final int messageId) {
protected void onError(final Throwable exception) {
if (DEBUG) Log.d(TAG, "onError() called with: exception = [" + exception + "]");
exception.printStackTrace();
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, messageId, Toast.LENGTH_LONG).show();
if (exception instanceof ReCaptchaException) {
onReCaptchaException();
} else if (exception instanceof IOException) {
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.GemaException) {
Toast.makeText(context, R.string.blocked_by_gema, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.LiveStreamException) {
Toast.makeText(context, R.string.live_streams_not_supported, Toast.LENGTH_LONG).show();
} else if (exception instanceof ContentNotAvailableException) {
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
} else {
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException ? R.string.youtube_signature_decryption_error :
exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
ErrorActivity.reportError(mainHandler, context, exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, errorId));
}
}
});
stopSelf();
}
@Override
public void onReCaptchaException() {
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
}
});
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
// Starting ReCaptcha Challenge Activity
Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
stopSelf();
}
@Override
public void onBlockedByGemaError() {
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, R.string.blocked_by_gema, Toast.LENGTH_LONG).show();
}
});
stopSelf();
}
@Override
public void onContentErrorWithMessage(final int messageId) {
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, messageId, Toast.LENGTH_LONG).show();
}
});
stopSelf();
}
@Override
public void onContentError() {
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
}
});
stopSelf();
}
@Override
public void onUnrecoverableError(Exception exception) {
exception.printStackTrace();
stopSelf();
}
}
}

View file

@ -1,3 +1,22 @@
/*
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
* VideoPlayer.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.player;
import android.animation.Animator;
@ -26,7 +45,6 @@ import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
@ -36,8 +54,8 @@ import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream_info.AudioStream;
import org.schabi.newpipe.extractor.stream_info.VideoStream;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.util.AnimationUtils;
import java.io.Serializable;
@ -74,7 +92,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
// Player
//////////////////////////////////////////////////////////////////////////*/
public static final int DEFAULT_CONTROLS_HIDE_TIME = 3000; // 3 Seconds
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
private static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f};
private boolean startedFromNewPipe = true;
@ -133,26 +151,27 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
public void initViews(View rootView) {
this.rootView = rootView;
this.aspectRatioFrameLayout = (AspectRatioFrameLayout) rootView.findViewById(R.id.aspectRatioLayout);
this.surfaceView = (SurfaceView) rootView.findViewById(R.id.surfaceView);
this.aspectRatioFrameLayout = rootView.findViewById(R.id.aspectRatioLayout);
this.surfaceView = rootView.findViewById(R.id.surfaceView);
this.surfaceForeground = rootView.findViewById(R.id.surfaceForeground);
this.loadingPanel = rootView.findViewById(R.id.loading_panel);
this.endScreen = (ImageView) rootView.findViewById(R.id.endScreen);
this.controlAnimationView = (ImageView) rootView.findViewById(R.id.controlAnimationView);
this.endScreen = rootView.findViewById(R.id.endScreen);
this.controlAnimationView = rootView.findViewById(R.id.controlAnimationView);
this.controlsRoot = rootView.findViewById(R.id.playbackControlRoot);
this.currentDisplaySeek = (TextView) rootView.findViewById(R.id.currentDisplaySeek);
this.playbackSeekBar = (SeekBar) rootView.findViewById(R.id.playbackSeekBar);
this.playbackCurrentTime = (TextView) rootView.findViewById(R.id.playbackCurrentTime);
this.playbackEndTime = (TextView) rootView.findViewById(R.id.playbackEndTime);
this.playbackSpeed = (TextView) rootView.findViewById(R.id.playbackSpeed);
this.currentDisplaySeek = rootView.findViewById(R.id.currentDisplaySeek);
this.playbackSeekBar = rootView.findViewById(R.id.playbackSeekBar);
this.playbackCurrentTime = rootView.findViewById(R.id.playbackCurrentTime);
this.playbackEndTime = rootView.findViewById(R.id.playbackEndTime);
this.playbackSpeed = rootView.findViewById(R.id.playbackSpeed);
this.bottomControlsRoot = rootView.findViewById(R.id.bottomControls);
this.topControlsRoot = rootView.findViewById(R.id.topControls);
this.qualityTextView = (TextView) rootView.findViewById(R.id.qualityTextView);
this.fullScreenButton = (ImageButton) rootView.findViewById(R.id.fullScreenButton);
this.qualityTextView = rootView.findViewById(R.id.qualityTextView);
this.fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
//this.aspectRatioFrameLayout.setAspectRatio(16.0f / 9.0f);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
this.playbackSeekBar.getProgressDrawable().setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
this.qualityPopupMenu = new PopupMenu(context, qualityTextView);
@ -226,7 +245,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
@Override
public MediaSource buildMediaSource(String url, String overrideExtension) {
MediaSource mediaSource = super.buildMediaSource(url, overrideExtension);
if (!getSelectedVideoStream().isVideoOnly) return mediaSource;
if (!getSelectedVideoStream().isVideoOnly || videoOnlyAudioStream == null) return mediaSource;
Uri audioUri = Uri.parse(videoOnlyAudioStream.url);
return new MergingMediaSource(mediaSource, new ExtractorMediaSource(audioUri, cacheDataSourceFactory, extractorsFactory, null, null));
@ -269,7 +288,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
playbackSeekBar.setProgress(0);
// Bug on lower api, disabling and enabling the seekBar resets the thumb color -.-, so sets the color again
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
animateView(endScreen, false, 0);
loadingPanel.setBackgroundColor(Color.BLACK);
@ -324,7 +344,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
playbackEndTime.setText(getTimeString(playbackSeekBar.getMax()));
playbackCurrentTime.setText(playbackEndTime.getText());
// Bug on lower api, disabling and enabling the seekBar resets the thumb color -.-, so sets the color again
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
animateView(surfaceForeground, true, 100);
@ -360,8 +381,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]");
if (videoStartPos > 0) {
playbackSeekBar.setProgress(videoStartPos);
playbackCurrentTime.setText(getTimeString(videoStartPos));
playbackSeekBar.setProgress((int) videoStartPos);
playbackCurrentTime.setText(getTimeString((int) videoStartPos));
videoStartPos = -1;
}
@ -444,11 +465,12 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
*/
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
if (DEBUG) Log.d(TAG, "onMenuItemClick() called with: menuItem = [" + menuItem + "], menuItem.getItemId = [" + menuItem.getItemId() + "]");
if (DEBUG)
Log.d(TAG, "onMenuItemClick() called with: menuItem = [" + menuItem + "], menuItem.getItemId = [" + menuItem.getItemId() + "]");
if (qualityPopupMenuGroupId == menuItem.getGroupId()) {
if (selectedIndexStream == menuItem.getItemId()) return true;
setVideoStartPos((int) simpleExoPlayer.getCurrentPosition());
setVideoStartPos(simpleExoPlayer.getCurrentPosition());
selectedIndexStream = menuItem.getItemId();
if (!(getCurrentState() == STATE_COMPLETED)) play(wasPlaying);

View file

@ -1,4 +1,4 @@
package org.schabi.newpipe.player;
package org.schabi.newpipe.player.old;
import android.content.Context;
import android.content.Intent;
@ -29,7 +29,7 @@ import android.widget.VideoView;
import org.schabi.newpipe.R;
/**
/*
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* PlayVideoActivity.java is part of NewPipe.
*
@ -122,8 +122,8 @@ public class PlayVideoActivity extends AppCompatActivity {
position = intent.getIntExtra(START_POSITION, 0)*1000;//convert from seconds to milliseconds
videoView = (VideoView) findViewById(R.id.video_view);
progressBar = (ProgressBar) findViewById(R.id.play_video_progress_bar);
videoView = findViewById(R.id.video_view);
progressBar = findViewById(R.id.play_video_progress_bar);
try {
videoView.setMediaController(mediaController);
videoView.setVideoURI(Uri.parse(intent.getStringExtra(STREAM_URL)));
@ -146,7 +146,7 @@ public class PlayVideoActivity extends AppCompatActivity {
});
videoUrl = intent.getStringExtra(VIDEO_URL);
Button button = (Button) findViewById(R.id.content_button);
Button button = findViewById(R.id.content_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {