1
0
Fork 0
mirror of https://github.com/TeamNewPipe/NewPipe.git synced 2025-10-03 09:49:21 +02:00

Merge branch 'refactor' into Playlist-Compose

# Conflicts:
#	app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
#	app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java
This commit is contained in:
Isira Seneviratne 2025-09-07 09:50:21 +05:30
commit 0931d44cc1
100 changed files with 659 additions and 572 deletions

View file

@ -12,6 +12,7 @@ import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -23,8 +24,23 @@ import static org.junit.Assert.assertTrue;
@LargeTest @LargeTest
public class ErrorInfoTest { public class ErrorInfoTest {
/**
* @param errorInfo the error info to access
* @return the private field errorInfo.message.stringRes using reflection
*/
private int getMessageFromErrorInfo(final ErrorInfo errorInfo)
throws NoSuchFieldException, IllegalAccessException {
final var message = ErrorInfo.class.getDeclaredField("message");
message.setAccessible(true);
final var messageValue = (ErrorInfo.Companion.ErrorMessage) message.get(errorInfo);
final var stringRes = ErrorInfo.Companion.ErrorMessage.class.getDeclaredField("stringRes");
stringRes.setAccessible(true);
return (int) Objects.requireNonNull(stringRes.get(messageValue));
}
@Test @Test
public void errorInfoTestParcelable() { public void errorInfoTestParcelable() throws NoSuchFieldException, IllegalAccessException {
final ErrorInfo info = new ErrorInfo(new ParsingException("Hello"), final ErrorInfo info = new ErrorInfo(new ParsingException("Hello"),
UserAction.USER_REPORT, "request", ServiceList.YouTube.getServiceId()); UserAction.USER_REPORT, "request", ServiceList.YouTube.getServiceId());
// Obtain a Parcel object and write the parcelable object to it: // Obtain a Parcel object and write the parcelable object to it:
@ -39,7 +55,7 @@ public class ErrorInfoTest {
assertEquals(ServiceList.YouTube.getServiceInfo().getName(), assertEquals(ServiceList.YouTube.getServiceInfo().getName(),
infoFromParcel.getServiceName()); infoFromParcel.getServiceName());
assertEquals("request", infoFromParcel.getRequest()); assertEquals("request", infoFromParcel.getRequest());
assertEquals(R.string.parsing_error, infoFromParcel.getMessageStringId()); assertEquals(R.string.parsing_error, getMessageFromErrorInfo(infoFromParcel));
parcel.recycle(); parcel.recycle();
} }

View file

@ -435,6 +435,7 @@
</activity> </activity>
<service <service
android:name=".RouterActivity$FetcherService" android:name=".RouterActivity$FetcherService"
android:foregroundServiceType="dataSync"
android:exported="false" /> android:exported="false" />
<!-- opting out of sending metrics to Google in Android System WebView --> <!-- opting out of sending metrics to Google in Android System WebView -->

View file

@ -58,20 +58,10 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.StreamingService.LinkType; import org.schabi.newpipe.extractor.StreamingService.LinkType;
import org.schabi.newpipe.extractor.channel.ChannelInfo; 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.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.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.player.PlayerType; import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
@ -260,7 +250,8 @@ public class RouterActivity extends AppCompatActivity {
showUnsupportedUrlDialog(url); showUnsupportedUrlDialog(url);
} }
}, throwable -> handleError(this, new ErrorInfo(throwable, }, throwable -> handleError(this, new ErrorInfo(throwable,
UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url)))); UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url,
null, url))));
} }
/** /**
@ -269,40 +260,19 @@ public class RouterActivity extends AppCompatActivity {
* @param errorInfo the error information * @param errorInfo the error information
*/ */
private static void handleError(final Context context, final ErrorInfo errorInfo) { private static void handleError(final Context context, final ErrorInfo errorInfo) {
if (errorInfo.getThrowable() != null) { if (errorInfo.getRecaptchaUrl() != null) {
errorInfo.getThrowable().printStackTrace();
}
if (errorInfo.getThrowable() instanceof ReCaptchaException) {
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 // Starting ReCaptcha Challenge Activity
final Intent intent = new Intent(context, ReCaptchaActivity.class); final Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, errorInfo.getRecaptchaUrl());
context.startActivity(intent); context.startActivity(intent);
} else if (errorInfo.getThrowable() != null } else if (errorInfo.isReportable()) {
&& 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 {
ErrorUtil.createNotification(context, errorInfo); ErrorUtil.createNotification(context, errorInfo);
} else {
// 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.getMessage(context), Toast.LENGTH_LONG).show();
} }
if (context instanceof RouterActivity) { if (context instanceof RouterActivity) {
@ -665,7 +635,8 @@ public class RouterActivity extends AppCompatActivity {
startActivity(intent); startActivity(intent);
finish(); finish();
}, throwable -> handleError(this, new ErrorInfo(throwable, }, throwable -> handleError(this, new ErrorInfo(throwable,
UserAction.SHARE_TO_NEWPIPE, "Starting info activity: " + currentUrl))) UserAction.SHARE_TO_NEWPIPE, "Starting info activity: " + currentUrl,
null, currentUrl)))
); );
return; return;
} }
@ -852,10 +823,10 @@ public class RouterActivity extends AppCompatActivity {
}) })
)), )),
throwable -> runOnVisible(ctx -> handleError(ctx, new ErrorInfo( throwable -> runOnVisible(ctx -> handleError(ctx, new ErrorInfo(
throwable, throwable, UserAction.REQUESTED_STREAM,
UserAction.REQUESTED_STREAM,
"Tried to add " + currentUrl + " to a playlist", "Tried to add " + currentUrl + " to a playlist",
((RouterActivity) ctx).currentService.getServiceId()) ((RouterActivity) ctx).currentService.getServiceId(),
currentUrl)
)) ))
) )
); );
@ -995,7 +966,7 @@ public class RouterActivity extends AppCompatActivity {
} }
}, throwable -> handleError(this, new ErrorInfo(throwable, finalUserAction, }, throwable -> handleError(this, new ErrorInfo(throwable, finalUserAction,
choice.url + " opened with " + choice.playerChoice, choice.url + " opened with " + choice.playerChoice,
choice.serviceId))); choice.serviceId, choice.url)));
} }
} }

View file

@ -389,8 +389,7 @@ public class DownloadDialog extends DialogFragment
} }
}, throwable -> ErrorUtil.showSnackbar(context, }, throwable -> ErrorUtil.showSnackbar(context,
new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG, new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG,
"Downloading video stream size", "Downloading video stream size", currentInfo))));
currentInfo.getServiceId()))));
disposables.add(StreamInfoWrapper.fetchMoreInfoForWrapper(getWrappedAudioStreams()) disposables.add(StreamInfoWrapper.fetchMoreInfoForWrapper(getWrappedAudioStreams())
.subscribe(result -> { .subscribe(result -> {
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId() if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()
@ -399,8 +398,7 @@ public class DownloadDialog extends DialogFragment
} }
}, throwable -> ErrorUtil.showSnackbar(context, }, throwable -> ErrorUtil.showSnackbar(context,
new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG, new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG,
"Downloading audio stream size", "Downloading audio stream size", currentInfo))));
currentInfo.getServiceId()))));
disposables.add(StreamInfoWrapper.fetchMoreInfoForWrapper(wrappedSubtitleStreams) disposables.add(StreamInfoWrapper.fetchMoreInfoForWrapper(wrappedSubtitleStreams)
.subscribe(result -> { .subscribe(result -> {
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId() if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()
@ -409,8 +407,7 @@ public class DownloadDialog extends DialogFragment
} }
}, throwable -> ErrorUtil.showSnackbar(context, }, throwable -> ErrorUtil.showSnackbar(context,
new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG, new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG,
"Downloading subtitle stream size", "Downloading subtitle stream size", currentInfo))));
currentInfo.getServiceId()))));
} }
private void setupAudioTrackSpinner() { private void setupAudioTrackSpinner() {

View file

@ -36,8 +36,8 @@ public class AcraReportSender implements ReportSender {
ErrorUtil.openActivity(context, new ErrorInfo( ErrorUtil.openActivity(context, new ErrorInfo(
new String[]{report.getString(ReportField.STACK_TRACE)}, new String[]{report.getString(ReportField.STACK_TRACE)},
UserAction.UI_ERROR, UserAction.UI_ERROR,
ErrorInfo.SERVICE_NONE,
"ACRA report", "ACRA report",
null,
R.string.app_ui_crash)); R.string.app_ui_crash));
} }
} }

View file

@ -115,7 +115,7 @@ public class ErrorActivity extends AppCompatActivity {
// normal bugreport // normal bugreport
buildInfo(errorInfo); buildInfo(errorInfo);
activityErrorBinding.errorMessageView.setText(errorInfo.getMessageStringId()); activityErrorBinding.errorMessageView.setText(errorInfo.getMessage(this));
activityErrorBinding.errorView.setText(formErrorText(errorInfo.getStackTraces())); activityErrorBinding.errorView.setText(formErrorText(errorInfo.getStackTraces()));
// print stack trace once again for debugging: // print stack trace once again for debugging:

View file

@ -1,115 +1,304 @@
package org.schabi.newpipe.error package org.schabi.newpipe.error
import android.content.Context
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import com.google.android.exoplayer2.ExoPlaybackException import com.google.android.exoplayer2.ExoPlaybackException
import kotlinx.parcelize.IgnoredOnParcel import com.google.android.exoplayer2.upstream.HttpDataSource
import com.google.android.exoplayer2.upstream.Loader
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.Info import org.schabi.newpipe.extractor.Info
import org.schabi.newpipe.extractor.ServiceList
import org.schabi.newpipe.extractor.ServiceList.YouTube
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException 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.ContentNotAvailableException
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException
import org.schabi.newpipe.extractor.exceptions.ExtractionException 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.SignInConfirmNotBotException
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.ktx.isNetworkRelated import org.schabi.newpipe.ktx.isNetworkRelated
import org.schabi.newpipe.util.ServiceHelper import org.schabi.newpipe.player.mediasource.FailedMediaSource
import org.schabi.newpipe.player.resolver.PlaybackResolver
import java.net.UnknownHostException
/**
* An error has occurred in the app. This class contains plain old parcelable data that can be used
* to report the error and to show it to the user along with correct action buttons.
*/
@Parcelize @Parcelize
class ErrorInfo( class ErrorInfo private constructor(
val stackTraces: Array<String>, val stackTraces: Array<String>,
val userAction: UserAction, val userAction: UserAction,
val serviceName: String,
val request: String, val request: String,
val messageStringId: Int val serviceId: Int?,
private val message: ErrorMessage,
/**
* If `true`, a report button will be shown for this error. Otherwise the error is not something
* that can really be reported (e.g. a network issue, or content not being available at all).
*/
val isReportable: Boolean,
/**
* If `true`, the process causing this error can be retried, otherwise not.
*/
val isRetryable: Boolean,
/**
* If present, indicates that the exception was a ReCaptchaException, and this is the URL
* provided by the service that can be used to solve the ReCaptcha challenge.
*/
val recaptchaUrl: String?,
/**
* If present, this resource can alternatively be opened in browser (useful if NewPipe is
* badly broken).
*/
val openInBrowserUrl: String?,
) : Parcelable { ) : Parcelable {
// no need to store throwable, all data for report is in other variables @JvmOverloads
// also, the throwable might not be serializable, see TeamNewPipe/NewPipe#7302 constructor(
@IgnoredOnParcel
var throwable: Throwable? = null
private constructor(
throwable: Throwable, throwable: Throwable,
userAction: UserAction, userAction: UserAction,
serviceName: String, request: String,
request: String serviceId: Int? = null,
openInBrowserUrl: String? = null,
) : this( ) : this(
throwableToStringList(throwable), throwableToStringList(throwable),
userAction, userAction,
serviceName,
request, request,
getMessageStringId(throwable, userAction) serviceId,
) { getMessage(throwable, userAction, serviceId),
this.throwable = throwable isReportable(throwable),
} isRetryable(throwable),
(throwable as? ReCaptchaException)?.url,
openInBrowserUrl,
)
private constructor( @JvmOverloads
throwable: List<Throwable>, constructor(
throwables: List<Throwable>,
userAction: UserAction, userAction: UserAction,
serviceName: String, request: String,
request: String serviceId: Int? = null,
openInBrowserUrl: String? = null,
) : this( ) : this(
throwableListToStringList(throwable), throwableListToStringList(throwables),
userAction, userAction,
serviceName,
request, request,
getMessageStringId(throwable.firstOrNull(), userAction) serviceId,
) { getMessage(throwables.firstOrNull(), userAction, serviceId),
this.throwable = throwable.firstOrNull() throwables.any(::isReportable),
throwables.isEmpty() || throwables.any(::isRetryable),
throwables.firstNotNullOfOrNull { it as? ReCaptchaException }?.url,
openInBrowserUrl,
)
// constructor to manually build ErrorInfo when no throwable is available
constructor(
stackTraces: Array<String>,
userAction: UserAction,
request: String,
serviceId: Int?,
@StringRes message: Int
) :
this(
stackTraces, userAction, request, serviceId, ErrorMessage(message),
true, false, null, null
)
// constructor with only one throwable to extract service id and openInBrowserUrl from an Info
constructor(
throwable: Throwable,
userAction: UserAction,
request: String,
info: Info?,
) :
this(throwable, userAction, request, info?.serviceId, info?.url)
// constructor with multiple throwables to extract service id and openInBrowserUrl from an Info
constructor(
throwables: List<Throwable>,
userAction: UserAction,
request: String,
info: Info?,
) :
this(throwables, userAction, request, info?.serviceId, info?.url)
fun getServiceName(): String {
return getServiceName(serviceId)
} }
// constructors with single throwable fun getMessage(context: Context): String {
constructor(throwable: Throwable, userAction: UserAction, request: String) : return message.getString(context)
this(throwable, userAction, SERVICE_NONE, request) }
constructor(throwable: Throwable, userAction: UserAction, request: String, serviceId: Int) :
this(throwable, userAction, ServiceHelper.getNameOfServiceById(serviceId), request)
constructor(throwable: Throwable, userAction: UserAction, request: String, info: Info?) :
this(throwable, userAction, getInfoServiceName(info), request)
// constructors with list of throwables
constructor(throwable: List<Throwable>, userAction: UserAction, request: String) :
this(throwable, userAction, SERVICE_NONE, request)
constructor(throwable: List<Throwable>, userAction: UserAction, request: String, serviceId: Int) :
this(throwable, userAction, ServiceHelper.getNameOfServiceById(serviceId), request)
constructor(throwable: List<Throwable>, userAction: UserAction, request: String, info: Info?) :
this(throwable, userAction, getInfoServiceName(info), request)
companion object { companion object {
const val SERVICE_NONE = "none" @Parcelize
class ErrorMessage(
@StringRes
private val stringRes: Int,
private vararg val formatArgs: String,
) : Parcelable {
fun getString(context: Context): String {
return if (formatArgs.isEmpty()) {
// use ContextCompat.getString() just in case context is not AppCompatActivity
ContextCompat.getString(context, stringRes)
} else {
// ContextCompat.getString() with formatArgs does not exist, so we just
// replicate its source code but with formatArgs
ContextCompat.getContextForLanguage(context).getString(stringRes, *formatArgs)
}
}
}
const val SERVICE_NONE = "<unknown_service>"
private fun getServiceName(serviceId: Int?) =
// not using getNameOfServiceById since we want to accept a nullable serviceId and we
// want to default to SERVICE_NONE
ServiceList.all()?.firstOrNull { it.serviceId == serviceId }?.serviceInfo?.name
?: SERVICE_NONE
fun throwableToStringList(throwable: Throwable) = arrayOf(throwable.stackTraceToString()) fun throwableToStringList(throwable: Throwable) = arrayOf(throwable.stackTraceToString())
fun throwableListToStringList(throwableList: List<Throwable>) = fun throwableListToStringList(throwableList: List<Throwable>) =
throwableList.map { it.stackTraceToString() }.toTypedArray() throwableList.map { it.stackTraceToString() }.toTypedArray()
private fun getInfoServiceName(info: Info?) = fun getMessage(
if (info == null) SERVICE_NONE else ServiceHelper.getNameOfServiceById(info.serviceId)
@StringRes
private fun getMessageStringId(
throwable: Throwable?, throwable: Throwable?,
action: UserAction action: UserAction?,
): Int { serviceId: Int?,
): ErrorMessage {
return when { return when {
throwable is AccountTerminatedException -> R.string.account_terminated // player exceptions
throwable is ContentNotAvailableException -> R.string.content_not_available // some may be IOException, so do these checks before isNetworkRelated!
throwable != null && throwable.isNetworkRelated -> R.string.network_error
throwable is ContentNotSupportedException -> R.string.content_not_supported
throwable is ExtractionException -> R.string.parsing_error
throwable is ExoPlaybackException -> { throwable is ExoPlaybackException -> {
when (throwable.type) { val cause = throwable.cause
ExoPlaybackException.TYPE_SOURCE -> R.string.player_stream_failure when {
ExoPlaybackException.TYPE_UNEXPECTED -> R.string.player_recoverable_failure cause is HttpDataSource.InvalidResponseCodeException -> {
else -> R.string.player_unrecoverable_failure if (cause.responseCode == 403) {
if (serviceId == YouTube.serviceId) {
ErrorMessage(R.string.youtube_player_http_403)
} else {
ErrorMessage(R.string.player_http_403)
}
} else {
ErrorMessage(R.string.player_http_invalid_status, cause.responseCode.toString())
} }
} }
action == UserAction.UI_ERROR -> R.string.app_ui_crash cause is Loader.UnexpectedLoaderException && cause.cause is ExtractionException ->
action == UserAction.REQUESTED_COMMENTS -> R.string.error_unable_to_load_comments getMessage(throwable, action, serviceId)
action == UserAction.SUBSCRIPTION_CHANGE -> R.string.subscription_change_failed throwable.type == ExoPlaybackException.TYPE_SOURCE ->
action == UserAction.SUBSCRIPTION_UPDATE -> R.string.subscription_update_failed ErrorMessage(R.string.player_stream_failure)
action == UserAction.LOAD_IMAGE -> R.string.could_not_load_thumbnails throwable.type == ExoPlaybackException.TYPE_UNEXPECTED ->
action == UserAction.DOWNLOAD_OPEN_DIALOG -> R.string.could_not_setup_download_menu ErrorMessage(R.string.player_recoverable_failure)
else -> R.string.general_error else ->
ErrorMessage(R.string.player_unrecoverable_failure)
}
}
throwable is FailedMediaSource.FailedMediaSourceException ->
getMessage(throwable.cause, action, serviceId)
throwable is PlaybackResolver.ResolverException ->
ErrorMessage(R.string.player_stream_failure)
// content not available exceptions
throwable is AccountTerminatedException ->
throwable.message
?.takeIf { reason -> !reason.isEmpty() }
?.let { reason ->
ErrorMessage(
R.string.account_terminated_service_provides_reason,
getServiceName(serviceId),
reason
)
}
?: ErrorMessage(R.string.account_terminated)
throwable is AgeRestrictedContentException ->
ErrorMessage(R.string.restricted_video_no_stream)
throwable is GeographicRestrictionException ->
ErrorMessage(R.string.georestricted_content)
throwable is PaidContentException ->
ErrorMessage(R.string.paid_content)
throwable is PrivateContentException ->
ErrorMessage(R.string.private_content)
throwable is SoundCloudGoPlusContentException ->
ErrorMessage(R.string.soundcloud_go_plus_content)
throwable is UnsupportedContentInCountryException ->
ErrorMessage(R.string.unsupported_content_in_country)
throwable is YoutubeMusicPremiumContentException ->
ErrorMessage(R.string.youtube_music_premium_content)
throwable is SignInConfirmNotBotException ->
ErrorMessage(R.string.sign_in_confirm_not_bot_error, getServiceName(serviceId))
throwable is ContentNotAvailableException ->
ErrorMessage(R.string.content_not_available)
// other extractor exceptions
throwable is ContentNotSupportedException ->
ErrorMessage(R.string.content_not_supported)
// ReCaptchas will be handled in a special way anyway
throwable is ReCaptchaException ->
ErrorMessage(R.string.recaptcha_request_toast)
// test this at the end as many exceptions could be a subclass of IOException
throwable != null && throwable.isNetworkRelated ->
ErrorMessage(R.string.network_error)
// an extraction exception unrelated to the network
// is likely an issue with parsing the website
throwable is ExtractionException ->
ErrorMessage(R.string.parsing_error)
// user actions (in case the exception is null or unrecognizable)
action == UserAction.UI_ERROR ->
ErrorMessage(R.string.app_ui_crash)
action == UserAction.REQUESTED_COMMENTS ->
ErrorMessage(R.string.error_unable_to_load_comments)
action == UserAction.SUBSCRIPTION_CHANGE ->
ErrorMessage(R.string.subscription_change_failed)
action == UserAction.SUBSCRIPTION_UPDATE ->
ErrorMessage(R.string.subscription_update_failed)
action == UserAction.LOAD_IMAGE ->
ErrorMessage(R.string.could_not_load_thumbnails)
action == UserAction.DOWNLOAD_OPEN_DIALOG ->
ErrorMessage(R.string.could_not_setup_download_menu)
else ->
ErrorMessage(R.string.error_snackbar_message)
}
}
fun isReportable(throwable: Throwable?): Boolean {
return when (throwable) {
// we don't have an exception, so this is a manually built error, which likely
// indicates that it's important and is thus reportable
null -> true
// the service explicitly said that content is not available (e.g. age restrictions,
// video deleted, etc.), there is no use in letting users report it
is ContentNotAvailableException -> false
// we know the content is not supported, no need to let the user report it
is ContentNotSupportedException -> false
// happens often when there is no internet connection; we don't use
// `throwable.isNetworkRelated` since any `IOException` would make that function
// return true, but not all `IOException`s are network related
is UnknownHostException -> false
// by default, this is an unexpected exception, which the user could report
else -> true
}
}
fun isRetryable(throwable: Throwable?): Boolean {
return when (throwable) {
// we know the content is not available, retrying won't help
is ContentNotAvailableException -> false
// we know the content is not supported, retrying won't help
is ContentNotSupportedException -> false
// by default (including if throwable is null), enable retrying (though the retry
// button will be shown only if a way to perform the retry is implemented)
else -> true
} }
} }
} }

View file

@ -2,7 +2,6 @@ package org.schabi.newpipe.error
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log
import android.view.View import android.view.View
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
@ -14,21 +13,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
import org.schabi.newpipe.MainActivity import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.R 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.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 org.schabi.newpipe.util.external_communication.ShareUtils
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -78,64 +63,32 @@ class ErrorPanelHelper(
} }
fun showError(errorInfo: ErrorInfo) { fun showError(errorInfo: ErrorInfo) {
if (errorInfo.throwable != null && errorInfo.throwable!!.isInterruptedCaused) {
if (DEBUG) {
Log.w(TAG, "onError() isInterruptedCaused! = [$errorInfo.throwable]")
}
return
}
ensureDefaultVisibility() ensureDefaultVisibility()
errorTextView.text = errorInfo.getMessage(context)
if (errorInfo.throwable is ReCaptchaException) { if (errorInfo.recaptchaUrl != null) {
errorTextView.setText(R.string.recaptcha_request_toast) showAndSetErrorButtonAction(R.string.recaptcha_solve) {
showAndSetErrorButtonAction(
R.string.recaptcha_solve
) {
// Starting ReCaptcha Challenge Activity // Starting ReCaptcha Challenge Activity
val intent = Intent(context, ReCaptchaActivity::class.java) val intent = Intent(context, ReCaptchaActivity::class.java)
intent.putExtra( intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, errorInfo.recaptchaUrl)
ReCaptchaActivity.RECAPTCHA_URL_EXTRA,
(errorInfo.throwable as ReCaptchaException).url
)
fragment.startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST) fragment.startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST)
errorActionButton.setOnClickListener(null) errorActionButton.setOnClickListener(null)
} }
} else if (errorInfo.isReportable) {
errorRetryButton.isVisible = retryShouldBeShown showAndSetErrorButtonAction(R.string.error_snackbar_action) {
showAndSetOpenInBrowserButtonAction(errorInfo)
} else if (errorInfo.throwable is AccountTerminatedException) {
errorTextView.setText(R.string.account_terminated)
if (!isNullOrEmpty((errorInfo.throwable as AccountTerminatedException).message)) {
errorServiceInfoTextView.text = context.resources.getString(
R.string.service_provides_reason,
ServiceHelper.getSelectedService(context)?.serviceInfo?.name ?: "<unknown>"
)
errorServiceInfoTextView.isVisible = true
errorServiceExplanationTextView.text =
(errorInfo.throwable as AccountTerminatedException).message
errorServiceExplanationTextView.isVisible = true
}
} else {
showAndSetErrorButtonAction(
R.string.error_snackbar_action
) {
ErrorUtil.openActivity(context, errorInfo) ErrorUtil.openActivity(context, errorInfo)
} }
}
errorTextView.setText(getExceptionDescription(errorInfo.throwable)) if (errorInfo.isRetryable) {
if (errorInfo.throwable !is ContentNotAvailableException &&
errorInfo.throwable !is ContentNotSupportedException
) {
// show retry button only for content which is not unavailable or unsupported
errorRetryButton.isVisible = retryShouldBeShown errorRetryButton.isVisible = retryShouldBeShown
} }
showAndSetOpenInBrowserButtonAction(errorInfo)
if (errorInfo.openInBrowserUrl != null) {
errorOpenInBrowserButton.isVisible = true
errorOpenInBrowserButton.setOnClickListener {
ShareUtils.openUrlInBrowser(context, errorInfo.openInBrowserUrl)
}
} }
setRootVisible() setRootVisible()
@ -153,15 +106,6 @@ class ErrorPanelHelper(
errorActionButton.setOnClickListener(listener) errorActionButton.setOnClickListener(listener)
} }
fun showAndSetOpenInBrowserButtonAction(
errorInfo: ErrorInfo
) {
errorOpenInBrowserButton.isVisible = true
errorOpenInBrowserButton.setOnClickListener {
ShareUtils.openUrlInBrowser(context, errorInfo.request)
}
}
fun showTextError(errorString: String) { fun showTextError(errorString: String) {
ensureDefaultVisibility() ensureDefaultVisibility()
@ -192,27 +136,5 @@ class ErrorPanelHelper(
companion object { companion object {
val TAG: String = ErrorPanelHelper::class.simpleName!! val TAG: String = ErrorPanelHelper::class.simpleName!!
val DEBUG: Boolean = MainActivity.DEBUG 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
}
}
}
}
} }
} }

