Merge remote-tracking branch 'newpipe/dev' into rebase

This commit is contained in:
Alexander-- 2020-04-11 08:30:40 +06:59
commit ac5571a363
41 changed files with 1701 additions and 1505 deletions

View file

@ -0,0 +1,82 @@
package org.schabi.newpipe.util
import java.io.IOException
import java.io.InterruptedIOException
class ExceptionUtils {
companion object {
/**
* @return if throwable is related to Interrupted exceptions, or one of its causes is.
*/
@JvmStatic
fun isInterruptedCaused(throwable: Throwable): Boolean {
return hasExactCause(throwable,
InterruptedIOException::class.java,
InterruptedException::class.java)
}
/**
* @return if throwable is related to network issues, or one of its causes is.
*/
@JvmStatic
fun isNetworkRelated(throwable: Throwable): Boolean {
return hasAssignableCause(throwable,
IOException::class.java)
}
/**
* Calls [hasCause] with the `checkSubtypes` parameter set to false.
*/
@JvmStatic
fun hasExactCause(throwable: Throwable, vararg causesToCheck: Class<*>): Boolean {
return hasCause(throwable, false, *causesToCheck)
}
/**
* Calls [hasCause] with the `checkSubtypes` parameter set to true.
*/
@JvmStatic
fun hasAssignableCause(throwable: Throwable?, vararg causesToCheck: Class<*>): Boolean {
return hasCause(throwable, true, *causesToCheck)
}
/**
* Check if throwable has some cause from the causes to check, or is itself in it.
*
* If `checkIfAssignable` is true, not only the exact type will be considered equals, but also its subtypes.
*
* @param throwable throwable that will be checked.
* @param checkSubtypes if subtypes are also checked.
* @param causesToCheck an array of causes to check.
*
* @see Class.isAssignableFrom
*/
@JvmStatic
tailrec fun hasCause(throwable: Throwable?, checkSubtypes: Boolean, vararg causesToCheck: Class<*>): Boolean {
if (throwable == null) {
return false
}
// Check if throwable is a subtype of any of the causes to check
causesToCheck.forEach { causeClass ->
if (checkSubtypes) {
if (causeClass.isAssignableFrom(throwable.javaClass)) {
return true
}
} else {
if (causeClass == throwable.javaClass) {
return true
}
}
}
val currentCause: Throwable? = throwable.cause
// Check if cause is not pointing to the same instance, to avoid infinite loops.
if (throwable !== currentCause) {
return hasCause(currentCause, checkSubtypes, *causesToCheck)
}
return false
}
}
}

View file

@ -37,6 +37,7 @@ import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.feed.FeedExtractor;
@ -51,8 +52,6 @@ import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Collections;
import java.util.List;
@ -289,10 +288,12 @@ public final class ExtractorHelper {
Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else if (exception instanceof IOException) {
} else if (ExceptionUtils.isNetworkRelated(exception)) {
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
} else if (exception instanceof ContentNotAvailableException) {
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
} else if (exception instanceof ContentNotSupportedException) {
Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show();
} else {
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException
? R.string.youtube_signature_decryption_error
@ -306,85 +307,4 @@ public final class ExtractorHelper {
}
});
}
/**
* Check if throwable have the cause that can be assignable from the causes to check.
*
* @see Class#isAssignableFrom(Class)
* @param throwable the throwable to be checked
* @param causesToCheck the causes to check
* @return whether the exception is an instance of a subclass of one of the causes
* or is caused by an instance of a subclass of one of the causes
*/
public static boolean hasAssignableCauseThrowable(final Throwable throwable,
final Class<?>... causesToCheck) {
// Check if getCause is not the same as cause (the getCause is already the root),
// as it will cause a infinite loop if it is
Throwable cause;
Throwable getCause = throwable;
// Check if throwable is a subclass of any of the filtered classes
final Class throwableClass = throwable.getClass();
for (Class<?> causesEl : causesToCheck) {
if (causesEl.isAssignableFrom(throwableClass)) {
return true;
}
}
// Iteratively checks if the root cause of the throwable is a subclass of the filtered class
while ((cause = throwable.getCause()) != null && getCause != cause) {
getCause = cause;
final Class causeClass = cause.getClass();
for (Class<?> causesEl : causesToCheck) {
if (causesEl.isAssignableFrom(causeClass)) {
return true;
}
}
}
return false;
}
/**
* Check if throwable have the exact cause from one of the causes to check.
*
* @param throwable the throwable to be checked
* @param causesToCheck the causes to check
* @return whether the exception is an instance of one of the causes
* or is caused by an instance of one of the causes
*/
public static boolean hasExactCauseThrowable(final Throwable throwable,
final Class<?>... causesToCheck) {
// Check if getCause is not the same as cause (the getCause is already the root),
// as it will cause a infinite loop if it is
Throwable cause;
Throwable getCause = throwable;
for (Class<?> causesEl : causesToCheck) {
if (throwable.getClass().equals(causesEl)) {
return true;
}
}
while ((cause = throwable.getCause()) != null && getCause != cause) {
getCause = cause;
for (Class<?> causesEl : causesToCheck) {
if (cause.getClass().equals(causesEl)) {
return true;
}
}
}
return false;
}
/**
* Check if throwable have Interrupted* exception as one of its causes.
*
* @param throwable the throwable to be checkes
* @return whether the throwable is caused by an interruption
*/
public static boolean isInterruptedCaused(final Throwable throwable) {
return ExtractorHelper.hasExactCauseThrowable(throwable,
InterruptedIOException.class,
InterruptedException.class);
}
}

