diff --git a/.travis.yml b/.travis.yml index d5d3aed9c..d6f97ab55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,13 @@ android: components: # The BuildTools version used by NewPipe - tools - - build-tools-27.0.3 + - build-tools-28.0.3 # The SDK version used to compile NewPipe - - android-27 + - android-28 before_install: - - yes | sdkmanager "platforms;android-27" + - yes | sdkmanager "platforms;android-28" script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug testDebugUnitTest licenses: diff --git a/README.md b/README.md index b154fad58..15ba3d04b 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,77 @@ -
+Screenshots • Description • Features • Contribution • Donate • License
-
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_1.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_2.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_3.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_4.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_5.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_6.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_7.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
+[
](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
+[
](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
## Description
-NewPipe does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without Google Services installed. Also, you don't need a YouTube account to use NewPipe, and it's FLOSS.
+NewPipe does not use any Google framework libraries, nor the YouTube API. Websites are only parsed to fetch required info, so this app can be used on devices without Google services installed. Also, you don't need a YouTube account to use NewPipe, which is copylefted libre software.
### Features
* Search videos
-* Display general information about a video
+* Display general info about videos
* Watch YouTube videos
* Listen to YouTube videos
* Popup mode (floating player)
-* Select the streaming player to watch the video with
-* Download videos
+* Select streaming player to watch video with
+* Download videos
* Download audio only
* Open a video in Kodi
-* Show Next/Related videos
+* Show next/related videos
* Search YouTube in a specific language
* Watch/Block age restricted material
-* Display general information about channels
+* Display general info about channels
* Search channels
* Watch videos from a channel
* Orbot/Tor support (not yet directly)
-* 1080p/2k/4k support
+* 1080p/2K/4K support
* View history
* Subscribe to channels
* Search history
-* Search/Watch Playlists
-* Watch as queues Playlists
-* Queuing videos
+* Search/watch playlists
+* Watch as enqueued playlists
+* Enqueue videos
* Local playlists
* Subtitles
-* Multi-service support (eg. SoundCloud in NewPipe Beta)
+* Multi-service support (e.g. SoundCloud \[beta\])
+* Livestream support
### Coming Features
-* Livestream support
* Cast to UPnP and Cast
* Show comments
-* ... and many more
+* … and many more
## Contribution
Whether you have ideas, translations, design changes, code cleaning, or real heavy code changes, help is always welcome.
@@ -77,26 +80,31 @@ The more is done the better it gets!
If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).
## Donate
-If you like NewPipe we'd be happy about a donation. You can either donate via Bitcoin, Bountysource or Liberapay. For further information about donating to NewPipe, please visit our [website](https://newpipe.schabi.org/donate).
+If you like NewPipe we'd be happy about a donation. You can either send bitcoin or donate via Bountysource or Liberapay. For further info on donating to NewPipe, please visit our [website](https://newpipe.schabi.org/donate).
![]() |
+ ![]() |
16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh | |||
![]() |
- ![]() |
+ ||||
![]() |
- ![]() |
+
* {@link ExoPlaybackException#TYPE_SOURCE TYPE_SOURCE}:
- *
+ *
* {@link ExoPlaybackException#TYPE_UNEXPECTED TYPE_UNEXPECTED}:
* If a runtime error occurred, then we can try to recover it by restarting the playback
* after setting the timestamp recovery.
- *
+ *
* {@link ExoPlaybackException#TYPE_RENDERER TYPE_RENDERER}:
* If the renderer failed, treat the error as unrecoverable.
*
* @see #processSourceError(IOException)
* @see Player.EventListener#onPlayerError(ExoPlaybackException)
- * */
+ */
@Override
public void onPlayerError(ExoPlaybackException error) {
if (DEBUG) Log.d(TAG, "ExoPlayer - onPlayerError() called with: " +
@@ -900,8 +926,8 @@ public abstract class BasePlayer implements
if (DEBUG) Log.d(TAG, "onPlayPrevious() called");
/* If current playback has run for PLAY_PREV_ACTIVATION_LIMIT_MILLIS milliseconds,
- * restart current track. Also restart the track if the current track
- * is the first in a queue.*/
+ * restart current track. Also restart the track if the current track
+ * is the first in a queue.*/
if (simpleExoPlayer.getCurrentPosition() > PLAY_PREV_ACTIVATION_LIMIT_MILLIS ||
playQueue.getIndex() == 0) {
seekToDefault();
@@ -1010,8 +1036,8 @@ public abstract class BasePlayer implements
try {
metadata = (MediaSourceTag) simpleExoPlayer.getCurrentTag();
} catch (IndexOutOfBoundsException | ClassCastException error) {
- if(DEBUG) Log.d(TAG, "Could not update metadata: " + error.getMessage());
- if(DEBUG) error.printStackTrace();
+ if (DEBUG) Log.d(TAG, "Could not update metadata: " + error.getMessage());
+ if (DEBUG) error.printStackTrace();
return;
}
@@ -1075,7 +1101,9 @@ public abstract class BasePlayer implements
currentThumbnail;
}
- /** Checks if the current playback is a livestream AND is playing at or beyond the live edge */
+ /**
+ * Checks if the current playback is a livestream AND is playing at or beyond the live edge
+ */
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean isLiveEdge() {
if (simpleExoPlayer == null || !isLive()) return false;
@@ -1099,8 +1127,8 @@ public abstract class BasePlayer implements
} catch (@NonNull IndexOutOfBoundsException ignored) {
// Why would this even happen =(
// But lets log it anyway. Save is save
- if(DEBUG) Log.d(TAG, "Could not update metadata: " + ignored.getMessage());
- if(DEBUG) ignored.printStackTrace();
+ if (DEBUG) Log.d(TAG, "Could not update metadata: " + ignored.getMessage());
+ if (DEBUG) ignored.printStackTrace();
return false;
}
}
@@ -1113,7 +1141,9 @@ public abstract class BasePlayer implements
@Player.RepeatMode
public int getRepeatMode() {
- return simpleExoPlayer == null ? Player.REPEAT_MODE_OFF : simpleExoPlayer.getRepeatMode();
+ return simpleExoPlayer == null
+ ? Player.REPEAT_MODE_OFF
+ : simpleExoPlayer.getRepeatMode();
}
public void setRepeatMode(@Player.RepeatMode final int repeatMode) {
@@ -1179,4 +1209,8 @@ public abstract class BasePlayer implements
if (DEBUG) Log.d(TAG, "Setting recovery, queue: " + queuePos + ", pos: " + windowPos);
playQueue.setRecovery(queuePos, windowPos);
}
+
+ public boolean gotDestroyed() {
+ return simpleExoPlayer == null;
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
index 8ce18fa56..07a9ac71c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
@@ -217,10 +217,9 @@ public final class MainVideoPlayer extends AppCompatActivity
if (playerImpl == null) return;
playerImpl.setRecovery();
- playerState = new PlayerState(playerImpl.getPlayQueue(), playerImpl.getRepeatMode(),
- playerImpl.getPlaybackSpeed(), playerImpl.getPlaybackPitch(),
- playerImpl.getPlaybackQuality(), playerImpl.getPlaybackSkipSilence(),
- playerImpl.isPlaying());
+ if(!playerImpl.gotDestroyed()) {
+ playerState = createPlayerState();
+ }
StateSaver.tryToSave(isChangingConfigurations(), null, outState, this);
}
@@ -235,6 +234,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (!isBackPressed) {
playerImpl.minimize();
}
+ playerState = createPlayerState();
playerImpl.destroy();
isInMultiWindow = false;
@@ -245,6 +245,13 @@ public final class MainVideoPlayer extends AppCompatActivity
// State Saving
//////////////////////////////////////////////////////////////////////////*/
+ private PlayerState createPlayerState() {
+ return new PlayerState(playerImpl.getPlayQueue(), playerImpl.getRepeatMode(),
+ playerImpl.getPlaybackSpeed(), playerImpl.getPlaybackPitch(),
+ playerImpl.getPlaybackQuality(), playerImpl.getPlaybackSkipSilence(),
+ playerImpl.isPlaying());
+ }
+
@Override
public String generateSuffix() {
return "." + UUID.randomUUID().toString() + ".player";
@@ -1006,12 +1013,14 @@ public final class MainVideoPlayer extends AppCompatActivity
private static final int MOVEMENT_THRESHOLD = 40;
- private final boolean isPlayerGestureEnabled = PlayerHelper.isPlayerGestureEnabled(getApplicationContext());
+ private final boolean isVolumeGestureEnabled = PlayerHelper.isVolumeGestureEnabled(getApplicationContext());
+ private final boolean isBrightnessGestureEnabled = PlayerHelper.isBrightnessGestureEnabled(getApplicationContext());
+
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
@Override
public boolean onScroll(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
- if (!isPlayerGestureEnabled) return false;
+ if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) return false;
//noinspection PointlessBooleanExpression
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
@@ -1027,7 +1036,11 @@ public final class MainVideoPlayer extends AppCompatActivity
isMoving = true;
- if (initialEvent.getX() > playerImpl.getRootView().getWidth() / 2) {
+ boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
+ boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
+ boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
+
+ if (isVolumeGestureEnabled && acceptVolumeArea) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
@@ -1052,7 +1065,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
}
- } else {
+ } else if (isBrightnessGestureEnabled && acceptBrightnessArea) {
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 05afe2859..16dffc3de 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -169,8 +169,12 @@ public class PlayerHelper {
return isResumeAfterAudioFocusGain(context, false);
}
- public static boolean isPlayerGestureEnabled(@NonNull final Context context) {
- return isPlayerGestureEnabled(context, true);
+ public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
+ return isVolumeGestureEnabled(context, true);
+ }
+
+ public static boolean isBrightnessGestureEnabled(@NonNull final Context context) {
+ return isBrightnessGestureEnabled(context, true);
}
public static boolean isUsingOldPlayer(@NonNull final Context context) {
@@ -306,8 +310,12 @@ public class PlayerHelper {
return getPreferences(context).getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), b);
}
- private static boolean isPlayerGestureEnabled(@NonNull final Context context, final boolean b) {
- return getPreferences(context).getBoolean(context.getString(R.string.player_gesture_controls_key), b);
+ private static boolean isVolumeGestureEnabled(@NonNull final Context context, final boolean b) {
+ return getPreferences(context).getBoolean(context.getString(R.string.volume_gesture_control_key), b);
+ }
+
+ private static boolean isBrightnessGestureEnabled(@NonNull final Context context, final boolean b) {
+ return getPreferences(context).getBoolean(context.getString(R.string.brightness_gesture_control_key), b);
}
private static boolean isUsingOldPlayer(@NonNull final Context context, final boolean b) {
diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
index 5c54fa735..82604f7da 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
@@ -17,6 +17,8 @@ import com.nononsenseapps.filepicker.Utils;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.extractor.NewPipe;
+import org.schabi.newpipe.extractor.utils.Localization;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.FilePickerActivityHelper;
@@ -106,6 +108,20 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
startActivityForResult(i, REQUEST_EXPORT_PATH);
return true;
});
+
+ Preference setPreferredLanguage = findPreference(getString(R.string.content_language_key));
+ setPreferredLanguage.setOnPreferenceChangeListener((Preference p, Object newLanguage) -> {
+ Localization oldLocal = org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(getActivity());
+ NewPipe.setLocalization(new Localization(oldLocal.getCountry(), (String) newLanguage));
+ return true;
+ });
+
+ Preference setPreferredCountry = findPreference(getString(R.string.content_country_key));
+ setPreferredCountry.setOnPreferenceChangeListener((Preference p, Object newCountry) -> {
+ Localization oldLocal = org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(getActivity());
+ NewPipe.setLocalization(new Localization((String) newCountry, oldLocal.getLanguage()));
+ return true;
+ });
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
index fb9579802..e04c1e8d0 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
@@ -32,6 +32,7 @@ import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
+import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
@@ -67,42 +68,37 @@ public final class ExtractorHelper {
public static Single> suggestionsFor(final int serviceId,
- final String query,
- final String contentCountry) {
+ final String query) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
NewPipe.getService(serviceId)
.getSuggestionExtractor()
- .suggestionList(query, contentCountry));
+ .suggestionList(query));
}
public static Single