View file

@ -122,7 +122,7 @@ class ErrorUtil {
) )
.setSmallIcon(R.drawable.ic_bug_report) .setSmallIcon(R.drawable.ic_bug_report)
.setContentTitle(context.getString(R.string.error_report_notification_title)) .setContentTitle(context.getString(R.string.error_report_notification_title))
.setContentText(context.getString(errorInfo.messageStringId)) .setContentText(errorInfo.getMessage(context))
.setAutoCancel(true) .setAutoCancel(true)
.setContentIntent( .setContentIntent(
PendingIntentCompat.getActivity( PendingIntentCompat.getActivity(
@ -156,10 +156,10 @@ class ErrorUtil {
// fallback to showing a notification if no root view is available // fallback to showing a notification if no root view is available
createNotification(context, errorInfo) createNotification(context, errorInfo)
} else { } else {
Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG) Snackbar.make(rootView, errorInfo.getMessage(context), Snackbar.LENGTH_LONG)
.setActionTextColor(Color.YELLOW) .setActionTextColor(Color.YELLOW)
.setAction(context.getString(R.string.error_snackbar_action).uppercase()) { .setAction(context.getString(R.string.error_snackbar_action).uppercase()) {
openActivity(context, errorInfo) context.startActivity(getErrorActivityIntent(context, errorInfo))
}.show() }.show()
} }
} }

View file

@ -33,7 +33,9 @@ public enum UserAction {
SHARE_TO_NEWPIPE("share to newpipe"), SHARE_TO_NEWPIPE("share to newpipe"),
CHECK_FOR_NEW_APP_VERSION("check for new app version"), CHECK_FOR_NEW_APP_VERSION("check for new app version"),
OPEN_INFO_ITEM_DIALOG("open info item dialog"), 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"),
SUBSCRIPTIONS("loading subscriptions");
private final String message; private final String message;

View file

@ -771,7 +771,7 @@ class VideoDetailFragment :
}, },
{ throwable -> { throwable ->
showError( showError(
ErrorInfo(throwable, UserAction.REQUESTED_STREAM, url ?: "no url", serviceId) ErrorInfo(throwable, UserAction.REQUESTED_STREAM, url ?: "no url", serviceId, url)
) )
} }
) )
@ -1460,7 +1460,7 @@ class VideoDetailFragment :
if (!info.errors.isEmpty()) { if (!info.errors.isEmpty()) {
showSnackBarError( showSnackBarError(
ErrorInfo(info.errors, UserAction.REQUESTED_STREAM, info.url, info) ErrorInfo(info.errors, UserAction.REQUESTED_STREAM, "Some info not extracted: " + info.url, info)
) )
} }
} }

View file

