Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 **/
Expand Down
34 changes: 5 additions & 29 deletions app/src/main/java/org/schabi/newpipe/RouterActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,13 @@
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;
Expand Down Expand Up @@ -279,28 +272,11 @@ private static void handleError(final Context context, final ErrorInfo errorInfo
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);
}
Expand Down
62 changes: 51 additions & 11 deletions app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,28 @@ 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.player.mediasource.FailedMediaSource
import org.schabi.newpipe.player.resolver.PlaybackResolver
import org.schabi.newpipe.util.ServiceHelper

@Parcelize
Expand Down Expand Up @@ -86,30 +99,57 @@ class ErrorInfo(
if (info == null) SERVICE_NONE else ServiceHelper.getNameOfServiceById(info.serviceId)

@StringRes
private fun getMessageStringId(
fun getMessageStringId(
throwable: Throwable?,
action: UserAction
action: UserAction?
): Int {
return when {
throwable is AccountTerminatedException -> R.string.account_terminated
throwable is ContentNotAvailableException -> R.string.content_not_available
throwable != null && throwable.isNetworkRelated -> R.string.network_error
throwable is ContentNotSupportedException -> R.string.content_not_supported
throwable is ExtractionException -> R.string.parsing_error
// player exceptions
// some may be IOException, so do these checks before isNetworkRelated!
throwable is ExoPlaybackException -> {
when (throwable.type) {
ExoPlaybackException.TYPE_SOURCE -> R.string.player_stream_failure
ExoPlaybackException.TYPE_UNEXPECTED -> R.string.player_recoverable_failure
val cause = throwable.cause
when {
cause is HttpDataSource.InvalidResponseCodeException && cause.responseCode == 403 -> R.string.player_error_403
cause is Loader.UnexpectedLoaderException && cause.cause is ExtractionException -> getMessageStringId(throwable, action)
throwable.type == ExoPlaybackException.TYPE_SOURCE -> R.string.player_stream_failure
throwable.type == ExoPlaybackException.TYPE_UNEXPECTED -> R.string.player_recoverable_failure
else -> R.string.player_unrecoverable_failure
}
}
throwable is FailedMediaSource.FailedMediaSourceException -> getMessageStringId(throwable.cause, action)
throwable is PlaybackResolver.ResolverException -> R.string.player_stream_failure

// 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

// other extractor exceptions
throwable is ContentNotSupportedException -> R.string.content_not_supported
// ReCaptchas should have already been handled elsewhere,
// but return an error message here just in case
throwable is ReCaptchaException -> R.string.recaptcha_request_toast
// test this at the end as many exceptions could be a subclass of IOException
throwable != null && throwable.isNetworkRelated -> R.string.network_error
// an extraction exception unrelated to the network
// is likely an issue with parsing the website
throwable is ExtractionException -> R.string.parsing_error

// user actions (in case the exception is null or 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
}
}
}
Expand Down
31 changes: 1 addition & 30 deletions app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/org/schabi/newpipe/error/UserAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.NewPipeDatabase
import org.schabi.newpipe.R
import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.extractor.InfoItem.InfoType
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler
Expand Down Expand Up @@ -84,7 +85,7 @@ class MediaBrowserPlaybackPreparer(
},
{ throwable ->
Log.e(TAG, "Failed to start playback of media ID [$mediaId]", throwable)
onPrepareError()
onPrepareError(throwable)
}
)
}
Expand Down Expand Up @@ -115,9 +116,9 @@ class MediaBrowserPlaybackPreparer(
)
}

private fun onPrepareError() {
private fun onPrepareError(throwable: Throwable) {
setMediaSessionError.accept(
ContextCompat.getString(context, R.string.error_snackbar_message),
ContextCompat.getString(context, ErrorInfo.getMessageStringId(throwable, null)),
PlaybackStateCompat.ERROR_CODE_APP_ERROR
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -158,19 +157,13 @@ public static boolean playOnPopup(final Context context,
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;
}
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -877,4 +877,7 @@
<string name="trending_movies">Trending movies and shows</string>
<string name="trending_music">Trending music</string>
<string name="entry_deleted">Entry deleted</string>
<string name="player_error_403">HTTP error 403 occurred while playing, likely caused by an IP ban or streaming URL deobfuscation issues</string>
<string name="youtube_sign_in_confirm_not_bot_error">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).</string>
<string name="unsupported_content_in_country">This content is not available for the currently selected content country.\n\nChange your selection from \"Settings > Content > Default content country\".</string>
</resources>
Loading