View file

@ -16,6 +16,7 @@ import androidx.annotation.StringRes;
import org.ocpsoft.prettytime.PrettyTime;
import org.ocpsoft.prettytime.units.Decade;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.localization.ContentCountry;
import java.math.BigDecimal;
@ -151,8 +152,30 @@ public final class Localization {
}
public static String localizeStreamCount(final Context context, final long streamCount) {
return getQuantity(context, R.plurals.videos, R.string.no_videos, streamCount,
localizeNumber(context, streamCount));
switch ((int) streamCount) {
case (int) ListExtractor.ITEM_COUNT_UNKNOWN:
return "";
case (int) ListExtractor.ITEM_COUNT_INFINITE:
return context.getResources().getString(R.string.infinite_videos);
case (int) ListExtractor.ITEM_COUNT_MORE_THAN_100:
return context.getResources().getString(R.string.more_than_100_videos);
default:
return getQuantity(context, R.plurals.videos, R.string.no_videos, streamCount,
localizeNumber(context, streamCount));
}
}
public static String localizeStreamCountMini(final Context context, final long streamCount) {
switch ((int) streamCount) {
case (int) ListExtractor.ITEM_COUNT_UNKNOWN:
return "";
case (int) ListExtractor.ITEM_COUNT_INFINITE:
return context.getResources().getString(R.string.infinite_videos_mini);
case (int) ListExtractor.ITEM_COUNT_MORE_THAN_100:
return context.getResources().getString(R.string.more_than_100_videos_mini);
default:
return String.valueOf(streamCount);
}
}
public static String localizeWatchingCount(final Context context, final long watchingCount) {

View file

@ -120,9 +120,6 @@ public final class NavigationHelper {
final boolean isMuted) {
return getPlayerIntent(context, targetClazz, playQueue, playbackQuality, resumePlayback)
.putExtra(BasePlayer.REPEAT_MODE, repeatMode)
.putExtra(BasePlayer.PLAYBACK_SPEED, playbackSpeed)
.putExtra(BasePlayer.PLAYBACK_PITCH, playbackPitch)
.putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence)
.putExtra(BasePlayer.START_PAUSED, startPaused)
.putExtra(BasePlayer.IS_MUTED, isMuted);
}

View file

@ -48,10 +48,12 @@ public final class ServiceHelper {
case "all":
return c.getString(R.string.all);
case "videos":
case "music_videos":
return c.getString(R.string.videos_string);
case "channels":
return c.getString(R.string.channels);
case "playlists":
case "music_playlists":
return c.getString(R.string.playlists);
case "tracks":
return c.getString(R.string.tracks);
@ -61,6 +63,12 @@ public final class ServiceHelper {
return c.getString(R.string.conferences);
case "events":
return c.getString(R.string.events);
case "music_songs":
return c.getString(R.string.songs);
case "music_albums":
return c.getString(R.string.albums);
case "music_artists":
return c.getString(R.string.artists);
default:
return filter;
}

View file

@ -194,7 +194,7 @@ public final class ThemeHelper {
}
/**
* Get a resource id from a resource styled according to the the context's theme.
* Get a resource id from a resource styled according to the context's theme.
*
* @param context Android app context
* @param attr attribute reference of the resource
@ -208,10 +208,10 @@ public final class ThemeHelper {
}
/**
* Get a color from an attr styled according to the the context's theme.
* Get a color from an attr styled according to the context's theme.
*
* @param context Android app context
* @param attrColor attribute reference of the resource
* @param context Android app context
* @param attrColor attribute reference of the resource
* @return the color
*/
public static int resolveColorFromAttr(final Context context, @AttrRes final int attrColor) {