@ -153,7 +153,7 @@ public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInf
handleResult(result); handleResult(result);
}, throwable -> }, throwable ->
showError(new ErrorInfo(throwable, errorUserAction, showError(new ErrorInfo(throwable, errorUserAction,
"Start loading: " + url, serviceId))); "Start loading: " + url, serviceId, url)));
} }
/** /**
@ -184,7 +184,7 @@ public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInf
handleNextItems(infoItemsPage); handleNextItems(infoItemsPage);
}, (@NonNull Throwable throwable) -> }, (@NonNull Throwable throwable) ->
dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable, dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable,
errorUserAction, "Loading more items: " + url, serviceId))); errorUserAction, "Loading more items: " + url, serviceId, url)));
} }
private void forbidDownwardFocusScroll() { private void forbidDownwardFocusScroll() {
@ -210,7 +210,7 @@ public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInf
if (!result.getErrors().isEmpty()) { if (!result.getErrors().isEmpty()) {
dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), errorUserAction, dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), errorUserAction,
"Get next items of: " + url, serviceId)); "Get next items of: " + url, serviceId, url));
} }
} }
@ -250,7 +250,7 @@ public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInf
if (!errors.isEmpty()) { if (!errors.isEmpty()) {
dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(),
errorUserAction, "Start loading: " + url, serviceId)); errorUserAction, "Start loading: " + url, serviceId, url));
} }
} }
} }

View file

@ -3,6 +3,7 @@ package org.schabi.newpipe.fragments.list.channel;
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor; import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor; import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
import static org.schabi.newpipe.ui.emptystate.EmptyStateUtil.setEmptyStateComposable;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -45,7 +46,6 @@ import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.feed.notifications.NotificationHelper; import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
import org.schabi.newpipe.local.subscription.SubscriptionManager; import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; import org.schabi.newpipe.ui.emptystate.EmptyStateSpec;
import org.schabi.newpipe.ui.emptystate.EmptyStateUtil;
import org.schabi.newpipe.util.ChannelTabHelper; import org.schabi.newpipe.util.ChannelTabHelper;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
@ -194,10 +194,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
}; };
activity.addMenuProvider(menuProvider, getViewLifecycleOwner()); activity.addMenuProvider(menuProvider, getViewLifecycleOwner());
EmptyStateUtil.setEmptyStateComposable( setEmptyStateComposable(binding.emptyStateView, EmptyStateSpec.ContentNotSupported);
binding.emptyStateView,
EmptyStateSpec.Companion.getContentNotSupported()
);
tabAdapter = new TabAdapter(getChildFragmentManager()); tabAdapter = new TabAdapter(getChildFragmentManager());
binding.viewPager.setAdapter(tabAdapter); binding.viewPager.setAdapter(tabAdapter);
@ -568,7 +565,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
isLoading.set(false); isLoading.set(false);
handleResult(result); handleResult(result);
}, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_CHANNEL, }, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_CHANNEL,
url == null ? "No URL" : url, serviceId))); url == null ? "No URL" : url, serviceId, url)));
} }
@Override @Override

View file

@ -3,6 +3,7 @@ package org.schabi.newpipe.fragments.list.search;
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags; import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
import static org.schabi.newpipe.extractor.utils.Utils.isBlank; import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ui.emptystate.EmptyStateUtil.setEmptyStateComposable;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@ -54,6 +55,7 @@ import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.search.SearchExtractor; import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.search.SearchInfo; import org.schabi.newpipe.extractor.search.SearchInfo;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
@ -65,7 +67,6 @@ import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.settings.NewPipeSettings; import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; import org.schabi.newpipe.ui.emptystate.EmptyStateSpec;
import org.schabi.newpipe.ui.emptystate.EmptyStateUtil;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
@ -356,9 +357,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
protected void initViews(final View rootView, final Bundle savedInstanceState) { protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState); super.initViews(rootView, savedInstanceState);
EmptyStateUtil.setEmptyStateComposable( setEmptyStateComposable(searchBinding.emptyStateView, EmptyStateSpec.NoSearchResult);
searchBinding.emptyStateView,
EmptyStateSpec.Companion.getNoSearchResult());
searchBinding.suggestionsList.setAdapter(suggestionListAdapter); searchBinding.suggestionsList.setAdapter(suggestionListAdapter);
// animations are just strange and useless, since the suggestions keep changing too much // animations are just strange and useless, since the suggestions keep changing too much
@ -940,7 +939,21 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
infoListAdapter.clearStreamItemList(); infoListAdapter.clearStreamItemList();
showEmptyState(); showEmptyState();
} else { } else {
showError(new ErrorInfo(exception, UserAction.SEARCHED, searchString, serviceId)); showError(new ErrorInfo(exception, UserAction.SEARCHED, searchString, serviceId,
getOpenInBrowserUrlForErrors()));
}
}
@Nullable
private String getOpenInBrowserUrlForErrors() {
if (TextUtils.isEmpty(searchString)) {
return null;
}
try {
return service.getSearchQHFactory().getUrl(searchString,
Arrays.asList(contentFilter), sortFilter);
} catch (final NullPointerException | ParsingException ignored) {
return null;
} }
} }
@ -1028,7 +1041,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
&& !(exceptions.size() == 1 && !(exceptions.size() == 1
&& exceptions.get(0) instanceof SearchExtractor.NothingFoundException)) { && exceptions.get(0) instanceof SearchExtractor.NothingFoundException)) {
showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED, showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED,
searchString, serviceId)); searchString, serviceId, getOpenInBrowserUrlForErrors()));
} }
searchSuggestion = result.getSearchSuggestion(); searchSuggestion = result.getSearchSuggestion();
@ -1101,13 +1114,14 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
// whose results are handled here, but let's check it anyway // whose results are handled here, but let's check it anyway
if (nextPage == null) { if (nextPage == null) {
showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED, showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED,
"\"" + searchString + "\" → nextPage == null", serviceId)); "\"" + searchString + "\" → nextPage == null", serviceId,
getOpenInBrowserUrlForErrors()));
} else { } else {
showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED, showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED,
"\"" + searchString + "\" → pageUrl: " + nextPage.getUrl() + ", " "\"" + searchString + "\" → pageUrl: " + nextPage.getUrl() + ", "
+ "pageIds: " + nextPage.getIds() + ", " + "pageIds: " + nextPage.getIds() + ", "
+ "pageCookies: " + nextPage.getCookies(), + "pageCookies: " + nextPage.getCookies(),
serviceId)); serviceId, getOpenInBrowserUrlForErrors()));
} }
} }

View file

@ -15,6 +15,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.compose.ui.platform.ComposeView;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -124,10 +125,8 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
super.initViews(rootView, savedInstanceState); super.initViews(rootView, savedInstanceState);
itemListAdapter.setUseItemHandle(true); itemListAdapter.setUseItemHandle(true);
EmptyStateUtil.setEmptyStateComposable( final ComposeView emptyView = rootView.findViewById(R.id.empty_state_view);
rootView.findViewById(R.id.empty_state_view), EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateSpec.NoBookmarkedPlaylist);
EmptyStateSpec.Companion.getNoBookmarkedPlaylist()
);
} }
@Override @Override

View file

@ -1,6 +1,8 @@
package org.schabi.newpipe.local.feed.notifications package org.schabi.newpipe.local.feed.notifications
import android.content.Context import android.content.Context
import android.content.pm.ServiceInfo
import android.os.Build
import android.util.Log import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.work.Constraints import androidx.work.Constraints
@ -83,7 +85,9 @@ class NotificationWorker(
.setPriority(NotificationCompat.PRIORITY_LOW) .setPriority(NotificationCompat.PRIORITY_LOW)
.setContentTitle(applicationContext.getString(R.string.feed_notification_loading)) .setContentTitle(applicationContext.getString(R.string.feed_notification_loading))
.build() .build()
setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification)) // ServiceInfo constants are not used below Android Q, so 0 is set here
val serviceType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC else 0
setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification, serviceType))
} }
companion object { companion object {

View file

@ -85,8 +85,8 @@ public class SubscriptionsImportFragment extends BaseFragment {
if (supportedSources.isEmpty() && currentServiceId != Constants.NO_SERVICE_ID) { if (supportedSources.isEmpty() && currentServiceId != Constants.NO_SERVICE_ID) {
ErrorUtil.showSnackbar(activity, ErrorUtil.showSnackbar(activity,
new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT, new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT,
ServiceHelper.getNameOfServiceById(currentServiceId),
"Service does not support importing subscriptions", "Service does not support importing subscriptions",
currentServiceId,
R.string.general_error)); R.string.general_error));
activity.finish(); activity.finish();
} }

View file

@ -1283,7 +1283,8 @@ public final class Player implements PlaybackListener, Listener {
UserAction.PLAY_STREAM, UserAction.PLAY_STREAM,
"Loading failed for [" + currentMetadata.getTitle() "Loading failed for [" + currentMetadata.getTitle()
+ "]: " + currentMetadata.getStreamUrl(), + "]: " + currentMetadata.getStreamUrl(),
currentMetadata.getServiceId()); currentMetadata.getServiceId(),
currentMetadata.getStreamUrl());
ErrorUtil.createNotification(context, errorInfo); ErrorUtil.createNotification(context, errorInfo);
} }
@ -1499,7 +1500,7 @@ public final class Player implements PlaybackListener, Listener {
errorInfo = new ErrorInfo(error, UserAction.PLAY_STREAM, errorInfo = new ErrorInfo(error, UserAction.PLAY_STREAM,
"Player error[type=" + error.getErrorCodeName() "Player error[type=" + error.getErrorCodeName()
+ "] occurred while playing " + currentMetadata.getStreamUrl(), + "] occurred while playing " + currentMetadata.getStreamUrl(),
currentMetadata.getServiceId()); currentMetadata.getServiceId(), currentMetadata.getStreamUrl());
} }
ErrorUtil.createNotification(context, errorInfo); ErrorUtil.createNotification(context, errorInfo);
} }

View file

@ -17,6 +17,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.MainActivity import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.NewPipeDatabase import org.schabi.newpipe.NewPipeDatabase
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.extractor.InfoItem.InfoType import org.schabi.newpipe.extractor.InfoItem.InfoType
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler
@ -84,7 +85,7 @@ class MediaBrowserPlaybackPreparer(
}, },
{ throwable -> { throwable ->
Log.e(TAG, "Failed to start playback of media ID [$mediaId]", throwable) Log.e(TAG, "Failed to start playback of media ID [$mediaId]", throwable)
onPrepareError() onPrepareError(throwable)
} }
) )
} }
@ -115,9 +116,9 @@ class MediaBrowserPlaybackPreparer(
) )
} }
private fun onPrepareError() { private fun onPrepareError(throwable: Throwable) {
setMediaSessionError.accept( setMediaSessionError.accept(
ContextCompat.getString(context, R.string.error_snackbar_message), ErrorInfo.getMessage(throwable, null, null).getString(context),
PlaybackStateCompat.ERROR_CODE_APP_ERROR PlaybackStateCompat.ERROR_CODE_APP_ERROR
) )
} }

View file

@ -167,19 +167,17 @@ public final class NotificationUtil {
&& notificationBuilder.mActions.get(2).actionIntent != null); && notificationBuilder.mActions.get(2).actionIntent != null);
} }
public void createNotificationAndStartForeground() { public void createNotificationAndStartForeground() {
if (notificationBuilder == null) { if (notificationBuilder == null) {
notificationBuilder = createNotification(); notificationBuilder = createNotification();
} }
updateNotification(); updateNotification();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // ServiceInfo constants are not used below Android Q, so 0 is set here
player.getService().startForeground(NOTIFICATION_ID, notificationBuilder.build(), final int serviceType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK); ? ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK : 0;
} else { ServiceCompat.startForeground(player.getService(), NOTIFICATION_ID,
player.getService().startForeground(NOTIFICATION_ID, notificationBuilder.build()); notificationBuilder.build(), serviceType);
}
} }
public void cancelNotificationAndStopForeground() { public void cancelNotificationAndStopForeground() {

View file

@ -95,8 +95,7 @@ public class SelectChannelFragment extends DialogFragment {
progressBar = v.findViewById(R.id.progressBar); progressBar = v.findViewById(R.id.progressBar);
emptyView = v.findViewById(R.id.empty_state_view); emptyView = v.findViewById(R.id.empty_state_view);
EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateSpec.NoSubscriptions);
EmptyStateSpec.Companion.getNoSubscriptions());
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE); recyclerView.setVisibility(View.GONE);
emptyView.setVisibility(View.GONE); emptyView.setVisibility(View.GONE);

View file

@ -65,8 +65,7 @@ public class SelectPlaylistFragment extends DialogFragment {
recyclerView = v.findViewById(R.id.items_list); recyclerView = v.findViewById(R.id.items_list);
emptyView = v.findViewById(R.id.empty_state_view); emptyView = v.findViewById(R.id.empty_state_view);
EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateSpec.NoBookmarkedPlaylist);
EmptyStateSpec.Companion.getNoBookmarkedPlaylist());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
final SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter(); final SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter();
recyclerView.setAdapter(playlistAdapter); recyclerView.setAdapter(playlistAdapter);

View file

@ -1,5 +1,7 @@
package org.schabi.newpipe.settings.preferencesearch; package org.schabi.newpipe.settings.preferencesearch;
import static org.schabi.newpipe.ui.emptystate.EmptyStateUtil.setEmptyStateComposable;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -12,7 +14,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import org.schabi.newpipe.databinding.SettingsPreferencesearchFragmentBinding; import org.schabi.newpipe.databinding.SettingsPreferencesearchFragmentBinding;
import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; import org.schabi.newpipe.ui.emptystate.EmptyStateSpec;
import org.schabi.newpipe.ui.emptystate.EmptyStateUtil;
import java.util.List; import java.util.List;
@ -41,9 +42,7 @@ public class PreferenceSearchFragment extends Fragment {
binding = SettingsPreferencesearchFragmentBinding.inflate(inflater, container, false); binding = SettingsPreferencesearchFragmentBinding.inflate(inflater, container, false);
binding.searchResults.setLayoutManager(new LinearLayoutManager(getContext())); binding.searchResults.setLayoutManager(new LinearLayoutManager(getContext()));
EmptyStateUtil.setEmptyStateComposable( setEmptyStateComposable(binding.emptyStateView, EmptyStateSpec.NoSearchResult);
binding.emptyStateView,
EmptyStateSpec.Companion.getNoSearchMaxSizeResult());
adapter = new PreferenceSearchAdapter(); adapter = new PreferenceSearchAdapter();
adapter.setOnItemClickListener(this::onItemClicked); adapter.setOnItemClickListener(this::onItemClicked);

View file

@ -1,12 +1,14 @@
package org.schabi.newpipe.ui.components.about package org.schabi.newpipe.ui.components.about
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@ -16,7 +18,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.NonRestartableComposable import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -26,13 +27,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.getDrawable
import coil3.compose.AsyncImage
import my.nanihadesuka.compose.ColumnScrollbar import my.nanihadesuka.compose.ColumnScrollbar
import org.schabi.newpipe.BuildConfig import org.schabi.newpipe.BuildConfig
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.ui.components.common.defaultThemedScrollbarSettings import org.schabi.newpipe.ui.components.common.defaultThemedScrollbarSettings
import org.schabi.newpipe.util.external_communication.ShareUtils import org.schabi.newpipe.util.external_communication.ShareUtils
import org.schabi.newpipe.util.image.NewPipeSquircleIcon
private val ABOUT_ITEMS = listOf( private val ABOUT_ITEMS = listOf(
AboutData(R.string.faq_title, R.string.faq_description, R.string.faq, R.string.faq_url), AboutData(R.string.faq_title, R.string.faq_description, R.string.faq, R.string.faq_url),
@ -83,12 +83,10 @@ fun AboutTab() {
.wrapContentSize(Alignment.Center), .wrapContentSize(Alignment.Center),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
// note: the preview Image(
val context = LocalContext.current imageVector = NewPipeSquircleIcon,
val launcherDrawable = remember { getDrawable(context, R.mipmap.ic_launcher) }
AsyncImage(
model = launcherDrawable,
contentDescription = stringResource(R.string.app_name), contentDescription = stringResource(R.string.app_name),
modifier = Modifier.size(64.dp),
) )
Spacer(Modifier.height(4.dp)) Spacer(Modifier.height(4.dp))
Text( Text(

View file

@ -19,7 +19,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.datasource.LoremIpsum import androidx.compose.ui.tooling.preview.datasource.LoremIpsum
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -122,30 +121,25 @@ private fun CommentRepliesDialog(
if (comments.itemCount == 0) { if (comments.itemCount == 0) {
item { item {
val refresh = comments.loadState.refresh when (val refresh = comments.loadState.refresh) {
if (refresh is LoadState.Loading) { is LoadState.Loading -> {
LoadingIndicator(modifier = Modifier.padding(top = 8.dp)) LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
} else if (refresh is LoadState.Error) { }
else -> {
// TODO use error panel instead // TODO use error panel instead
EmptyStateComposable( EmptyStateComposable(
spec = EmptyStateSpec.DisabledComments.copy( spec = if (refresh is LoadState.Error) {
descriptionText = { EmptyStateSpec.ErrorLoadingComments
stringResource(R.string.error_unable_to_load_comments)
},
),
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 128.dp)
)
} else { } else {
EmptyStateComposable( EmptyStateSpec.NoComments
spec = EmptyStateSpec.NoComments, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = 128.dp) .heightIn(min = 128.dp)
) )
} }
} }
}
} else { } else {
items(comments.itemCount) { items(comments.itemCount) {
Comment( Comment(

View file

@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -75,7 +74,6 @@ private fun CommentSection(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = 128.dp) .heightIn(min = 128.dp)
) )
} }
} else if (count == 0) { } else if (count == 0) {
@ -111,13 +109,7 @@ private fun CommentSection(
is LoadState.Error -> { is LoadState.Error -> {
item { item {
// TODO use error panel instead // TODO use error panel instead
EmptyStateComposable( EmptyStateComposable(EmptyStateSpec.ErrorLoadingComments)
EmptyStateSpec.DisabledComments.copy(
descriptionText = {
stringResource(R.string.error_unable_to_load_comments)
}
)
)
} }
} }
@ -134,11 +126,7 @@ private fun CommentSection(
item { item {
// TODO use error panel instead // TODO use error panel instead
EmptyStateComposable( EmptyStateComposable(
spec = EmptyStateSpec.DisabledComments.copy( spec = EmptyStateSpec.ErrorLoadingComments,
descriptionText = {
stringResource(R.string.error_unable_to_load_comments)
}
),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = 128.dp) .heightIn(min = 128.dp)

View file

@ -1,6 +1,7 @@
package org.schabi.newpipe.ui.emptystate package org.schabi.newpipe.ui.emptystate
import android.graphics.Color import android.graphics.Color
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -22,25 +23,14 @@ import org.schabi.newpipe.ui.theme.AppTheme
fun EmptyStateComposable( fun EmptyStateComposable(
spec: EmptyStateSpec, spec: EmptyStateSpec,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) = EmptyStateComposable(
emojiText = spec.emojiText(),
descriptionText = spec.descriptionText(),
modifier = modifier
)
@Composable
private fun EmptyStateComposable(
emojiText: String,
descriptionText: String,
modifier: Modifier = Modifier,
) { ) {
Column( Column(
modifier = modifier, modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center,
) { ) {
Text( Text(
text = emojiText, text = spec.emojiText,
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleLarge,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
) )
@ -49,7 +39,7 @@ private fun EmptyStateComposable(
modifier = Modifier modifier = Modifier
.padding(top = 6.dp) .padding(top = 6.dp)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
text = descriptionText, text = stringResource(spec.descriptionText),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
) )
@ -82,66 +72,48 @@ fun EmptyStateComposableNoCommentPreview() {
} }
} }
data class EmptyStateSpec( enum class EmptyStateSpec(
val emojiText: @Composable () -> String, val emojiText: String,
val descriptionText: @Composable () -> String, @field:StringRes val descriptionText: Int,
) { ) {
companion object { GenericError(
emojiText = "¯\\_(ツ)_/¯",
val GenericError = descriptionText = R.string.empty_list_subtitle,
EmptyStateSpec( ),
emojiText = { "¯\\_(ツ)_/¯" }, NoVideos(
descriptionText = { stringResource(id = R.string.empty_list_subtitle) }, emojiText = "(╯°-°)╯",
) descriptionText = R.string.no_videos,
),
val NoVideos = NoComments(
EmptyStateSpec( emojiText = "¯\\_(╹x╹)_/¯",
emojiText = { "(╯°-°)╯" }, descriptionText = R.string.no_comments,
descriptionText = { stringResource(id = R.string.no_videos) }, ),
) DisabledComments(
emojiText = "¯\\_(╹x╹)_/¯",
val NoComments = descriptionText = R.string.comments_are_disabled,
EmptyStateSpec( ),
ErrorLoadingComments(
emojiText = { "¯\\_(╹x╹)_/¯" }, emojiText = "¯\\_(╹x╹)_/¯",
descriptionText = { stringResource(id = R.string.no_comments) }, descriptionText = R.string.error_unable_to_load_comments,
) ),
NoSearchResult(
val DisabledComments = emojiText = "╰(°●°╰)",
NoComments.copy( descriptionText = R.string.search_no_results,
descriptionText = { stringResource(id = R.string.comments_are_disabled) }, ),
) ContentNotSupported(
emojiText = "(︶︹︺)",
val NoSearchResult = descriptionText = R.string.content_not_supported,
NoComments.copy( ),
emojiText = { "╰(°●°╰)" }, NoBookmarkedPlaylist(
descriptionText = { stringResource(id = R.string.search_no_results) } emojiText = "(╥﹏╥)",
) descriptionText = R.string.no_playlist_bookmarked_yet,
),
val NoSearchMaxSizeResult = NoSubscriptionsHint(
NoSearchResult emojiText = "(꩜ᯅ꩜)",
descriptionText = R.string.import_subscriptions_hint,
val ContentNotSupported = ),
NoComments.copy( NoSubscriptions(
emojiText = { "(︶︹︺)" }, emojiText = "(꩜ᯅ꩜)",
descriptionText = { stringResource(id = R.string.content_not_supported) }, descriptionText = R.string.no_channel_subscribed_yet,
) ),
val NoBookmarkedPlaylist =
EmptyStateSpec(
emojiText = { "(╥﹏╥)" },
descriptionText = { stringResource(id = R.string.no_playlist_bookmarked_yet) },
)
val NoSubscriptionsHint =
EmptyStateSpec(
emojiText = { "(꩜ᯅ꩜)" },
descriptionText = { stringResource(id = R.string.import_subscriptions_hint) },
)
val NoSubscriptions =
NoSubscriptionsHint.copy(
descriptionText = { stringResource(id = R.string.no_channel_subscribed_yet) },
)
}
} }

View file

@ -9,9 +9,11 @@ import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.text.Html;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@ -113,6 +115,7 @@ public final class PermissionHelper {
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
public static boolean checkSystemAlertWindowPermission(final Context context) { public static boolean checkSystemAlertWindowPermission(final Context context) {
if (!Settings.canDrawOverlays(context)) { if (!Settings.canDrawOverlays(context)) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
final Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, final Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + context.getPackageName())); Uri.parse("package:" + context.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@ -121,6 +124,38 @@ public final class PermissionHelper {
} catch (final ActivityNotFoundException ignored) { } catch (final ActivityNotFoundException ignored) {
} }
return false; return false;
// from Android R the ACTION_MANAGE_OVERLAY_PERMISSION will only point to the menu,
// so lets add a dialog that points the user to the right setting.
} else {
final String appName = context.getApplicationInfo()
.loadLabel(context.getPackageManager()).toString();
final String title = context.getString(R.string.permission_display_over_apps);
final String permissionName =
context.getString(R.string.permission_display_over_apps_permission_name);
final String appNameItalic = "<i>" + appName + "</i>";
final String permissionNameItalic = "<i>" + permissionName + "</i>";
final String message =
context.getString(R.string.permission_display_over_apps_message,
appNameItalic,
permissionNameItalic
);
new AlertDialog.Builder(context)
.setTitle(title)
.setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT))
.setPositiveButton("OK", (dialog, which) -> {
// we dont need the package name here, since it wont do anything on >R
final Intent intent =
new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
try {
context.startActivity(intent);
} catch (final ActivityNotFoundException ignored) {
}
})
.setCancelable(true)
.show();
return false;
}
} else { } else {
return true; return true;
} }

View file

@ -121,7 +121,7 @@ public final class SparseItemUtil {
callback.accept(result); callback.accept(result);
}, throwable -> ErrorUtil.createNotification(context, }, throwable -> ErrorUtil.createNotification(context,
new ErrorInfo(throwable, UserAction.REQUESTED_STREAM, new ErrorInfo(throwable, UserAction.REQUESTED_STREAM,
"Loading stream info: " + url, serviceId) "Loading stream info: " + url, serviceId, url)
)); ));
} }
} }

View file

@ -0,0 +1,99 @@
package org.schabi.newpipe.util.image
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
/**
* Generated with https://github.com/rafaeltonholo/svg-to-compose/
* based on assets/newpipe_squircle.svg.
*/
val NewPipeSquircleIcon: ImageVector
get() {
val current = _newPipeIcon
if (current != null) return current
return ImageVector.Builder(
name = "org.schabi.newpipe.ui.theme.AppTheme.NewPipeSquircleIcon",
defaultWidth = 100.0.dp,
defaultHeight = 100.0.dp,
viewportWidth = 100.0f,
viewportHeight = 100.0f,
).apply {
// M0 50 C0 15 15 0 50 0 s50 15 50 50 -15 50 -50 50 S0 85 0 50
path(
fill = SolidColor(Color(0xFFCD201F)),
) {
// M 0 50
moveTo(x = 0.0f, y = 50.0f)
// C 0 15 15 0 50 0
curveTo(
x1 = 0.0f,
y1 = 15.0f,
x2 = 15.0f,
y2 = 0.0f,
x3 = 50.0f,
y3 = 0.0f,
)
// s 50 15 50 50
reflectiveCurveToRelative(
dx1 = 50.0f,
dy1 = 15.0f,
dx2 = 50.0f,
dy2 = 50.0f,
)
// s -15 50 -50 50
reflectiveCurveToRelative(
dx1 = -15.0f,
dy1 = 50.0f,
dx2 = -50.0f,
dy2 = 50.0f,
)
// S 0 85 0 50
reflectiveCurveTo(
x1 = 0.0f,
y1 = 85.0f,
x2 = 0.0f,
y2 = 50.0f,
)
}
// M31.7 19.2 v61.7 l9.7 -5.73 V36 l23.8 14 -17.6 10.35 V71.5 L84 50
path(
fill = SolidColor(Color(0xFFFFFFFF)),
) {
// M 31.7 19.2
moveTo(x = 31.7f, y = 19.2f)
// v 61.7
verticalLineToRelative(dy = 61.7f)
// l 9.7 -5.73
lineToRelative(dx = 9.7f, dy = -5.73f)
// V 36
verticalLineTo(y = 36.0f)
// l 23.8 14
lineToRelative(dx = 23.8f, dy = 14.0f)
// l -17.6 10.35
lineToRelative(dx = -17.6f, dy = 10.35f)
// V 71.5
verticalLineTo(y = 71.5f)
// L 84 50
lineTo(x = 84.0f, y = 50.0f)
}
}.build().also { _newPipeIcon = it }
}
@Preview
@Composable
private fun IconPreview() {
Image(
imageVector = NewPipeSquircleIcon,
contentDescription = null,
)
}
@Suppress("ObjectPropertyName")
private var _newPipeIcon: ImageVector? = null

View file

@ -1,14 +1,13 @@
package org.schabi.newpipe.util.text; package org.schabi.newpipe.util.text;
import android.content.Context; import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R; import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorPanelHelper; import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@ -158,19 +157,13 @@ public final class InternalUrlsHandler {
disposables.add(single.subscribeOn(Schedulers.io()) disposables.add(single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> { .subscribe(info -> {
final PlayQueue playQueue = final PlayQueue playQueue = new SinglePlayQueue(info, seconds * 1000L);
new SinglePlayQueue(info, seconds * 1000L);
NavigationHelper.playOnPopupPlayer(context, playQueue, false); NavigationHelper.playOnPopupPlayer(context, playQueue, false);
}, throwable -> { }, throwable -> {
if (DEBUG) { // This will only show a snackbar if the passed context has a root view:
Log.e(TAG, "Could not play on popup: " + url, throwable); // otherwise it will resort to showing a notification, so we are safe here.
} ErrorUtil.showSnackbar(context,
new AlertDialog.Builder(context) new ErrorInfo(throwable, UserAction.PLAY_ON_POPUP, url, null, url));
.setTitle(R.string.player_stream_failure)
.setMessage(
ErrorPanelHelper.Companion.getExceptionDescription(throwable))
.setPositiveButton(R.string.ok, null)
.show();
})); }));
return true; return true;
} }

