diff --git a/app/build.gradle b/app/build.gradle
index dbffc2bf6..7f4166a57 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -214,7 +214,7 @@ dependencies {
// the corresponding commit hash, since JitPack sometimes deletes artifacts.
// If there’s already a git hash, just add more of it to the end (or remove a letter)
// to cause jitpack to regenerate the artifact.
- implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.8'
+ implementation 'com.github.Stypox:NewPipeExtractor:b8bd4cda8cca00a14940933e3d3635d5aafec222'
implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
/** Checkstyle **/
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index 3294cae0b..dac2d29a1 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -58,20 +58,13 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.StreamingService.LinkType;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
-import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
-import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException;
-import org.schabi.newpipe.extractor.exceptions.PaidContentException;
-import org.schabi.newpipe.extractor.exceptions.PrivateContentException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
-import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException;
-import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
-import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.helper.PlayerHelper;
@@ -279,28 +272,11 @@ public class RouterActivity extends AppCompatActivity {
final Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
- } else if (errorInfo.getThrowable() != null
- && ExceptionUtils.isNetworkRelated(errorInfo.getThrowable())) {
- Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof AgeRestrictedContentException) {
- Toast.makeText(context, R.string.restricted_video_no_stream,
- Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof GeographicRestrictionException) {
- Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof PaidContentException) {
- Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof PrivateContentException) {
- Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof SoundCloudGoPlusContentException) {
- Toast.makeText(context, R.string.soundcloud_go_plus_content,
- Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof YoutubeMusicPremiumContentException) {
- Toast.makeText(context, R.string.youtube_music_premium_content,
- Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof ContentNotAvailableException) {
- Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) {
- Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show();
+ } else if (errorInfo.getThrowable() instanceof ContentNotAvailableException
+ || errorInfo.getThrowable() instanceof ContentNotSupportedException) {
+ // this exception does not usually indicate a problem that should be reported,
+ // so just show a toast instead of the notification
+ Toast.makeText(context, errorInfo.getMessageStringId(), Toast.LENGTH_LONG).show();
} else {
ErrorUtil.createNotification(context, errorInfo);
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
index 6d8c1bd63..014be540f 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
@@ -3,14 +3,25 @@ package org.schabi.newpipe.error
import android.os.Parcelable
import androidx.annotation.StringRes
import com.google.android.exoplayer2.ExoPlaybackException
+import com.google.android.exoplayer2.upstream.HttpDataSource
+import com.google.android.exoplayer2.upstream.Loader
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.Info
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException
+import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException
import org.schabi.newpipe.extractor.exceptions.ExtractionException
+import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException
+import org.schabi.newpipe.extractor.exceptions.PaidContentException
+import org.schabi.newpipe.extractor.exceptions.PrivateContentException
+import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
+import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException
+import org.schabi.newpipe.extractor.exceptions.UnsupportedContentInCountryException
+import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException
+import org.schabi.newpipe.extractor.exceptions.YoutubeSignInConfirmNotBotException
import org.schabi.newpipe.ktx.isNetworkRelated
import org.schabi.newpipe.util.ServiceHelper
@@ -91,11 +102,28 @@ class ErrorInfo(
action: UserAction
): Int {
return when {
+ // content not available exceptions
throwable is AccountTerminatedException -> R.string.account_terminated
+ throwable is AgeRestrictedContentException -> R.string.restricted_video_no_stream
+ throwable is GeographicRestrictionException -> R.string.georestricted_content
+ throwable is PaidContentException -> R.string.paid_content
+ throwable is PrivateContentException -> R.string.private_content
+ throwable is SoundCloudGoPlusContentException -> R.string.soundcloud_go_plus_content
+ throwable is UnsupportedContentInCountryException -> R.string.unsupported_content_in_country
+ throwable is YoutubeMusicPremiumContentException -> R.string.youtube_music_premium_content
+ throwable is YoutubeSignInConfirmNotBotException -> R.string.youtube_sign_in_confirm_not_bot_error
throwable is ContentNotAvailableException -> R.string.content_not_available
- throwable != null && throwable.isNetworkRelated -> R.string.network_error
+
+ // ReCaptchas should have already been handled elsewhere,
+ // but return an error message here just in case
+ throwable is ReCaptchaException -> R.string.recaptcha_request_toast
+
+ // other extractor exceptions
throwable is ContentNotSupportedException -> R.string.content_not_supported
+ throwable != null && throwable.isNetworkRelated -> R.string.network_error
throwable is ExtractionException -> R.string.parsing_error
+
+ // ExoPlayer exceptions
throwable is ExoPlaybackException -> {
when (throwable.type) {
ExoPlaybackException.TYPE_SOURCE -> R.string.player_stream_failure
@@ -103,13 +131,15 @@ class ErrorInfo(
else -> R.string.player_unrecoverable_failure
}
}
+
+ // user actions (in case the exception is unrecognizable)
action == UserAction.UI_ERROR -> R.string.app_ui_crash
action == UserAction.REQUESTED_COMMENTS -> R.string.error_unable_to_load_comments
action == UserAction.SUBSCRIPTION_CHANGE -> R.string.subscription_change_failed
action == UserAction.SUBSCRIPTION_UPDATE -> R.string.subscription_update_failed
action == UserAction.LOAD_IMAGE -> R.string.could_not_load_thumbnails
action == UserAction.DOWNLOAD_OPEN_DIALOG -> R.string.could_not_setup_download_menu
- else -> R.string.general_error
+ else -> R.string.error_snackbar_message
}
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
index 14ec41148..66d4d9fae 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
@@ -15,19 +15,12 @@ import io.reactivex.rxjava3.disposables.Disposable
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException
-import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException
-import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException
-import org.schabi.newpipe.extractor.exceptions.PaidContentException
-import org.schabi.newpipe.extractor.exceptions.PrivateContentException
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
-import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException
-import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException
import org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.ktx.isInterruptedCaused
-import org.schabi.newpipe.ktx.isNetworkRelated
import org.schabi.newpipe.util.ServiceHelper
import org.schabi.newpipe.util.external_communication.ShareUtils
import java.util.concurrent.TimeUnit
@@ -127,7 +120,7 @@ class ErrorPanelHelper(
ErrorUtil.openActivity(context, errorInfo)
}
- errorTextView.setText(getExceptionDescription(errorInfo.throwable))
+ errorTextView.setText(errorInfo.messageStringId)
if (errorInfo.throwable !is ContentNotAvailableException &&
errorInfo.throwable !is ContentNotSupportedException
@@ -192,27 +185,5 @@ class ErrorPanelHelper(
companion object {
val TAG: String = ErrorPanelHelper::class.simpleName!!
val DEBUG: Boolean = MainActivity.DEBUG
-
- @StringRes
- 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
- }
- }
- }
- }
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
index e74711b88..958188b6a 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
@@ -156,7 +156,7 @@ class ErrorUtil {
// fallback to showing a notification if no root view is available
createNotification(context, errorInfo)
} else {
- Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG)
+ Snackbar.make(rootView, errorInfo.messageStringId, Snackbar.LENGTH_LONG)
.setActionTextColor(Color.YELLOW)
.setAction(context.getString(R.string.error_snackbar_action).uppercase()) {
openActivity(context, errorInfo)
diff --git a/app/src/main/java/org/schabi/newpipe/error/UserAction.java b/app/src/main/java/org/schabi/newpipe/error/UserAction.java
index afb880a29..997bff996 100644
--- a/app/src/main/java/org/schabi/newpipe/error/UserAction.java
+++ b/app/src/main/java/org/schabi/newpipe/error/UserAction.java
@@ -33,7 +33,8 @@ public enum UserAction {
SHARE_TO_NEWPIPE("share to newpipe"),
CHECK_FOR_NEW_APP_VERSION("check for new app version"),
OPEN_INFO_ITEM_DIALOG("open info item dialog"),
- GETTING_MAIN_SCREEN_TAB("getting main screen tab");
+ GETTING_MAIN_SCREEN_TAB("getting main screen tab"),
+ PLAY_ON_POPUP("play on popup");
private final String message;
diff --git a/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java b/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java
index 066515d6b..a2743141b 100644
--- a/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java
+++ b/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java
@@ -1,14 +1,13 @@
package org.schabi.newpipe.util.text;
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.error.ErrorInfo;
+import org.schabi.newpipe.error.ErrorUtil;
+import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@@ -158,19 +157,13 @@ public final class InternalUrlsHandler {
disposables.add(single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> {
- final PlayQueue playQueue =
- new SinglePlayQueue(info, seconds * 1000L);
+ final PlayQueue playQueue = 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, null)
- .show();
+ final var errorInfo = new ErrorInfo(throwable, UserAction.PLAY_ON_POPUP, url);
+ // This will only show a snackbar if the passed context has a root view:
+ // otherwise it will resort to showing a notification, so we are safe here.
+ ErrorUtil.showSnackbar(context, errorInfo);
}));
return true;
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 922b7bd3f..21593674d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -877,4 +877,6 @@
Trending movies and shows
Trending music
Entry deleted
+ YouTube refused to provide data, asking for a login.\n\nYour IP might have been temporarily banned by YouTube, you can wait some time or switch to a different IP (for example by turning on/off a VPN, or by switching from WiFi to mobile data).
+ This content is not available for the currently selected content country.\n\nChange your selection from \"Settings > Content > Default content country\".