View file

@ -265,7 +265,7 @@ public class DownloadManager {
} }
} }
public void deleteMission(Mission mission) { public void deleteMission(Mission mission, boolean alsoDeleteFile) {
synchronized (this) { synchronized (this) {
if (mission instanceof DownloadMission) { if (mission instanceof DownloadMission) {
mMissionsPending.remove(mission); mMissionsPending.remove(mission);
@ -274,9 +274,11 @@ public class DownloadManager {
mFinishedMissionStore.deleteMission(mission); mFinishedMissionStore.deleteMission(mission);
} }
if (alsoDeleteFile) {
mission.delete(); mission.delete();
} }
} }
}
public void forgetMission(StoredFileHelper storage) { public void forgetMission(StoredFileHelper storage) {
synchronized (this) { synchronized (this) {

View file

@ -563,16 +563,16 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
} }
request.append("]"); request.append("]");
String service; Integer service;
try { try {
service = NewPipe.getServiceByUrl(mission.source).getServiceInfo().getName(); service = NewPipe.getServiceByUrl(mission.source).getServiceId();
} catch (Exception e) { } catch (Exception e) {
service = ErrorInfo.SERVICE_NONE; service = null;
} }
ErrorUtil.createNotification(mContext, ErrorUtil.createNotification(mContext,
new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action, new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action,
service, request.toString(), reason)); request.toString(), service, reason));
} }
public void clearFinishedDownloads(boolean delete) { public void clearFinishedDownloads(boolean delete) {
@ -614,7 +614,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
while (i.hasNext()) { while (i.hasNext()) {
Mission mission = i.next(); Mission mission = i.next();
if (mission != null) { if (mission != null) {
mDownloadManager.deleteMission(mission); mDownloadManager.deleteMission(mission, true);
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri())); mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri()));
} }
i.remove(); i.remove();
@ -667,7 +667,14 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
shareFile(h.item.mission); shareFile(h.item.mission);
return true; return true;
case R.id.delete: case R.id.delete:
mDeleter.append(h.item.mission); // delete the entry and the file
mDeleter.append(h.item.mission, true);
applyChanges();
checkMasterButtonsVisibility();
return true;
case R.id.delete_entry:
// just delete the entry
mDeleter.append(h.item.mission, false);
applyChanges(); applyChanges();
checkMasterButtonsVisibility(); checkMasterButtonsVisibility();
return true; return true;
@ -676,7 +683,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
final StoredFileHelper storage = h.item.mission.storage; final StoredFileHelper storage = h.item.mission.storage;
if (!storage.existsAsFile()) { if (!storage.existsAsFile()) {
Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show(); Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show();
mDeleter.append(h.item.mission); mDeleter.append(h.item.mission, true);
applyChanges(); applyChanges();
return true; return true;
} }

View file

@ -13,7 +13,9 @@ import com.google.android.material.snackbar.Snackbar;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Optional;
import kotlin.Pair;
import us.shandian.giga.get.FinishedMission; import us.shandian.giga.get.FinishedMission;
import us.shandian.giga.get.Mission; import us.shandian.giga.get.Mission;
import us.shandian.giga.service.DownloadManager; import us.shandian.giga.service.DownloadManager;
@ -30,7 +32,8 @@ public class Deleter {
private static final int DELAY_RESUME = 400;// ms private static final int DELAY_RESUME = 400;// ms
private Snackbar snackbar; private Snackbar snackbar;
private ArrayList<Mission> items; // list of missions to be deleted, and whether to also delete the corresponding file
private ArrayList<Pair<Mission, Boolean>> items;
private boolean running = true; private boolean running = true;
private final Context mContext; private final Context mContext;
@ -51,7 +54,7 @@ public class Deleter {
items = new ArrayList<>(2); items = new ArrayList<>(2);
} }
public void append(Mission item) { public void append(Mission item, boolean alsoDeleteFile) {
/* If a mission is removed from the list while the Snackbar for a previously /* If a mission is removed from the list while the Snackbar for a previously
* removed item is still showing, commit the action for the previous item * removed item is still showing, commit the action for the previous item
* immediately. This prevents Snackbars from stacking up in reverse order. * immediately. This prevents Snackbars from stacking up in reverse order.
@ -60,13 +63,13 @@ public class Deleter {
commit(); commit();
mIterator.hide(item); mIterator.hide(item);
items.add(0, item); items.add(0, new Pair<>(item, alsoDeleteFile));
show(); show();
} }
private void forget() { private void forget() {
mIterator.unHide(items.remove(0)); mIterator.unHide(items.remove(0).getFirst());
mAdapter.applyChanges(); mAdapter.applyChanges();
show(); show();
@ -84,7 +87,19 @@ public class Deleter {
private void next() { private void next() {
if (items.size() < 1) return; if (items.size() < 1) return;
String msg = mContext.getString(R.string.file_deleted).concat(":\n").concat(items.get(0).storage.getName()); final Optional<String> fileToBeDeleted = items.stream()
.filter(Pair::getSecond)
.map(p -> p.getFirst().storage.getName())
.findFirst();
String msg;
if (fileToBeDeleted.isPresent()) {
msg = mContext.getString(R.string.file_deleted)
.concat(":\n")
.concat(fileToBeDeleted.get());
} else {
msg = mContext.getString(R.string.entry_deleted);
}
snackbar = Snackbar.make(mView, msg, Snackbar.LENGTH_INDEFINITE); snackbar = Snackbar.make(mView, msg, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.undo, s -> forget()); snackbar.setAction(R.string.undo, s -> forget());
@ -98,11 +113,13 @@ public class Deleter {
if (items.size() < 1) return; if (items.size() < 1) return;
while (items.size() > 0) { while (items.size() > 0) {
Mission mission = items.remove(0); Pair<Mission, Boolean> missionAndAlsoDeleteFile = items.remove(0);
Mission mission = missionAndAlsoDeleteFile.getFirst();
boolean alsoDeleteFile = missionAndAlsoDeleteFile.getSecond();
if (mission.deleted) continue; if (mission.deleted) continue;
mIterator.unHide(mission); mIterator.unHide(mission);
mDownloadManager.deleteMission(mission); mDownloadManager.deleteMission(mission, alsoDeleteFile);
if (mission instanceof FinishedMission) { if (mission instanceof FinishedMission) {
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri())); mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri()));
@ -137,7 +154,11 @@ public class Deleter {
pause(); pause();
for (Mission mission : items) mDownloadManager.deleteMission(mission); for (Pair<Mission, Boolean> missionAndAlsoDeleteFile : items) {
Mission mission = missionAndAlsoDeleteFile.getFirst();
boolean alsoDeleteFile = missionAndAlsoDeleteFile.getSecond();
mDownloadManager.deleteMission(mission, alsoDeleteFile);
}
items = null; items = null;
} }
} }

View file

@ -27,7 +27,11 @@
<item <item
android:id="@+id/delete" android:id="@+id/delete"
android:title="@string/delete" /> android:title="@string/delete_file" />
<item
android:id="@+id/delete_entry"
android:title="@string/delete_entry" />
<item <item
android:id="@+id/error_message_view" android:id="@+id/error_message_view"

View file

@ -640,7 +640,6 @@
<string name="play_queue_audio_track">الصوت : %s</string> <string name="play_queue_audio_track">الصوت : %s</string>
<string name="playback_step">خطوة</string> <string name="playback_step">خطوة</string>
<string name="recaptcha_solve">حل</string> <string name="recaptcha_solve">حل</string>
<string name="service_provides_reason">%s يقدم هذا السبب:</string>
<string name="selected_stream_external_player_not_supported">الدفق المحدد غير مدعوم من قبل المشغلون الخارجيون</string> <string name="selected_stream_external_player_not_supported">الدفق المحدد غير مدعوم من قبل المشغلون الخارجيون</string>
<string name="title_activity_about">عن تطبيق نيوپايپ</string> <string name="title_activity_about">عن تطبيق نيوپايپ</string>
<string name="seek_duration_title">تسريع إلى الأمام/-ترجيع وقت البحث</string> <string name="seek_duration_title">تسريع إلى الأمام/-ترجيع وقت البحث</string>

View file

@ -649,7 +649,6 @@
<string name="description_select_enable">تمكين تحديد نص في الوصف</string> <string name="description_select_enable">تمكين تحديد نص في الوصف</string>
<string name="description_select_note">يمكنك الآن تحديد نص داخل الوصف. لاحظ أن الصفحة قد تومض وقد لا تكون الروابط قابلة للنقر أثناء وضع التحديد.</string> <string name="description_select_note">يمكنك الآن تحديد نص داخل الوصف. لاحظ أن الصفحة قد تومض وقد لا تكون الروابط قابلة للنقر أثناء وضع التحديد.</string>
<string name="open_website_license">فتح الموقع</string> <string name="open_website_license">فتح الموقع</string>
<string name="service_provides_reason">%s يقدم هذا السبب:</string>
<string name="account_terminated">تم إنهاء الحساب</string> <string name="account_terminated">تم إنهاء الحساب</string>
<string name="feed_load_error_fast_unknown">لا يوفر وضع التغذية السريعة مزيدًا من المعلومات حول هذا الموضوع.</string> <string name="feed_load_error_fast_unknown">لا يوفر وضع التغذية السريعة مزيدًا من المعلومات حول هذا الموضوع.</string>
<string name="feed_load_error_terminated">حساب منشئ المحتوى قد تم إنهائه. <string name="feed_load_error_terminated">حساب منشئ المحتوى قد تم إنهائه.

View file

@ -499,7 +499,6 @@
<string name="enable_queue_limit">Endirmə növbəsini məhdudlaşdır</string> <string name="enable_queue_limit">Endirmə növbəsini məhdudlaşdır</string>
<string name="enable_queue_limit_desc">Eyni vaxtda ancaq bir endirmə həyata keçiriləcək</string> <string name="enable_queue_limit_desc">Eyni vaxtda ancaq bir endirmə həyata keçiriləcək</string>
<string name="account_terminated">Hesab ləğv edildi</string> <string name="account_terminated">Hesab ləğv edildi</string>
<string name="service_provides_reason">%s bu səbəbi təmin edir:</string>
<string name="download_has_started">Yükləmə başladı</string> <string name="download_has_started">Yükləmə başladı</string>
<string name="description_select_disable">ıqlamadakı mətni seçməyi qeyri-aktiv et</string> <string name="description_select_disable">ıqlamadakı mətni seçməyi qeyri-aktiv et</string>
<string name="metadata_category">Kateqoriya</string> <string name="metadata_category">Kateqoriya</string>

View file

@ -704,7 +704,6 @@
<string name="private_content">Гэта змесціва з\'яўляецца прыватным, таму NewPipe не можа яго трансляваць або спампоўваць.</string> <string name="private_content">Гэта змесціва з\'яўляецца прыватным, таму NewPipe не можа яго трансляваць або спампоўваць.</string>
<string name="youtube_music_premium_content">Гэта відэа даступна толькі для падпісчыкаў YouTube Music Premium, таму NewPipe не можа яго трансляваць або спампоўваць.</string> <string name="youtube_music_premium_content">Гэта відэа даступна толькі для падпісчыкаў YouTube Music Premium, таму NewPipe не можа яго трансляваць або спампоўваць.</string>
<string name="account_terminated">Уліковы запіс спынены</string> <string name="account_terminated">Уліковы запіс спынены</string>
<string name="service_provides_reason">%s дае наступную прычыну:</string>
<string name="featured">Вартае ўвагі</string> <string name="featured">Вартае ўвагі</string>
<string name="metadata_privacy_internal">Унутраная</string> <string name="metadata_privacy_internal">Унутраная</string>
<string name="feed_show_watched">Прагледжаныя цалкам</string> <string name="feed_show_watched">Прагледжаныя цалкам</string>

View file

@ -416,7 +416,6 @@
<string name="playlist_page_summary">Страница на плейлиста</string> <string name="playlist_page_summary">Страница на плейлиста</string>
<string name="chapters">Глави</string> <string name="chapters">Глави</string>
<string name="metadata_licence">Лиценз</string> <string name="metadata_licence">Лиценз</string>
<string name="service_provides_reason">%s посочва следната причина:</string>
<string name="metadata_tags">Маркери</string> <string name="metadata_tags">Маркери</string>
<string name="metadata_privacy">Поверителност</string> <string name="metadata_privacy">Поверителност</string>
<string name="metadata_language">Език</string> <string name="metadata_language">Език</string>

View file

@ -540,7 +540,6 @@
<string name="feed_load_error_account_info">\'%s\' এর জন্য ফিড প্রক্রিয়া করা যাচ্ছে না।</string> <string name="feed_load_error_account_info">\'%s\' এর জন্য ফিড প্রক্রিয়া করা যাচ্ছে না।</string>
<string name="description_select_disable">বর্ণনার লেখা নির্বাচন করা নিষ্ক্রিয় করো</string> <string name="description_select_disable">বর্ণনার লেখা নির্বাচন করা নিষ্ক্রিয় করো</string>
<string name="description_select_enable">বর্ণনার লেখা নির্বাচন করা সক্ষম করো</string> <string name="description_select_enable">বর্ণনার লেখা নির্বাচন করা সক্ষম করো</string>
<string name="service_provides_reason">%s এই কারণ বলছে:</string>
<string name="feed_load_error">প্রক্রিয়াকরণ ফিডে ত্রুটি</string> <string name="feed_load_error">প্রক্রিয়াকরণ ফিডে ত্রুটি</string>
<string name="open_website_license">ওয়েবসাইট খুলুন</string> <string name="open_website_license">ওয়েবসাইট খুলুন</string>
<string name="account_terminated">অ্যাকাউন্ট ধ্বংসকৃত</string> <string name="account_terminated">অ্যাকাউন্ট ধ্বংসকৃত</string>

View file

@ -612,7 +612,6 @@
<string name="select_night_theme_toast">Pot seleccionar el seu tema fosc favorit aqui sota</string> <string name="select_night_theme_toast">Pot seleccionar el seu tema fosc favorit aqui sota</string>
<string name="night_theme_summary">Selecciona el teu tema fosc favorit — %s</string> <string name="night_theme_summary">Selecciona el teu tema fosc favorit — %s</string>
<string name="auto_device_theme_title">Automàtic (tema del dispositiu)</string> <string name="auto_device_theme_title">Automàtic (tema del dispositiu)</string>
<string name="service_provides_reason">%s dóna aquesta raó:</string>
<string name="account_terminated">Usuari suspes</string> <string name="account_terminated">Usuari suspes</string>
<string name="feed_load_error_terminated">El compte de l\'autor ha estat esborrat. <string name="feed_load_error_terminated">El compte de l\'autor ha estat esborrat.
\nNewPipe no serà capaç de carregar aquest fil en el futur. \nNewPipe no serà capaç de carregar aquest fil en el futur.

View file

@ -596,7 +596,6 @@
<string name="radio">ڕادیۆ</string> <string name="radio">ڕادیۆ</string>
<string name="featured">تایبەتکراو</string> <string name="featured">تایبەتکراو</string>
<string name="paid_content">ئه‌م بابه‌ته‌ ته‌نیا بۆ ئه‌و كه‌سانه‌ به‌رده‌سته‌ كه‌ پاره‌یان داوه‌ ، بۆیه‌ ناتوانرێت له‌ نیوپایپه‌وه‌ داببه‌زێنرێت.</string> <string name="paid_content">ئه‌م بابه‌ته‌ ته‌نیا بۆ ئه‌و كه‌سانه‌ به‌رده‌سته‌ كه‌ پاره‌یان داوه‌ ، بۆیه‌ ناتوانرێت له‌ نیوپایپه‌وه‌ داببه‌زێنرێت.</string>
<string name="service_provides_reason">%s ئه‌م هۆكاره‌ دابین ده‌كات:</string>
<string name="account_terminated">هه‌ژمار له‌ناوبراوه‌</string> <string name="account_terminated">هه‌ژمار له‌ناوبراوه‌</string>
<string name="youtube_music_premium_content">ئه‌م ڤیدیۆیه‌ ته‌نیا له‌ وه‌شانی نایابی یوتوب میوزیك به‌رده‌سته‌ ، بۆیه‌ ناتوانرێت له‌ نیوپایپه‌وه‌ داببه‌زێنرێت.</string> <string name="youtube_music_premium_content">ئه‌م ڤیدیۆیه‌ ته‌نیا له‌ وه‌شانی نایابی یوتوب میوزیك به‌رده‌سته‌ ، بۆیه‌ ناتوانرێت له‌ نیوپایپه‌وه‌ داببه‌زێنرێت.</string>
<string name="soundcloud_go_plus_content">ئه‌مه‌ تراكی SoundCloud Go+ ه ، لانی كه‌م له‌ وڵاته‌كه‌ی تۆدا، ناتوانرێت له‌لایه‌ن نیوپایپه‌وه‌ داببه‌زێنرێت.</string> <string name="soundcloud_go_plus_content">ئه‌مه‌ تراكی SoundCloud Go+ ه ، لانی كه‌م له‌ وڵاته‌كه‌ی تۆدا، ناتوانرێت له‌لایه‌ن نیوپایپه‌وه‌ داببه‌زێنرێت.</string>

View file

@ -619,7 +619,6 @@
<string name="description_select_disable">Vypnout výběr textu v popisu</string> <string name="description_select_disable">Vypnout výběr textu v popisu</string>
<string name="description_select_enable">Zapnout výběr textu v popisu</string> <string name="description_select_enable">Zapnout výběr textu v popisu</string>
<string name="description_select_note">Nyní můžete vybrat v popisu text. Pamatujte, že v režimu výběru může stránka blikat a odkazy nemusí reagovat na kliknutí.</string> <string name="description_select_note">Nyní můžete vybrat v popisu text. Pamatujte, že v režimu výběru může stránka blikat a odkazy nemusí reagovat na kliknutí.</string>
<string name="service_provides_reason">%s udává teno důvod:</string>
<string name="account_terminated">Účet uzavřen</string> <string name="account_terminated">Účet uzavřen</string>
<string name="feed_load_error_fast_unknown">Režim rychlého feedu o tom neposkytuje více informací.</string> <string name="feed_load_error_fast_unknown">Režim rychlého feedu o tom neposkytuje více informací.</string>
<string name="feed_load_error_terminated">Autorův účet byl uzavřen. <string name="feed_load_error_terminated">Autorův účet byl uzavřen.

View file

@ -553,7 +553,6 @@
<string name="private_content">Dette indhold er privat, så det kan ikke streames eller hentes af NewPipe.</string> <string name="private_content">Dette indhold er privat, så det kan ikke streames eller hentes af NewPipe.</string>
<string name="recently_added">Nyligt tilføjede</string> <string name="recently_added">Nyligt tilføjede</string>
<string name="featured">Fremhævede</string> <string name="featured">Fremhævede</string>
<string name="service_provides_reason">%s giver denne grund:</string>
<plurals name="listening"> <plurals name="listening">
<item quantity="one">%s lytter</item> <item quantity="one">%s lytter</item>
<item quantity="other">%s lyttere</item> <item quantity="other">%s lyttere</item>

View file

@ -627,7 +627,6 @@
<string name="downloads_storage_ask_summary_no_saf_notice">Du wirst jedes Mal gefragt werden, wohin der Download gespeichert werden soll</string> <string name="downloads_storage_ask_summary_no_saf_notice">Du wirst jedes Mal gefragt werden, wohin der Download gespeichert werden soll</string>
<string name="feed_load_error">Fehler beim Laden des Feeds</string> <string name="feed_load_error">Fehler beim Laden des Feeds</string>
<string name="feed_load_error_account_info">Konnte Feed für \'%s\' nicht laden.</string> <string name="feed_load_error_account_info">Konnte Feed für \'%s\' nicht laden.</string>
<string name="service_provides_reason">%s gibt diesen Grund an:</string>
<string name="on">An</string> <string name="on">An</string>
<string name="tablet_mode_title">Tablet-Modus</string> <string name="tablet_mode_title">Tablet-Modus</string>
<string name="off">Aus</string> <string name="off">Aus</string>

View file

@ -608,7 +608,6 @@
<string name="description_select_enable">Ενεργοποίηση επιλογής κειμένου στην περιγραφή</string> <string name="description_select_enable">Ενεργοποίηση επιλογής κειμένου στην περιγραφή</string>
<string name="description_select_note">Τώρα μπορείτε να επιλέξετε κείμενο εντός της περιγραφής. Σημειώστε ότι, η σελίδα μπορεί να παρουσιάζει αστάθεια κατά τη διάρκεια της κατάστασης επιλογής κειμένου.</string> <string name="description_select_note">Τώρα μπορείτε να επιλέξετε κείμενο εντός της περιγραφής. Σημειώστε ότι, η σελίδα μπορεί να παρουσιάζει αστάθεια κατά τη διάρκεια της κατάστασης επιλογής κειμένου.</string>
<string name="open_website_license">Ανοικτή ιστοσελίδα</string> <string name="open_website_license">Ανοικτή ιστοσελίδα</string>
<string name="service_provides_reason">Το %s παρέχει αυτή την αιτία:</string>
<string name="account_terminated">Ο λογαριασμός διαγράφηκε</string> <string name="account_terminated">Ο λογαριασμός διαγράφηκε</string>
<string name="feed_load_error_fast_unknown">Η κατάσταση γρήγορης τροφοδοσίας δεν παρέχει περισσότερες πληροφορίες.</string> <string name="feed_load_error_fast_unknown">Η κατάσταση γρήγορης τροφοδοσίας δεν παρέχει περισσότερες πληροφορίες.</string>
<string name="feed_load_error_terminated">Ο λογαριασμός του δημιουργού έχει διαγραφεί. <string name="feed_load_error_terminated">Ο λογαριασμός του δημιουργού έχει διαγραφεί.

View file

@ -504,7 +504,6 @@
<string name="on">Ŝaltita</string> <string name="on">Ŝaltita</string>
<string name="metadata_tags">Etikedoj</string> <string name="metadata_tags">Etikedoj</string>
<string name="download_has_started">Elŝutado komenciĝis</string> <string name="download_has_started">Elŝutado komenciĝis</string>
<string name="service_provides_reason">%s donas tiun kialon:</string>
<string name="georestricted_content">Tiu enaĵo ne disponeblas en via lando.</string> <string name="georestricted_content">Tiu enaĵo ne disponeblas en via lando.</string>
<string name="recent">Freŝaj</string> <string name="recent">Freŝaj</string>
<string name="video_detail_by">De %s</string> <string name="video_detail_by">De %s</string>

View file

@ -611,7 +611,6 @@
<string name="description_select_disable">Deshabilitar la selección de texto de la descripción</string> <string name="description_select_disable">Deshabilitar la selección de texto de la descripción</string>
<string name="description_select_enable">Habilitar la selección de texto de la descripción</string> <string name="description_select_enable">Habilitar la selección de texto de la descripción</string>
<string name="description_select_note">Ahora puede seleccionar el texto dentro de la descripción. Note que la página puede parpadear y los links no serán cliqueables mientras está en el modo de selección.</string> <string name="description_select_note">Ahora puede seleccionar el texto dentro de la descripción. Note que la página puede parpadear y los links no serán cliqueables mientras está en el modo de selección.</string>
<string name="service_provides_reason">%s da esta razón:</string>
<string name="feed_load_error_account_info">No fue posible cargar el feed por \'%s\'.</string> <string name="feed_load_error_account_info">No fue posible cargar el feed por \'%s\'.</string>
<string name="account_terminated">Cuenta cancelada</string> <string name="account_terminated">Cuenta cancelada</string>
<string name="feed_load_error_fast_unknown">El modo de muro rápido no arroja más información sobre esto.</string> <string name="feed_load_error_fast_unknown">El modo de muro rápido no arroja más información sobre esto.</string>

View file

@ -562,7 +562,6 @@
<string name="show_thumbnail_title">Näita pisipilte</string> <string name="show_thumbnail_title">Näita pisipilte</string>
<string name="show_thumbnail_summary">Kasuta pisipilti nii lukustusvaate kui teavituste taustana</string> <string name="show_thumbnail_summary">Kasuta pisipilti nii lukustusvaate kui teavituste taustana</string>
<string name="account_terminated">Kasutajakonto on suletud</string> <string name="account_terminated">Kasutajakonto on suletud</string>
<string name="service_provides_reason">%s toob põhjuseks:</string>
<string name="description_select_enable">Võimalda valida kirjelduse teksti</string> <string name="description_select_enable">Võimalda valida kirjelduse teksti</string>
<string name="description_select_disable">Ära võimalda valida kirjelduse teksti</string> <string name="description_select_disable">Ära võimalda valida kirjelduse teksti</string>
<string name="metadata_category">Kategooria</string> <string name="metadata_category">Kategooria</string>

View file

@ -615,7 +615,6 @@
<string name="downloads_storage_ask_summary_no_saf_notice">Non gorde galdetuko zaizu deskarga bakoitzean</string> <string name="downloads_storage_ask_summary_no_saf_notice">Non gorde galdetuko zaizu deskarga bakoitzean</string>
<string name="no_dir_yet">Ez da deskargatzeko karpetarik ezarri oraindik, aukeratu lehenetsitako deskargatzeko karpeta orain</string> <string name="no_dir_yet">Ez da deskargatzeko karpetarik ezarri oraindik, aukeratu lehenetsitako deskargatzeko karpeta orain</string>
<string name="metadata_privacy">Pribatutasuna</string> <string name="metadata_privacy">Pribatutasuna</string>
<string name="service_provides_reason">%s arrazoi hau ematen du:</string>
<string name="account_terminated">Kontua ezabatu da</string> <string name="account_terminated">Kontua ezabatu da</string>
<string name="feed_load_error_fast_unknown">Jario azkarrak ez du honi buruz informazio gehiagorik ematen.</string> <string name="feed_load_error_fast_unknown">Jario azkarrak ez du honi buruz informazio gehiagorik ematen.</string>
<string name="metadata_age_limit">Adin muga</string> <string name="metadata_age_limit">Adin muga</string>

View file

@ -625,7 +625,6 @@
\nنیوپایپ قادر به بار کردن این خوراک در آینده نیست. \nنیوپایپ قادر به بار کردن این خوراک در آینده نیست.
\nمیخواهید اشتراک این کانال را لغو کنید؟</string> \nمیخواهید اشتراک این کانال را لغو کنید؟</string>
<string name="feed_load_error_fast_unknown">حالت خوراک سریع، اطَلاعات بیش‌تری در این باره نمی‌دهد.</string> <string name="feed_load_error_fast_unknown">حالت خوراک سریع، اطَلاعات بیش‌تری در این باره نمی‌دهد.</string>
<string name="service_provides_reason">%s این دلیل را آورد:</string>
<string name="seekbar_preview_thumbnail_title">پیش‌نمایش بندانگشتی نوار جویش</string> <string name="seekbar_preview_thumbnail_title">پیش‌نمایش بندانگشتی نوار جویش</string>
<string name="detail_heart_img_view_description">قلب‌شده به دست ایجادگر</string> <string name="detail_heart_img_view_description">قلب‌شده به دست ایجادگر</string>
<string name="local_search_suggestions">پیشنهادهای جست‌وجوی محلّی</string> <string name="local_search_suggestions">پیشنهادهای جست‌وجوی محلّی</string>

View file

@ -592,7 +592,6 @@
<string name="night_theme_title">Yöteema</string> <string name="night_theme_title">Yöteema</string>
<string name="description_select_disable">Poista käytöstä tekstinvalinta kuvauskentän sisältä</string> <string name="description_select_disable">Poista käytöstä tekstinvalinta kuvauskentän sisältä</string>
<string name="description_select_note">Voit nyt valita tekstin kuvauskentän sisältä. Huomioithan, että valintatilan aikana sivu voi vilkkua ja linkit eivät ehkä ole klikattavia.</string> <string name="description_select_note">Voit nyt valita tekstin kuvauskentän sisältä. Huomioithan, että valintatilan aikana sivu voi vilkkua ja linkit eivät ehkä ole klikattavia.</string>
<string name="service_provides_reason">%s tuo tämän syyn:</string>
<string name="seekbar_preview_thumbnail_title">Säätövivun kuvakkeen esikatselu</string> <string name="seekbar_preview_thumbnail_title">Säätövivun kuvakkeen esikatselu</string>
<string name="disable_media_tunneling_summary">Poista median tunnelointi käytöstä, jos havaitset mustan näyttöruudun tai änkytystä videon toistossa.</string> <string name="disable_media_tunneling_summary">Poista median tunnelointi käytöstä, jos havaitset mustan näyttöruudun tai änkytystä videon toistossa.</string>
<string name="disable_media_tunneling_title">Poista median tunnelointi käytöstä</string> <string name="disable_media_tunneling_title">Poista median tunnelointi käytöstä</string>

View file

@ -620,7 +620,6 @@
<string name="metadata_tags">Étiquettes</string> <string name="metadata_tags">Étiquettes</string>
<string name="metadata_category">Catégorie</string> <string name="metadata_category">Catégorie</string>
<string name="description_select_note">Vous pouvez maintenant sélectionner du texte à lintérieur de la description. Notez que la page peut scintiller et que les liens peuvent ne pas être cliquables en mode sélection.</string> <string name="description_select_note">Vous pouvez maintenant sélectionner du texte à lintérieur de la description. Notez que la page peut scintiller et que les liens peuvent ne pas être cliquables en mode sélection.</string>
<string name="service_provides_reason">%s indique le motif :</string>
<string name="no_dir_yet">Aucun dossier de téléchargement nest défini pour le moment, sélectionnez le dossier de téléchargement par défaut</string> <string name="no_dir_yet">Aucun dossier de téléchargement nest défini pour le moment, sélectionnez le dossier de téléchargement par défaut</string>
<string name="open_website_license">Ouvrir le site web</string> <string name="open_website_license">Ouvrir le site web</string>
<string name="account_terminated">Compte résilié</string> <string name="account_terminated">Compte résilié</string>

View file

@ -554,7 +554,6 @@
<string name="description_select_note">Agora pode seleccionar o texto na descrición. Teña en conta que a páxina pode cintilar e as ligazóns poden non ser clicábeis no modo selección.</string> <string name="description_select_note">Agora pode seleccionar o texto na descrición. Teña en conta que a páxina pode cintilar e as ligazóns poden non ser clicábeis no modo selección.</string>
<string name="auto_device_theme_title">Automático (Tema do dispositivo)</string> <string name="auto_device_theme_title">Automático (Tema do dispositivo)</string>
<string name="radio">Radio</string> <string name="radio">Radio</string>
<string name="service_provides_reason">%s dá este motivo:</string>
<string name="georestricted_content">Este contido non está dispoñíbel no seu país.</string> <string name="georestricted_content">Este contido non está dispoñíbel no seu país.</string>
<string name="chapters">Capítulos</string> <string name="chapters">Capítulos</string>
<string name="recent">Recentes</string> <string name="recent">Recentes</string>

View file

@ -632,7 +632,6 @@
\nל־NewPipe לא תהיה אפשרות להוריד את ההזנה הזאת בעתיד. \nל־NewPipe לא תהיה אפשרות להוריד את ההזנה הזאת בעתיד.
\nלהסיר את המינוי מהערוץ הזה\?</string> \nלהסיר את המינוי מהערוץ הזה\?</string>
<string name="open_website_license">פתיחת האתר</string> <string name="open_website_license">פתיחת האתר</string>
<string name="service_provides_reason">%s מספק את הסיבה הבאה:</string>
<string name="account_terminated">החשבון הושמד</string> <string name="account_terminated">החשבון הושמד</string>
<string name="feed_load_error_fast_unknown">מצב ההזנה המהירה לא מספק מידע נוסף על כך.</string> <string name="feed_load_error_fast_unknown">מצב ההזנה המהירה לא מספק מידע נוסף על כך.</string>
<string name="feed_load_error_account_info">לא ניתן לטעון את ההזנה עבור %s.</string> <string name="feed_load_error_account_info">לא ניתן לטעון את ההזנה עבור %s.</string>

View file

@ -654,7 +654,6 @@
<string name="disable_media_tunneling_title">मीडिया टनलिंग अक्षम करें</string> <string name="disable_media_tunneling_title">मीडिया टनलिंग अक्षम करें</string>
<string name="show_crash_the_player_title">\"क्रैश द प्लेयर\" दिखाएं</string> <string name="show_crash_the_player_title">\"क्रैश द प्लेयर\" दिखाएं</string>
<string name="feed_subscription_not_loaded_count">लोड नहीं हुआ: %d</string> <string name="feed_subscription_not_loaded_count">लोड नहीं हुआ: %d</string>
<string name="service_provides_reason">%s इसका कारण प्रदान करता है:</string>
<string name="metadata_tags">टैग</string> <string name="metadata_tags">टैग</string>
<string name="metadata_licence">लाइसेंस</string> <string name="metadata_licence">लाइसेंस</string>
<string name="faq_description">यदि आपको ऐप का उपयोग करने में परेशानी हो रही है, तो सामान्य प्रश्नों के इन उत्तरों को देखना सुनिश्चित करें!</string> <string name="faq_description">यदि आपको ऐप का उपयोग करने में परेशानी हो रही है, तो सामान्य प्रश्नों के इन उत्तरों को देखना सुनिश्चित करें!</string>

View file

@ -639,7 +639,6 @@
<string name="metadata_privacy_internal">Interno</string> <string name="metadata_privacy_internal">Interno</string>
<string name="metadata_privacy">Privatnost</string> <string name="metadata_privacy">Privatnost</string>
<string name="description_select_note">Sada možeš odabrati tekst u opisu. Napomena: stranica će možda treperiti i možda nećeš moći kliknuti poveznice u načinu rada za odabir teksta.</string> <string name="description_select_note">Sada možeš odabrati tekst u opisu. Napomena: stranica će možda treperiti i možda nećeš moći kliknuti poveznice u načinu rada za odabir teksta.</string>
<string name="service_provides_reason">%s pruža ovaj razlog:</string>
<string name="processing_may_take_a_moment">Obrada u tijeku … Može malo potrajati</string> <string name="processing_may_take_a_moment">Obrada u tijeku … Može malo potrajati</string>
<string name="main_page_content_swipe_remove">Za ukljanjanje stavki povuci ih</string> <string name="main_page_content_swipe_remove">Za ukljanjanje stavki povuci ih</string>
<plurals name="download_finished_notification"> <plurals name="download_finished_notification">

View file

@ -537,7 +537,6 @@
<string name="related_items_tab_description">Kapcsolódó elemek</string> <string name="related_items_tab_description">Kapcsolódó elemek</string>
<string name="error_report_open_github_notice">Ellenőrizze, hogy létezik-e már olyan jegy, amely az összeomlásával foglalkozik. Ha duplikált jegyet ad fel, akkor olyan időt vesz el tőlünk, amelyet a hiba javítására tudnánk fordítani.</string> <string name="error_report_open_github_notice">Ellenőrizze, hogy létezik-e már olyan jegy, amely az összeomlásával foglalkozik. Ha duplikált jegyet ad fel, akkor olyan időt vesz el tőlünk, amelyet a hiba javítására tudnánk fordítani.</string>
<string name="minimize_on_exit_title">Minimalizálás alkalmazásváltáskor</string> <string name="minimize_on_exit_title">Minimalizálás alkalmazásváltáskor</string>
<string name="service_provides_reason">A(z) %s ezt az okot adta meg:</string>
<string name="local_search_suggestions">Helyi keresési javaslatok</string> <string name="local_search_suggestions">Helyi keresési javaslatok</string>
<string name="remote_search_suggestions">Távoli keresési javaslatok</string> <string name="remote_search_suggestions">Távoli keresési javaslatok</string>
<string name="start_main_player_fullscreen_title">A fő lejátszó teljes képernyős indítása</string> <string name="start_main_player_fullscreen_title">A fő lejátszó teljes képernyős indítása</string>

View file

@ -599,7 +599,6 @@
<string name="description_select_enable">Aktifkan dapat memilih teks pada deskripsi</string> <string name="description_select_enable">Aktifkan dapat memilih teks pada deskripsi</string>
<string name="description_select_note">Anda sekarang dapat memilih teks di dalam deskripsi. Perhatikan bahwa halaman mungkin berkedip dan tautan tidak dapat diklik saat dalam mode pemilihan.</string> <string name="description_select_note">Anda sekarang dapat memilih teks di dalam deskripsi. Perhatikan bahwa halaman mungkin berkedip dan tautan tidak dapat diklik saat dalam mode pemilihan.</string>
<string name="open_website_license">Buka situs web</string> <string name="open_website_license">Buka situs web</string>
<string name="service_provides_reason">%s menyediakan alasan ini:</string>
<string name="account_terminated">Akun dinonaktifkan</string> <string name="account_terminated">Akun dinonaktifkan</string>
<string name="feed_load_error_fast_unknown">Mode langganan cepat tidak menyediakan lebih banyak info tentang ini.</string> <string name="feed_load_error_fast_unknown">Mode langganan cepat tidak menyediakan lebih banyak info tentang ini.</string>
<string name="feed_load_error_terminated">Akun kreator telah dinonaktifkan. <string name="feed_load_error_terminated">Akun kreator telah dinonaktifkan.

View file

@ -573,7 +573,6 @@
<string name="no_appropriate_file_manager_message_android_10">Enginn viðeigandi skráarstjóri fannst fyrir þessa aðgerð. <string name="no_appropriate_file_manager_message_android_10">Enginn viðeigandi skráarstjóri fannst fyrir þessa aðgerð.
\nVinsamlegast settu upp skráarstjóra sem styður Geymsluaðgangsramma (SAF)</string> \nVinsamlegast settu upp skráarstjóra sem styður Geymsluaðgangsramma (SAF)</string>
<string name="georestricted_content">Þetta efni er ekki fáanlegt í þínu landi.</string> <string name="georestricted_content">Þetta efni er ekki fáanlegt í þínu landi.</string>
<string name="service_provides_reason">%s gefur þessa ástæðu:</string>
<string name="paid_content">Þetta efni er aðeins í boði fyrir notendur sem hafa greitt — það er ekki hægt að streyma því eða sækja með NewPipe.</string> <string name="paid_content">Þetta efni er aðeins í boði fyrir notendur sem hafa greitt — það er ekki hægt að streyma því eða sækja með NewPipe.</string>
<string name="auto_device_theme_title">Sjálfvirk (þema tækis)</string> <string name="auto_device_theme_title">Sjálfvirk (þema tækis)</string>
<string name="night_theme_summary">Veldu uppáhalds næturþemu þína — %s</string> <string name="night_theme_summary">Veldu uppáhalds næturþemu þína — %s</string>

View file

@ -619,7 +619,6 @@
<string name="description_select_enable">Attiva la selezione del testo nella descrizione</string> <string name="description_select_enable">Attiva la selezione del testo nella descrizione</string>
<string name="description_select_note">È possibile selezionare il testo all\'interno della descrizione. In modalità selezione la pagina potrebbe sfarfallare e i collegamenti potrebbero non essere cliccabili.</string> <string name="description_select_note">È possibile selezionare il testo all\'interno della descrizione. In modalità selezione la pagina potrebbe sfarfallare e i collegamenti potrebbero non essere cliccabili.</string>
<string name="open_website_license">Visita il sito</string> <string name="open_website_license">Visita il sito</string>
<string name="service_provides_reason">%s fornisce questa motivazione:</string>
<string name="account_terminated">Account chiuso</string> <string name="account_terminated">Account chiuso</string>
<string name="feed_load_error_fast_unknown">Il recupero veloce dei feed non fornisce ulteriori informazioni al riguardo.</string> <string name="feed_load_error_fast_unknown">Il recupero veloce dei feed non fornisce ulteriori informazioni al riguardo.</string>
<string name="feed_load_error_terminated">L\'account dell\'autore è stato chiuso. <string name="feed_load_error_terminated">L\'account dell\'autore è stato chiuso.

View file

@ -612,7 +612,6 @@
<string name="off">オフ</string> <string name="off">オフ</string>
<string name="on">オン</string> <string name="on">オン</string>
<string name="tablet_mode_title">タブレットモード</string> <string name="tablet_mode_title">タブレットモード</string>
<string name="service_provides_reason">%s がこの理由を提示:</string>
<string name="dont_show">表示しない</string> <string name="dont_show">表示しない</string>
<string name="low_quality_smaller">低品質 (小)</string> <string name="low_quality_smaller">低品質 (小)</string>
<string name="high_quality_larger">高品質 (大)</string> <string name="high_quality_larger">高品質 (大)</string>

View file

@ -544,7 +544,6 @@
<string name="georestricted_content">ეს ხელმიუწვდომელია თქვენი ქვეყნიდან.</string> <string name="georestricted_content">ეს ხელმიუწვდომელია თქვენი ქვეყნიდან.</string>
<string name="private_content">ეს მასალა პირადულია, ამიტომაც NewPipe-ს მისი არც მთლიანად და არც თანდათანობით ჩამოწერა არ შეუძლია.</string> <string name="private_content">ეს მასალა პირადულია, ამიტომაც NewPipe-ს მისი არც მთლიანად და არც თანდათანობით ჩამოწერა არ შეუძლია.</string>
<string name="account_terminated">ანგარიში შეწყვეტილია</string> <string name="account_terminated">ანგარიში შეწყვეტილია</string>
<string name="service_provides_reason">%s იძლევა ამ მიზეზს:</string>
<string name="paid_content">ეს მასალა ხელმისაწვდომია მხოლოდ გადამხდელებისთვის, ამიტომაც NewPipe-ს მისი არც მთლიანად და არც თანდათანობით ჩამოწერა არ შეუძლია.</string> <string name="paid_content">ეს მასალა ხელმისაწვდომია მხოლოდ გადამხდელებისთვის, ამიტომაც NewPipe-ს მისი არც მთლიანად და არც თანდათანობით ჩამოწერა არ შეუძლია.</string>
<string name="featured">გამორჩეული</string> <string name="featured">გამორჩეული</string>
<string name="radio">რადიო</string> <string name="radio">რადიო</string>

View file

@ -643,7 +643,6 @@
<string name="chapters">챕터</string> <string name="chapters">챕터</string>
<string name="recent">최근</string> <string name="recent">최근</string>
<string name="account_terminated">계정이 해지됨</string> <string name="account_terminated">계정이 해지됨</string>
<string name="service_provides_reason">%s은(는) 다음과 같은 이유를 제공:</string>
<string name="soundcloud_go_plus_content">이것은 적어도 귀하의 국가에서 SoundCloud Go+ 트랙이므로 NewPipe에서 스트리밍하거나 다운로드할 수 없습니다.</string> <string name="soundcloud_go_plus_content">이것은 적어도 귀하의 국가에서 SoundCloud Go+ 트랙이므로 NewPipe에서 스트리밍하거나 다운로드할 수 없습니다.</string>
<string name="auto_device_theme_title">자동 (장치 테마)</string> <string name="auto_device_theme_title">자동 (장치 테마)</string>
<string name="detail_pinned_comment_view_description">고정된 댓글</string> <string name="detail_pinned_comment_view_description">고정된 댓글</string>

View file

@ -623,7 +623,6 @@
<string name="description_select_enable">Įgalinti teksto pasirinkimą apraše</string> <string name="description_select_enable">Įgalinti teksto pasirinkimą apraše</string>
<string name="description_select_disable">Neleisti pasirinkti teksto apraše</string> <string name="description_select_disable">Neleisti pasirinkti teksto apraše</string>
<string name="description_select_note">Dabar apraše galite pasirinkti tekstą aprašyme. Atminkite, kad puslapis gali mirgėti, o nuorodos gali būti nespustelėjamos, kai veikia pasirinkimo režimas.</string> <string name="description_select_note">Dabar apraše galite pasirinkti tekstą aprašyme. Atminkite, kad puslapis gali mirgėti, o nuorodos gali būti nespustelėjamos, kai veikia pasirinkimo režimas.</string>
<string name="service_provides_reason">%s pateikia šią priežastį:</string>
<string name="account_terminated">Paskyra anuliuota</string> <string name="account_terminated">Paskyra anuliuota</string>
<string name="feed_load_error_fast_unknown">Greito srauto režimas nesuteikia daugiau informacijos apie tai.</string> <string name="feed_load_error_fast_unknown">Greito srauto režimas nesuteikia daugiau informacijos apie tai.</string>
<string name="feed_load_error_terminated">Autoriaus paskyra anuliuota. <string name="feed_load_error_terminated">Autoriaus paskyra anuliuota.

View file

@ -629,7 +629,6 @@
\nNewPipe turpmāk nevarēs ielādēt šo plūsmu. \nNewPipe turpmāk nevarēs ielādēt šo plūsmu.
\nVai vēlaties atteikties no šī kanāla abonēšanas\?</string> \nVai vēlaties atteikties no šī kanāla abonēšanas\?</string>
<string name="feed_load_error_fast_unknown">Ātrās straumes režīms nesniedz vairāk informācijas par šo.</string> <string name="feed_load_error_fast_unknown">Ātrās straumes režīms nesniedz vairāk informācijas par šo.</string>
<string name="service_provides_reason">%s dod šādu pamatojumu:</string>
<string name="description_select_disable">Izslēgt teksta atlasīšanu video aprakstā</string> <string name="description_select_disable">Izslēgt teksta atlasīšanu video aprakstā</string>
<string name="metadata_privacy_internal">Iekšeji</string> <string name="metadata_privacy_internal">Iekšeji</string>
<string name="detail_heart_img_view_description">Autors piekrīt</string> <string name="detail_heart_img_view_description">Autors piekrīt</string>

View file

@ -431,7 +431,6 @@
<string name="feed_load_error_account_info">Неуспешно вчитување на новинска лента за „%s“.</string> <string name="feed_load_error_account_info">Неуспешно вчитување на новинска лента за „%s“.</string>
<string name="feed_show_hide_streams">Прикажи / скриј стримови</string> <string name="feed_show_hide_streams">Прикажи / скриј стримови</string>
<string name="private_content">Оваа содржина е приватна, така што не може да биде емитувана или преземена од страна на NewPipe.</string> <string name="private_content">Оваа содржина е приватна, така што не може да биде емитувана или преземена од страна на NewPipe.</string>
<string name="service_provides_reason">%s ја посочува следната причина:</string>
<string name="featured">Истакнато</string> <string name="featured">Истакнато</string>
<string name="radio">Радио</string> <string name="radio">Радио</string>
<string name="auto_device_theme_title">Автоматски (режим на уредот)</string> <string name="auto_device_theme_title">Автоматски (режим на уредот)</string>

View file

@ -612,7 +612,6 @@
<string name="metadata_tags">ടാഗുക്കൾ</string> <string name="metadata_tags">ടാഗുക്കൾ</string>
<string name="metadata_category">വിഭാഗം</string> <string name="metadata_category">വിഭാഗം</string>
<string name="description_select_note">താക്കൾക് ഇപ്പോൾ ഡിസ്ക്രിപ്ഷൻ ബോക്സിലെ ടെക്സ്റ്റ്‌ തിരഞ്ഞെടുക്കാൻ സാധിക്കും. ശ്രെദ്ധിക്കുക സെലെക്ഷൻ മോഡിൽ പേജ് ചിലപ്പോൾ മിന്നുകയും ലിങ്കുകൾ ക്ലിക്ക് ചെയ്യാനാകാതെയും വന്നേക്കാം.</string> <string name="description_select_note">താക്കൾക് ഇപ്പോൾ ഡിസ്ക്രിപ്ഷൻ ബോക്സിലെ ടെക്സ്റ്റ്‌ തിരഞ്ഞെടുക്കാൻ സാധിക്കും. ശ്രെദ്ധിക്കുക സെലെക്ഷൻ മോഡിൽ പേജ് ചിലപ്പോൾ മിന്നുകയും ലിങ്കുകൾ ക്ലിക്ക് ചെയ്യാനാകാതെയും വന്നേക്കാം.</string>
<string name="service_provides_reason">ഇതിന്റെ കാരണം %s നൽകും:</string>
<string name="account_terminated">അക്കൗണ്ട് ഇല്ലാതായിരിക്കുന്നു</string> <string name="account_terminated">അക്കൗണ്ട് ഇല്ലാതായിരിക്കുന്നു</string>
<string name="feed_load_error_fast_unknown">ഫാസ്റ്റ് ഫീഡ് മോഡ് കൂടുതൽ വിവരങ്ങൾ നൽകില്ല.</string> <string name="feed_load_error_fast_unknown">ഫാസ്റ്റ് ഫീഡ് മോഡ് കൂടുതൽ വിവരങ്ങൾ നൽകില്ല.</string>
<string name="feed_load_error_terminated">സൃഷ്ടാവിന്റെ അക്കൗണ്ട് ഇല്ലാതായിരിക്കുന്നു. <string name="feed_load_error_terminated">സൃഷ്ടാവിന്റെ അക്കൗണ്ട് ഇല്ലാതായിരിക്കുന്നു.

View file

@ -600,7 +600,6 @@
\nØnsker du å oppheve ditt abonnement på denne kanalen\?</string> \nØnsker du å oppheve ditt abonnement på denne kanalen\?</string>
<string name="description_select_disable">Skru av merking av tekst i beskrivelsen</string> <string name="description_select_disable">Skru av merking av tekst i beskrivelsen</string>
<string name="description_select_enable">Skru på merking av tekst i beskrivelsen</string> <string name="description_select_enable">Skru på merking av tekst i beskrivelsen</string>
<string name="service_provides_reason">%s oppgav denne grunnen:</string>
<string name="account_terminated">Konto terminert</string> <string name="account_terminated">Konto terminert</string>
<string name="feed_load_error_account_info">Kunne ikke laste inn informasjonskanal for «%s».</string> <string name="feed_load_error_account_info">Kunne ikke laste inn informasjonskanal for «%s».</string>
<string name="feed_load_error">Kunne ikke laste inn informasjonskanal</string> <string name="feed_load_error">Kunne ikke laste inn informasjonskanal</string>

View file

@ -612,7 +612,6 @@
<string name="on">Aan</string> <string name="on">Aan</string>
<string name="tablet_mode_title">Tablet-modus</string> <string name="tablet_mode_title">Tablet-modus</string>
<string name="open_website_license">Website openen</string> <string name="open_website_license">Website openen</string>
<string name="service_provides_reason">%s geeft de volgende reden:</string>
<string name="account_terminated">Account getermineerd</string> <string name="account_terminated">Account getermineerd</string>
<string name="feed_load_error_fast_unknown">De snelle feed mode levert hierover niet meer informatie.</string> <string name="feed_load_error_fast_unknown">De snelle feed mode levert hierover niet meer informatie.</string>
<string name="feed_load_error_terminated">De account van de auteur is getermineerd. <string name="feed_load_error_terminated">De account van de auteur is getermineerd.

View file

@ -625,7 +625,6 @@
<string name="no_appropriate_file_manager_message_android_10">ߞߐߕߐ߯ ߡߊߡߙߊߟߊ߲߫ ߛߌ߫ ߡߊ߫ ߛߐ߬ߘߐ߲߬ ߞߋߥߊߟߌ ߣߌ߲߬ ߞߊ߲ߡߊ߬. <string name="no_appropriate_file_manager_message_android_10">ߞߐߕߐ߯ ߡߊߡߙߊߟߊ߲߫ ߛߌ߫ ߡߊ߫ ߛߐ߬ߘߐ߲߬ ߞߋߥߊߟߌ ߣߌ߲߬ ߞߊ߲ߡߊ߬.
\nߘߌ߬ߢߍ߬ ߦߋ߫ ߞߐߕߐ߯ ߡߊߡߙߊߟߊ߲ ߘߏ߫ ߡߊߞߍ߫ ߡߍ߲ ߣߌ߫ ߡߙߊ߬ߘߐ߬ߦߊ ߟߊߛߐ߬ߘߐ߲ ߡߎ߬ߙߊ߲߬ߞߊ߲ߞߋ ߘߌ߫ ߓߍ߲߬</string> \nߘߌ߬ߢߍ߬ ߦߋ߫ ߞߐߕߐ߯ ߡߊߡߙߊߟߊ߲ ߘߏ߫ ߡߊߞߍ߫ ߡߍ߲ ߣߌ߫ ߡߙߊ߬ߘߐ߬ߦߊ ߟߊߛߐ߬ߘߐ߲ ߡߎ߬ߙߊ߲߬ߞߊ߲ߞߋ ߘߌ߫ ߓߍ߲߬</string>
<string name="youtube_music_premium_content">ߦߋߡߍ߲ߕߊ ߘߌ߫ ߡߊߛߐ߬ߘߐ߲߬ YouTube Music Premium ߛߌ߲߬ߝߏ߲ ߠߎ߬ ߟߋ߬ ߘߐߙߐ߲߫ ߓߟߏ߫߸ ߏ߬ ߘߐ߫ ߊ߬ ߕߍ߫ ߛߋ߫ ߘߐߛߊߙߌ߫ ߟߊ߫ ߥߟߊ߫ ߞߵߊ߬ ߟߊߖߌ߰ ߣߌߎߔߌߔ ߓߟߏ.</string> <string name="youtube_music_premium_content">ߦߋߡߍ߲ߕߊ ߘߌ߫ ߡߊߛߐ߬ߘߐ߲߬ YouTube Music Premium ߛߌ߲߬ߝߏ߲ ߠߎ߬ ߟߋ߬ ߘߐߙߐ߲߫ ߓߟߏ߫߸ ߏ߬ ߘߐ߫ ߊ߬ ߕߍ߫ ߛߋ߫ ߘߐߛߊߙߌ߫ ߟߊ߫ ߥߟߊ߫ ߞߵߊ߬ ߟߊߖߌ߰ ߣߌߎߔߌߔ ߓߟߏ.</string>
<string name="service_provides_reason">%s ߦߋ߫ ߞߎ߲߭ ߣߌ߲߬ ߠߋ߬ ߝߐ߫ ߟߊ߫:</string>
<string name="featured">ߛߊ߲ߞߊߥߟߌ</string> <string name="featured">ߛߊ߲ߞߊߥߟߌ</string>
<string name="radio">ߥߎߢߊ߲ߓߍ߲</string> <string name="radio">ߥߎߢߊ߲ߓߍ߲</string>
<string name="auto_device_theme_title">ߖߘߍ߬ߢߍ߫ (ߕߙߏߞߏ߫ ߛߊߛߊ)</string> <string name="auto_device_theme_title">ߖߘߍ߬ߢߍ߫ (ߕߙߏߞߏ߫ ߛߊߛߊ)</string>

View file

@ -485,7 +485,6 @@
<string name="feed_group_dialog_select_subscriptions">ସଦସ୍ୟତା ଚୟନ କରନ୍ତୁ</string> <string name="feed_group_dialog_select_subscriptions">ସଦସ୍ୟତା ଚୟନ କରନ୍ତୁ</string>
<string name="feed_group_dialog_empty_selection">କୌଣସି ସଦସ୍ୟତା ଚୟନ ହୋଇନାହିଁ</string> <string name="feed_group_dialog_empty_selection">କୌଣସି ସଦସ୍ୟତା ଚୟନ ହୋଇନାହିଁ</string>
<string name="feed_use_dedicated_fetch_method_enable_button">ଦ୍ରୁତ ମୋଡ୍ ସକ୍ଷମ କରନ୍ତୁ</string> <string name="feed_use_dedicated_fetch_method_enable_button">ଦ୍ରୁତ ମୋଡ୍ ସକ୍ଷମ କରନ୍ତୁ</string>
<string name="service_provides_reason">%s ଏହି କାରଣ ପ୍ରଦାନ କରେ:</string>
<string name="detail_sub_channel_thumbnail_view_description">ଚ୍ୟାନେଲର ଅବତାର ଥମ୍ୱନେଲ୍</string> <string name="detail_sub_channel_thumbnail_view_description">ଚ୍ୟାନେଲର ଅବତାର ଥମ୍ୱନେଲ୍</string>
<string name="featured">ବୈଶିଷ୍ଟ୍ୟ</string> <string name="featured">ବୈଶିଷ୍ଟ୍ୟ</string>
<string name="radio">ରେଡିଓ</string> <string name="radio">ରେଡିଓ</string>

View file

@ -455,7 +455,6 @@
<string name="radio">ਰੇਡੀਓ</string> <string name="radio">ਰੇਡੀਓ</string>
<string name="featured">ਫੀਚਰਡ</string> <string name="featured">ਫੀਚਰਡ</string>
<string name="paid_content">ਇਹ ਸਮੱਗਰੀ ਸਿਰਫ਼ ਉਹਨਾਂ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਉਪਲਬਧ ਹੈ ਜਿੰਨ੍ਹਾਂ ਨੇ ਇਸਦੇ ਲਈ ਕੀਮਤ ਦਿੱਤੀ ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</string> <string name="paid_content">ਇਹ ਸਮੱਗਰੀ ਸਿਰਫ਼ ਉਹਨਾਂ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਉਪਲਬਧ ਹੈ ਜਿੰਨ੍ਹਾਂ ਨੇ ਇਸਦੇ ਲਈ ਕੀਮਤ ਦਿੱਤੀ ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</string>
<string name="service_provides_reason">%s ਇਸਦਾ ਕਾਰਨ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ:</string>
<string name="account_terminated">ਖਾਤਾ ਬੰਦ ਕੀਤਾ ਗਿਆ</string> <string name="account_terminated">ਖਾਤਾ ਬੰਦ ਕੀਤਾ ਗਿਆ</string>
<string name="youtube_music_premium_content">ਇਹ ਵੀਡੀਓ ਸਿਰਫ਼ ਯੂਟਿਊਬ ਮਿਊਜ਼ਿਕ ਦੇ ਪ੍ਰੀਮੀਅਮ ਮੈਂਬਰਾਂ ਲਈ ਉਪਲਬਧ ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</string> <string name="youtube_music_premium_content">ਇਹ ਵੀਡੀਓ ਸਿਰਫ਼ ਯੂਟਿਊਬ ਮਿਊਜ਼ਿਕ ਦੇ ਪ੍ਰੀਮੀਅਮ ਮੈਂਬਰਾਂ ਲਈ ਉਪਲਬਧ ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</string>
<string name="private_content">ਇਹ ਸਮੱਗਰੀ ਨਿੱਜੀ (ਪ੍ਰਾਈਵੇਟ) ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</string> <string name="private_content">ਇਹ ਸਮੱਗਰੀ ਨਿੱਜੀ (ਪ੍ਰਾਈਵੇਟ) ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</string>

View file

@ -623,7 +623,6 @@
<string name="metadata_category">Kategoria</string> <string name="metadata_category">Kategoria</string>
<string name="open_website_license">Otwórz stronę</string> <string name="open_website_license">Otwórz stronę</string>
<string name="description_select_note">Teraz możesz zaznaczyć tekst wewnątrz opisu. Pamiętaj, że w trybie zaznaczania strona może migotać i linki nie będą klikalne.</string> <string name="description_select_note">Teraz możesz zaznaczyć tekst wewnątrz opisu. Pamiętaj, że w trybie zaznaczania strona może migotać i linki nie będą klikalne.</string>
<string name="service_provides_reason">%s podaje ten powód:</string>
<string name="account_terminated">Konto zamknięte</string> <string name="account_terminated">Konto zamknięte</string>
<string name="feed_load_error_fast_unknown">Tryb szybki dla ładowania kanału nie dostarcza więcej informacji na ten temat.</string> <string name="feed_load_error_fast_unknown">Tryb szybki dla ładowania kanału nie dostarcza więcej informacji na ten temat.</string>
<string name="feed_load_error_terminated">Konto autora zostało zawieszone. <string name="feed_load_error_terminated">Konto autora zostało zawieszone.

View file

@ -619,7 +619,6 @@
<string name="description_select_enable">Ativar seleção de texto na descrição</string> <string name="description_select_enable">Ativar seleção de texto na descrição</string>
<string name="description_select_note">Agora você pode selecionar o texto dentro da descrição. Note que a página pode piscar e os URL podem não ser clicáveis no modo de seleção.</string> <string name="description_select_note">Agora você pode selecionar o texto dentro da descrição. Note que a página pode piscar e os URL podem não ser clicáveis no modo de seleção.</string>
<string name="open_website_license">Abrir site</string> <string name="open_website_license">Abrir site</string>
<string name="service_provides_reason">%s fornece este motivo:</string>
<string name="account_terminated">Conta encerrada</string> <string name="account_terminated">Conta encerrada</string>
<string name="feed_load_error_fast_unknown">O modo feed rápido não fornece mais informações sobre isso.</string> <string name="feed_load_error_fast_unknown">O modo feed rápido não fornece mais informações sobre isso.</string>
<string name="feed_load_error_terminated">A conta do autor foi encerrada. <string name="feed_load_error_terminated">A conta do autor foi encerrada.

View file

@ -623,7 +623,6 @@
<string name="description_select_disable">Desativar seleção de texto na descrição</string> <string name="description_select_disable">Desativar seleção de texto na descrição</string>
<string name="description_select_enable">Ativar seleção de texto na descrição</string> <string name="description_select_enable">Ativar seleção de texto na descrição</string>
<string name="description_select_note">Agora pode selecionar o texto na descrição. Note que a página pode cintilar e as ligações podem não ser clicáveis enquanto estiver no modo de seleção.</string> <string name="description_select_note">Agora pode selecionar o texto na descrição. Note que a página pode cintilar e as ligações podem não ser clicáveis enquanto estiver no modo de seleção.</string>
<string name="service_provides_reason">%s fornece este motivo:</string>
<string name="account_terminated">Conta encerrada</string> <string name="account_terminated">Conta encerrada</string>
<string name="feed_load_error_fast_unknown">O modo de feed rápido não fornece mais informações sobre isto.</string> <string name="feed_load_error_fast_unknown">O modo de feed rápido não fornece mais informações sobre isto.</string>
<string name="feed_load_error_terminated">A conta do autor foi encerrada. <string name="feed_load_error_terminated">A conta do autor foi encerrada.

View file

@ -605,7 +605,6 @@
<string name="disable_media_tunneling_title">Desativar túnel multimédia</string> <string name="disable_media_tunneling_title">Desativar túnel multimédia</string>
<string name="downloads_storage_ask_summary_no_saf_notice">Sempre que descarregar um ficheiro, terá que indicar o local para o guardar</string> <string name="downloads_storage_ask_summary_no_saf_notice">Sempre que descarregar um ficheiro, terá que indicar o local para o guardar</string>
<string name="no_dir_yet">Ainda não definiu uma pasta para as descargas. Escolha agora a pasta a utilizar</string> <string name="no_dir_yet">Ainda não definiu uma pasta para as descargas. Escolha agora a pasta a utilizar</string>
<string name="service_provides_reason">%s fornece este motivo:</string>
<string name="account_terminated">Conta encerrada</string> <string name="account_terminated">Conta encerrada</string>
<string name="feed_load_error_fast_unknown">O modo de fonte rápida não fornece mais informações sobre isto.</string> <string name="feed_load_error_fast_unknown">O modo de fonte rápida não fornece mais informações sobre isto.</string>
<string name="feed_load_error_terminated">A conta do autor foi encerrada. <string name="feed_load_error_terminated">A conta do autor foi encerrada.

View file

@ -624,7 +624,6 @@
<string name="description_select_disable">Dezactivați selectarea textului în descriere</string> <string name="description_select_disable">Dezactivați selectarea textului în descriere</string>
<string name="description_select_enable">Activați selectarea textului în descriere</string> <string name="description_select_enable">Activați selectarea textului în descriere</string>
<string name="description_select_note">Acum puteți selecta text în interiorul descrierii. Rețineți că este posibil ca pagina să pâlpâie, iar linkurile să nu poată fi accesate în modul de selecție.</string> <string name="description_select_note">Acum puteți selecta text în interiorul descrierii. Rețineți că este posibil ca pagina să pâlpâie, iar linkurile să nu poată fi accesate în modul de selecție.</string>
<string name="service_provides_reason">%s oferă acest motiv:</string>
<string name="account_terminated">Contul a fost închis</string> <string name="account_terminated">Contul a fost închis</string>
<string name="feed_load_error_fast_unknown">Modul rapid nu furnizează mai multe informații în acest sens.</string> <string name="feed_load_error_fast_unknown">Modul rapid nu furnizează mai multe informații în acest sens.</string>
<string name="feed_load_error_terminated">Contul autorului a fost închis. <string name="feed_load_error_terminated">Contul autorului a fost închis.

View file

@ -633,7 +633,6 @@
<string name="feed_load_error_account_info">Не удалось загрузить подписку \'%s\'.</string> <string name="feed_load_error_account_info">Не удалось загрузить подписку \'%s\'.</string>
<string name="feed_load_error">Ошибка загрузки подписки</string> <string name="feed_load_error">Ошибка загрузки подписки</string>
<string name="open_website_license">Открыть веб-сайт</string> <string name="open_website_license">Открыть веб-сайт</string>
<string name="service_provides_reason">%s указывает следующую причину:</string>
<string name="account_terminated">Аккаунт отключён</string> <string name="account_terminated">Аккаунт отключён</string>
<string name="downloads_storage_use_saf_summary_api_29">Начиная с Android 10 поддерживается только «Storage Access Framework»</string> <string name="downloads_storage_use_saf_summary_api_29">Начиная с Android 10 поддерживается только «Storage Access Framework»</string>
<string name="downloads_storage_ask_summary_no_saf_notice">Спрашивать, куда сохранять каждую загрузку</string> <string name="downloads_storage_ask_summary_no_saf_notice">Спрашивать, куда сохранять каждую загрузку</string>

View file

@ -622,7 +622,6 @@
<string name="off">オフ</string> <string name="off">オフ</string>
<string name="on">オン</string> <string name="on">オン</string>
<string name="tablet_mode_title">タブレットモード</string> <string name="tablet_mode_title">タブレットモード</string>
<string name="service_provides_reason">%sやしがくぬりゆうていじ</string>
<string name="dont_show">ひょうじさん</string> <string name="dont_show">ひょうじさん</string>
<string name="low_quality_smaller">ていふぃんしち(しょう)</string> <string name="low_quality_smaller">ていふぃんしち(しょう)</string>
<string name="high_quality_larger">かんふぃんしち(だい)</string> <string name="high_quality_larger">かんふぃんしち(だい)</string>

View file

@ -330,7 +330,6 @@
<string name="chapters">ᱪᱮᱯᱴᱟᱨᱥ</string> <string name="chapters">ᱪᱮᱯᱴᱟᱨᱥ</string>
<string name="no_appropriate_file_manager_message_android_10">ᱞᱟᱹᱠᱛᱤ ᱠᱟᱱᱟ ᱟᱢ ᱢᱤᱫ ᱯᱷᱤᱞ ᱢᱟᱱᱮᱡᱚᱨ ᱤᱱᱥᱴᱚᱞ ᱢᱮ ᱟᱨᱵᱟᱝ ᱰᱟᱩᱱᱞᱚᱰ ᱥᱤᱴᱤᱝ ᱨᱮ ᱵᱚᱫᱚᱞ ᱦᱚᱪᱚ ᱞᱟᱹᱜᱤᱫ ᱯᱨᱚᱵᱷᱟᱣ ᱢᱮ\"</string> <string name="no_appropriate_file_manager_message_android_10">ᱞᱟᱹᱠᱛᱤ ᱠᱟᱱᱟ ᱟᱢ ᱢᱤᱫ ᱯᱷᱤᱞ ᱢᱟᱱᱮᱡᱚᱨ ᱤᱱᱥᱴᱚᱞ ᱢᱮ ᱟᱨᱵᱟᱝ ᱰᱟᱩᱱᱞᱚᱰ ᱥᱤᱴᱤᱝ ᱨᱮ ᱵᱚᱫᱚᱞ ᱦᱚᱪᱚ ᱞᱟᱹᱜᱤᱫ ᱯᱨᱚᱵᱷᱟᱣ ᱢᱮ\"</string>
<string name="youtube_music_premium_content">ᱱᱚᱶᱟ ᱵᱷᱤᱰᱤᱭᱳ ᱫᱚ ᱭᱩᱴᱭᱩᱵᱽ ᱢᱤᱣᱡᱤᱠ ᱯᱨᱤᱢᱤᱭᱟᱢ ᱥᱮᱞᱮᱫᱤᱭᱟᱹ ᱠᱚ ᱞᱟᱹᱜᱤᱫ ᱜᱮ ᱧᱟᱢᱚᱜᱼᱟ, ᱚᱱᱟᱛᱮ ᱱᱚᱶᱟ ᱫᱚ ᱱᱤᱭᱩ ᱯᱟᱭᱤᱯ ᱦᱚᱛᱮᱛᱮ ᱵᱟᱝ ᱥᱴᱨᱤᱢ ᱟᱨ ᱵᱟᱝ ᱰᱟᱩᱱᱞᱳᱰ ᱦᱩᱭ ᱫᱟᱲᱮᱭᱟᱜᱼᱟ ᱾</string> <string name="youtube_music_premium_content">ᱱᱚᱶᱟ ᱵᱷᱤᱰᱤᱭᱳ ᱫᱚ ᱭᱩᱴᱭᱩᱵᱽ ᱢᱤᱣᱡᱤᱠ ᱯᱨᱤᱢᱤᱭᱟᱢ ᱥᱮᱞᱮᱫᱤᱭᱟᱹ ᱠᱚ ᱞᱟᱹᱜᱤᱫ ᱜᱮ ᱧᱟᱢᱚᱜᱼᱟ, ᱚᱱᱟᱛᱮ ᱱᱚᱶᱟ ᱫᱚ ᱱᱤᱭᱩ ᱯᱟᱭᱤᱯ ᱦᱚᱛᱮᱛᱮ ᱵᱟᱝ ᱥᱴᱨᱤᱢ ᱟᱨ ᱵᱟᱝ ᱰᱟᱩᱱᱞᱳᱰ ᱦᱩᱭ ᱫᱟᱲᱮᱭᱟᱜᱼᱟ ᱾</string>
<string name="service_provides_reason">%s ᱫᱚ ᱱᱚᱶᱟ ᱞᱟᱹᱠᱛᱤ ᱠᱟᱱᱟ:</string>
<string name="auto_device_theme_title">ᱚᱴᱚᱢᱟᱴᱤᱠ (ᱰᱤᱵᱟᱤᱥ ᱛᱷᱮᱢ)</string> <string name="auto_device_theme_title">ᱚᱴᱚᱢᱟᱴᱤᱠ (ᱰᱤᱵᱟᱤᱥ ᱛᱷᱮᱢ)</string>
<string name="night_theme_summary">ᱟᱢᱟᱜ ᱯᱩᱭᱞᱩ ᱧᱤᱫᱟᱹ ᱛᱷᱤᱢ ᱵᱟᱪᱷᱟᱣ ᱢᱮ ⁇ %s</string> <string name="night_theme_summary">ᱟᱢᱟᱜ ᱯᱩᱭᱞᱩ ᱧᱤᱫᱟᱹ ᱛᱷᱤᱢ ᱵᱟᱪᱷᱟᱣ ᱢᱮ ⁇ %s</string>
<string name="select_night_theme_toast">ᱟᱢ ᱞᱟᱛᱟᱨ ᱨᱮ ᱟᱢᱟᱜ ᱧᱤᱫᱟᱹ ᱪᱮᱛᱟᱱ ᱵᱟᱪᱷᱟᱣ ᱫᱟᱲᱮᱭᱟᱜ ᱟ</string> <string name="select_night_theme_toast">ᱟᱢ ᱞᱟᱛᱟᱨ ᱨᱮ ᱟᱢᱟᱜ ᱧᱤᱫᱟᱹ ᱪᱮᱛᱟᱱ ᱵᱟᱪᱷᱟᱣ ᱫᱟᱲᱮᱭᱟᱜ ᱟ</string>

View file

@ -610,7 +610,6 @@
<string name="description_select_note">Como podes ischertare su testu in intro de sa descritzione. Ammenta·ti chi sa pàgina diat pòdere trèmere e sos ligàmenes si diant pòdere no abèrrere cando ses in modalidade de ischerta.</string> <string name="description_select_note">Como podes ischertare su testu in intro de sa descritzione. Ammenta·ti chi sa pàgina diat pòdere trèmere e sos ligàmenes si diant pòdere no abèrrere cando ses in modalidade de ischerta.</string>
<string name="downloads_storage_use_saf_summary_api_29">Incumintzende dae Android 10 petzi sa \'Storage Access Framework\' (Istrutura de Atzessu a s\'Archiviatzione) est suportada</string> <string name="downloads_storage_use_saf_summary_api_29">Incumintzende dae Android 10 petzi sa \'Storage Access Framework\' (Istrutura de Atzessu a s\'Archiviatzione) est suportada</string>
<string name="open_website_license">Aberi su situ web</string> <string name="open_website_license">Aberi su situ web</string>
<string name="service_provides_reason">%s frunit custa resone:</string>
<string name="account_terminated">Contu serradu</string> <string name="account_terminated">Contu serradu</string>
<string name="feed_load_error_fast_unknown">Su recùperu lestru de sos flussos non frunit àteras informatziones in subra de custu.</string> <string name="feed_load_error_fast_unknown">Su recùperu lestru de sos flussos non frunit àteras informatziones in subra de custu.</string>
<string name="feed_load_error_terminated">Su contu de s\'autore l\'ant serradu. <string name="feed_load_error_terminated">Su contu de s\'autore l\'ant serradu.

View file

@ -618,7 +618,6 @@
<string name="description_select_enable">Povolenie výberu textu v popise</string> <string name="description_select_enable">Povolenie výberu textu v popise</string>
<string name="description_select_note">Teraz môžete vybrať text vo vnútri popisu. Upozorňujeme, že stránka môže blikať a odkazy nemusia byť klikateľné, keď je v režime výberu.</string> <string name="description_select_note">Teraz môžete vybrať text vo vnútri popisu. Upozorňujeme, že stránka môže blikať a odkazy nemusia byť klikateľné, keď je v režime výberu.</string>
<string name="open_website_license">Otvoriť webstránku</string> <string name="open_website_license">Otvoriť webstránku</string>
<string name="service_provides_reason">%s uvádza tento dôvod:</string>
<string name="account_terminated">Účet bol zrušený</string> <string name="account_terminated">Účet bol zrušený</string>
<string name="feed_load_error_fast_unknown">Tento rýchly režim neposkytuje viac informácií.</string> <string name="feed_load_error_fast_unknown">Tento rýchly režim neposkytuje viac informácií.</string>
<string name="feed_load_error_terminated">Účet autora bol zrušený. <string name="feed_load_error_terminated">Účet autora bol zrušený.

View file

@ -608,7 +608,6 @@
<string name="description_select_disable">Xidh caalamadinta qoraalka</string> <string name="description_select_disable">Xidh caalamadinta qoraalka</string>
<string name="description_select_enable">Fur caalamadinta qoraalka</string> <string name="description_select_enable">Fur caalamadinta qoraalka</string>
<string name="description_select_note">Hadda waad dooran kartaa qoraalka ku dhexjira faahfaahinta. Ogow markaad caalamdinayso qoraalka boggu wuu boodboodi karaa tixraacyadana waxay noqon karaan kuwo aan lagu dhufan karin.</string> <string name="description_select_note">Hadda waad dooran kartaa qoraalka ku dhexjira faahfaahinta. Ogow markaad caalamdinayso qoraalka boggu wuu boodboodi karaa tixraacyadana waxay noqon karaan kuwo aan lagu dhufan karin.</string>
<string name="service_provides_reason">%s wuxuu sheegayaa sababtan:</string>
<string name="account_terminated">Akoonka waa lajoojiyay</string> <string name="account_terminated">Akoonka waa lajoojiyay</string>
<string name="feed_load_error_fast_unknown">Nidaamka dagdaga ah faahfaahin dheeraad ah uma hayo shaygan.</string> <string name="feed_load_error_fast_unknown">Nidaamka dagdaga ah faahfaahin dheeraad ah uma hayo shaygan.</string>
<string name="feed_load_error_terminated">Akoonka soosaaraha waa la joojiyay. <string name="feed_load_error_terminated">Akoonka soosaaraha waa la joojiyay.

View file

@ -598,7 +598,6 @@
<string name="night_theme_summary">Zgjidhni temën tuaj të preferuar të natës - %s</string> <string name="night_theme_summary">Zgjidhni temën tuaj të preferuar të natës - %s</string>
<string name="auto_device_theme_title">Automatike (tema e pajisjes)</string> <string name="auto_device_theme_title">Automatike (tema e pajisjes)</string>
<string name="radio">Radio</string> <string name="radio">Radio</string>
<string name="service_provides_reason">%s e jep këtë arsye:</string>
<string name="account_terminated">Llogaria është mbyllur</string> <string name="account_terminated">Llogaria është mbyllur</string>
<string name="private_content">Kjo përmbajtje është private, kështu që nuk mund të luhet apo shkarkohet nga NewPipe.</string> <string name="private_content">Kjo përmbajtje është private, kështu që nuk mund të luhet apo shkarkohet nga NewPipe.</string>
<string name="georestricted_content">Kjo përmbajtje nuk është e disponueshme në shtetin tuaj.</string> <string name="georestricted_content">Kjo përmbajtje nuk është e disponueshme në shtetin tuaj.</string>

View file

@ -619,7 +619,6 @@
<string name="description_select_enable">Омогући бирање текста унутар описа</string> <string name="description_select_enable">Омогући бирање текста унутар описа</string>
<string name="description_select_disable">Онемогући бирање текста унутар описа</string> <string name="description_select_disable">Онемогући бирање текста унутар описа</string>
<string name="description_select_note">Сада можете изабрати текст унутар описа. Имајте на уму да страница може треперети и да се на линкове можда неће моћи кликнути док сте у режиму избора.</string> <string name="description_select_note">Сада можете изабрати текст унутар описа. Имајте на уму да страница може треперети и да се на линкове можда неће моћи кликнути док сте у режиму избора.</string>
<string name="service_provides_reason">%s даје овај разлог:</string>
<string name="account_terminated">Налог укинут</string> <string name="account_terminated">Налог укинут</string>
<string name="feed_load_error_fast_unknown">Режим брзог фида не пружа више информација о овоме.</string> <string name="feed_load_error_fast_unknown">Режим брзог фида не пружа више информација о овоме.</string>
<string name="feed_load_error_terminated">Налог аутора је укинут. <string name="feed_load_error_terminated">Налог аутора је укинут.

View file

@ -586,7 +586,6 @@
<string name="download_has_started">Hämtningen har startat</string> <string name="download_has_started">Hämtningen har startat</string>
<string name="radio">Radio</string> <string name="radio">Radio</string>
<string name="paid_content">Detta innehåll är endast tillgängligt för användare som har betalat för det, så det kan inte strömmas eller hämtas av NewPipe.</string> <string name="paid_content">Detta innehåll är endast tillgängligt för användare som har betalat för det, så det kan inte strömmas eller hämtas av NewPipe.</string>
<string name="service_provides_reason">%s anger detta skäl:</string>
<string name="account_terminated">Kontot avslutat</string> <string name="account_terminated">Kontot avslutat</string>
<string name="youtube_music_premium_content">Denna video är endast tillgänglig för YouTube Music Premium-medlemmar, så den kan inte strömmas eller hämtas av NewPipe.</string> <string name="youtube_music_premium_content">Denna video är endast tillgänglig för YouTube Music Premium-medlemmar, så den kan inte strömmas eller hämtas av NewPipe.</string>
<string name="private_content">Detta innehåll är privat, så det kan inte strömmas eller hämtas av NewPipe.</string> <string name="private_content">Detta innehåll är privat, så det kan inte strömmas eller hämtas av NewPipe.</string>

View file

@ -428,7 +428,6 @@
<string name="enable_queue_limit">பதிவிறக்க வரிசையை கட்டுப்படுத்துங்கள்</string> <string name="enable_queue_limit">பதிவிறக்க வரிசையை கட்டுப்படுத்துங்கள்</string>
<string name="enable_queue_limit_desc">ஒரு பதிவிறக்கம் ஒரே நேரத்தில் இயங்கும்</string> <string name="enable_queue_limit_desc">ஒரு பதிவிறக்கம் ஒரே நேரத்தில் இயங்கும்</string>
<string name="no_app_to_open_intent">உங்கள் சாதனத்தில் எந்த பயன்பாடும் இதைத் திறக்க முடியாது</string> <string name="no_app_to_open_intent">உங்கள் சாதனத்தில் எந்த பயன்பாடும் இதைத் திறக்க முடியாது</string>
<string name="service_provides_reason">%s இந்த காரணத்தை வழங்குகிறது:</string>
<string name="metadata_subchannel_avatars">துணை சேனல் அவதாரங்கள்</string> <string name="metadata_subchannel_avatars">துணை சேனல் அவதாரங்கள்</string>
<string name="metadata_avatars">அவதாரங்கள்</string> <string name="metadata_avatars">அவதாரங்கள்</string>
<string name="progressive_load_interval_exoplayer_default">எக்சோப்ளேயர் இயல்புநிலை</string> <string name="progressive_load_interval_exoplayer_default">எக்சோப்ளேயர் இயல்புநிலை</string>

View file

@ -608,7 +608,6 @@
<string name="description_select_enable">ıklamadaki metni seçmeyi etkinleştir</string> <string name="description_select_enable">ıklamadaki metni seçmeyi etkinleştir</string>
<string name="description_select_note">Artık, açıklamadaki metni seçebilirsiniz. Seçim kipindeyken sayfanın titreyebileceğini ve bağlantıların tıklanamayacağını unutmayın.</string> <string name="description_select_note">Artık, açıklamadaki metni seçebilirsiniz. Seçim kipindeyken sayfanın titreyebileceğini ve bağlantıların tıklanamayacağını unutmayın.</string>
<string name="open_website_license">Web sitesini aç</string> <string name="open_website_license">Web sitesini aç</string>
<string name="service_provides_reason">%s şu nedeni sağlıyor:</string>
<string name="account_terminated">Hesap sonlandırıldı</string> <string name="account_terminated">Hesap sonlandırıldı</string>
<string name="feed_load_error_fast_unknown">Hızlı besleme kipi bununla ilgili daha çok bilgi sağlamıyor.</string> <string name="feed_load_error_fast_unknown">Hızlı besleme kipi bununla ilgili daha çok bilgi sağlamıyor.</string>
<string name="feed_load_error_terminated">Yazarın hesabı sonlandırılmış. <string name="feed_load_error_terminated">Yazarın hesabı sonlandırılmış.

View file

@ -624,7 +624,6 @@
<string name="description_select_disable">Заборонити виділення тексту в описі</string> <string name="description_select_disable">Заборонити виділення тексту в описі</string>
<string name="description_select_enable">Дозволити виділяти текст в описі</string> <string name="description_select_enable">Дозволити виділяти текст в описі</string>
<string name="description_select_note">Тепер можна виділяти текст в описі. Зауважте, що сторінка може мигати і посилання можуть не працювати в режимі виділення.</string> <string name="description_select_note">Тепер можна виділяти текст в описі. Зауважте, що сторінка може мигати і посилання можуть не працювати в режимі виділення.</string>
<string name="service_provides_reason">%s подає таку причину:</string>
<string name="feed_load_error_account_info">Неможливо завантажити стрічку для «%s».</string> <string name="feed_load_error_account_info">Неможливо завантажити стрічку для «%s».</string>
<string name="feed_load_error">Помилка завантаження стрічки</string> <string name="feed_load_error">Помилка завантаження стрічки</string>
<string name="feed_load_error_terminated">Обліковий запис автора припинено. <string name="feed_load_error_terminated">Обліковий запис автора припинено.

View file

@ -602,7 +602,6 @@
<string name="description_select_disable">Tắt chọn văn bản trong mô tả</string> <string name="description_select_disable">Tắt chọn văn bản trong mô tả</string>
<string name="description_select_enable">Bật chọn văn bản trong mô tả</string> <string name="description_select_enable">Bật chọn văn bản trong mô tả</string>
<string name="description_select_note">Bây giờ bạn có thể chọn văn bản trong mô tả. Lưu ý rằng trang có thể nhấp nháy và các liên kết có thể không nhấn vào được trong khi ở chế độ chọn.</string> <string name="description_select_note">Bây giờ bạn có thể chọn văn bản trong mô tả. Lưu ý rằng trang có thể nhấp nháy và các liên kết có thể không nhấn vào được trong khi ở chế độ chọn.</string>
<string name="service_provides_reason">%s cung cấp lý do này:</string>
<string name="account_terminated">Tài khoản đã bị chấm dứt</string> <string name="account_terminated">Tài khoản đã bị chấm dứt</string>
<string name="feed_load_error_fast_unknown">Chế độ nạp nhanh không cung cấp thêm thông tin về điều này.</string> <string name="feed_load_error_fast_unknown">Chế độ nạp nhanh không cung cấp thêm thông tin về điều này.</string>
<string name="feed_load_error_terminated">Tài khoản của tác giả đã bị chấm dứt. <string name="feed_load_error_terminated">Tài khoản của tác giả đã bị chấm dứt.

View file

@ -599,7 +599,6 @@
<string name="description_select_enable">启用简介中的文本选择功能</string> <string name="description_select_enable">启用简介中的文本选择功能</string>
<string name="description_select_note">你现在可以选择简介中的文本,注意,在选择模式下,页面可能会闪烁,链接可能无法点击。</string> <string name="description_select_note">你现在可以选择简介中的文本,注意,在选择模式下,页面可能会闪烁,链接可能无法点击。</string>
<string name="open_website_license">打开网站</string> <string name="open_website_license">打开网站</string>
<string name="service_provides_reason">%s 提供这个原因:</string>
<string name="account_terminated">账号被终止</string> <string name="account_terminated">账号被终止</string>
<string name="feed_load_error_fast_unknown">快速 Feed 模式不提供关于这个的更多信息。</string> <string name="feed_load_error_fast_unknown">快速 Feed 模式不提供关于这个的更多信息。</string>
<string name="feed_load_error_terminated">作者账号已被终止。 <string name="feed_load_error_terminated">作者账号已被终止。

View file

@ -486,7 +486,6 @@
<string name="content_not_supported">NewPipe 仲未支援到呢樣。 <string name="content_not_supported">NewPipe 仲未支援到呢樣。
\n \n
\n希望未來會喺日後嘅版本支援啦。</string> \n希望未來會喺日後嘅版本支援啦。</string>
<string name="service_provides_reason">%s 話理由如下:</string>
<string name="no_appropriate_file_manager_message">搵唔到合適嘅檔案總管進行呢個動作。 <string name="no_appropriate_file_manager_message">搵唔到合適嘅檔案總管進行呢個動作。
\n請安裝一個檔案管理程式又或者試下喺下載設定度停用「%s」</string> \n請安裝一個檔案管理程式又或者試下喺下載設定度停用「%s」</string>
<string name="no_appropriate_file_manager_message_android_10">搵唔到合適嘅檔案總管進行呢個動作。 <string name="no_appropriate_file_manager_message_android_10">搵唔到合適嘅檔案總管進行呢個動作。

View file

@ -599,7 +599,6 @@
<string name="description_select_enable">啟用選取描述中的文字</string> <string name="description_select_enable">啟用選取描述中的文字</string>
<string name="description_select_note">您現在可以選取描述中的文字了。請注意,在選取模式下,頁面可能會閃爍,連結也可能無法點擊。</string> <string name="description_select_note">您現在可以選取描述中的文字了。請注意,在選取模式下,頁面可能會閃爍,連結也可能無法點擊。</string>
<string name="open_website_license">開啟網站</string> <string name="open_website_license">開啟網站</string>
<string name="service_provides_reason">%s 提供了這個理由:</string>
<string name="account_terminated">帳號已終止</string> <string name="account_terminated">帳號已終止</string>
<string name="feed_load_error_fast_unknown">快速 feed 模式不會提供更多資訊。</string> <string name="feed_load_error_fast_unknown">快速 feed 模式不會提供更多資訊。</string>
<string name="feed_load_error_terminated">作者的帳號已被終止。 <string name="feed_load_error_terminated">作者的帳號已被終止。

View file

@ -257,6 +257,8 @@
<string name="restore_defaults">Restore defaults</string> <string name="restore_defaults">Restore defaults</string>
<string name="restore_defaults_confirmation">Do you want to restore defaults?</string> <string name="restore_defaults_confirmation">Do you want to restore defaults?</string>
<string name="permission_display_over_apps">Give permission to display over other apps</string> <string name="permission_display_over_apps">Give permission to display over other apps</string>
<string name="permission_display_over_apps_message">In order to use the Popup Player, please select %1$s in the following Android settings menu and enable %2$s.</string>
<string name="permission_display_over_apps_permission_name">“Allow display over other apps”</string>
<!-- error activity --> <!-- error activity -->
<string name="error_report_notification_title">NewPipe encountered an error, tap to report</string> <string name="error_report_notification_title">NewPipe encountered an error, tap to report</string>
<string name="error_report_notification_toast">An error occurred, see the notification</string> <string name="error_report_notification_toast">An error occurred, see the notification</string>
@ -333,6 +335,8 @@
<string name="pause">Pause</string> <string name="pause">Pause</string>
<string name="create">Create</string> <string name="create">Create</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="delete_file">Delete file</string>
<string name="delete_entry">Delete entry</string>
<string name="checksum">Checksum</string> <string name="checksum">Checksum</string>
<string name="dismiss">Dismiss</string> <string name="dismiss">Dismiss</string>
<string name="rename">Rename</string> <string name="rename">Rename</string>
@ -752,7 +756,7 @@
<string name="private_content">This content is private, so it cannot be streamed or downloaded by NewPipe.</string> <string name="private_content">This content is private, so it cannot be streamed or downloaded by NewPipe.</string>
<string name="youtube_music_premium_content">This video is available only to YouTube Music Premium members, so it cannot be streamed or downloaded by NewPipe.</string> <string name="youtube_music_premium_content">This video is available only to YouTube Music Premium members, so it cannot be streamed or downloaded by NewPipe.</string>
<string name="account_terminated">Account terminated</string> <string name="account_terminated">Account terminated</string>
<string name="service_provides_reason">%s provides this reason:</string> <string name="account_terminated_service_provides_reason">Account terminated\n\n%1$s provides this reason: %2$s</string>
<string name="paid_content">This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe.</string> <string name="paid_content">This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe.</string>
<string name="featured">Featured</string> <string name="featured">Featured</string>
<string name="radio">Radio</string> <string name="radio">Radio</string>
@ -891,4 +895,10 @@
<string name="trending_podcasts">Trending podcasts</string> <string name="trending_podcasts">Trending podcasts</string>
<string name="trending_movies">Trending movies and shows</string> <string name="trending_movies">Trending movies and shows</string>
<string name="trending_music">Trending music</string> <string name="trending_music">Trending music</string>
<string name="entry_deleted">Entry deleted</string>
<string name="player_http_403">HTTP error 403 received from server while playing, likely caused by streaming URL expiration or an IP ban</string>
<string name="player_http_invalid_status">HTTP error %1$s received from server while playing</string>
<string name="youtube_player_http_403">HTTP error 403 received from server while playing, likely caused by an IP ban or streaming URL deobfuscation issues</string>
<string name="sign_in_confirm_not_bot_error">%1$s refused to provide data, asking for a login to confirm the requester is not a bot.\n\nYour IP might have been temporarily banned by %1$s, 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> </resources>

View file

@ -1,21 +1 @@
<?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50" style="fill:#cd201f"/><path d="M31.7 19.2v61.7l9.7-5.73V36l23.8 14-17.6 10.35V71.5L84 50" style="fill:#fff"/></svg>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#CD201F;}
.st1{fill:#FFFFFF;}
</style>
<g id="Alapkör">
<circle id="XMLID_23_" class="st0" cx="50" cy="50" r="50"/>
</g>
<g id="Elemek">
<path id="XMLID_19_" class="st1" d="M47,28.2c-9-5.3-15.3-9-15.3-9v61.7c0,0,30.4-18,52.3-30.9C72.1,43,57.7,34.5,47,28.2z"/>
</g>
<g id="Fedő">
<path id="XMLID_5_" class="st0" d="M48.4,40.1c-4.1-2.4-7-4.1-7-4.1V64c0,0,13.9-8.2,23.8-14C59.8,46.8,53.3,42.9,48.4,40.1z"/>
<rect id="XMLID_4_" x="41.4" y="55.6" class="st0" width="6.2" height="21"/>
</g>
<g id="Vonalak">
</g>
</svg>

Before

Width:  |  Height:  |  Size: 850 B

After

Width:  |  Height:  |  Size: 229 B

Before After
Before After

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 100 100"><path d="M0 50C0 15 15 0 50 0s50 15 50 50-15 50-50 50S0 85 0 50" style="fill:#cd201f"/><path d="M31.7 19.2v61.7l9.7-5.73V36l23.8 14-17.6 10.35V71.5L84 50" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 263 B

View file

@ -1,67 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 100 100"><path d="M31.7 19.2v61.7l9.7-5.73V36l23.8 14-17.6 10.35V71.5L84 50" style="fill:#fff"/></svg>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
style="enable-background:new 0 0 100 100;"
xml:space="preserve"
id="svg12"
sodipodi:docname="NP logo v2.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata18"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs16">
</defs><sodipodi:namedview
pagecolor="#9f9f9f"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="740"
id="namedview14"
showgrid="false"
inkscape:zoom="1.668772"
inkscape:cx="63.900143"
inkscape:cy="31.160181"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg12" />
<style
type="text/css"
id="style2">
.st0{fill:#CD201F;}
.st1{fill:#FFFFFF;}
</style>
<path
style="fill:#ffffff;stroke-width:1.2782383"
d="m 23.90906,10.210574 v 78.8688 c 0,0 7.70042,-4.556206 12.400409,-7.337388 V 67.476647 56.738946 31.685975 c 0,0 3.706891,2.172506 8.947669,5.240278 6.263367,3.579067 14.570418,8.564696 21.472905,12.655059 -9.358315,5.482649 -16.799873,9.875994 -22.496496,13.23426 V 77.053449 C 57.973932,68.927101 75.175728,58.76222 90.76192,49.581312 75.550885,40.633643 57.144253,29.76762 43.467104,21.714718 31.962959,14.940056 23.90906,10.210574 23.90906,10.210574 Z"
id="XMLID_19_"
inkscape:connector-curvature="0" />
<g
id="Vonalak">
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 176 B

Before After
Before After

View file

@ -58,7 +58,7 @@ teamnewpipe-nanojson = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996"
# the corresponding commit hash, since JitPack sometimes deletes artifacts. # the corresponding commit hash, since JitPack sometimes deletes artifacts.
# If theres already a git hash, just add more of it to the end (or remove a letter) # If theres already a git hash, just add more of it to the end (or remove a letter)
# to cause jitpack to regenerate the artifact. # to cause jitpack to regenerate the artifact.
teamnewpipe-newpipe-extractor = "v0.24.8" teamnewpipe-newpipe-extractor = "0023b22095a2d62a60cdfc87f4b5cd85c8b266c3"
webkit = "1.9.0" webkit = "1.9.0"
work = "2.10.0" work = "2.10.0"