Compare commits

...

32 Commits

Author SHA1 Message Date
yosrinajar cc2ebcb3c4
Merge 4c2f405adb into 9828586762 2024-04-23 20:40:37 +02:00
Stypox 9828586762
Fix indentation for ktlint 2024-04-23 20:16:04 +02:00
Hosted Weblate 8caaa6d297
Merge branch 'origin/dev' into Weblate. 2024-04-23 19:27:20 +02:00
Stypox 83ca6b9468
Update NewPipeExtractor to v0.24.0 2024-04-23 19:25:13 +02:00
Stypox 24e65ef018
Merge branch 'dev' 2024-04-23 19:23:20 +02:00
Stypox a69bbab732
Merge pull request from GHSA-wxrm-jhpf-vp6v
Fix preferences import vulnerability
2024-04-23 19:22:17 +02:00
Stypox a557ac3c7b
Merge pull request #10929 from TeamNewPipe/release-0.27.0
Release v0.27.0 (997)
2024-04-23 19:21:12 +02:00
Stypox d61b4b89ea
Merge pull request #10992 from Stypox/fix-download-nnfp
Fix free storage space check for all APIs
2024-04-23 18:42:57 +02:00
Stypox b8daf16b92
Update app/src/main/java/org/schabi/newpipe/streams/io/StoredDirectoryHelper.java
Co-authored-by: Tobi <TobiGr@users.noreply.github.com>
2024-04-23 18:39:56 +02:00
Stypox caa3812e13
Ignore all errors when getting free storage space
It's not a critical check that needs to be perfomed, so in case something does not work on some device/version, let's just ignore the error.
2024-04-23 18:05:31 +02:00
Hosted Weblate 23a087c498
Translated using Weblate (Romanian)
Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Croatian)

Currently translated at 99.5% (735 of 738 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (French (Louisiana))

Currently translated at 0.2% (2 of 738 strings)

Translated using Weblate (Portuguese (Portugal))

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Portuguese (Portugal))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (738 of 738 strings)

Added translation using Weblate (French (Louisiana))

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (French)

Currently translated at 99.7% (736 of 738 strings)

Added translation using Weblate (Arabic (Tunisian))

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (ryu (generated) (ryu))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Kannada)

Currently translated at 5.8% (43 of 738 strings)

Translated using Weblate (Kannada)

Currently translated at 5.1% (4 of 78 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Russian)

Currently translated at 99.8% (737 of 738 strings)

Translated using Weblate (German)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (German)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (ryu (generated) (ryu))

Currently translated at 99.0% (731 of 738 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.7% (736 of 738 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Russian)

Currently translated at 99.7% (736 of 738 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Vietnamese)

Currently translated at 50.0% (39 of 78 strings)

Translated using Weblate (Sardinian)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Vietnamese)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Greek)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Japanese)

Currently translated at 99.4% (734 of 738 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Punjabi)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Punjabi)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Hindi)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Serbian)

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (Slovak)

Currently translated at 21.7% (17 of 78 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 62.8% (49 of 78 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (78 of 78 strings)

Translated using Weblate (Polish)

Currently translated at 61.5% (48 of 78 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 23.0% (18 of 78 strings)

Co-authored-by: Agnieszka C <aga_04@o2.pl>
Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Co-authored-by: Alex25820 <alexs25820@gmail.com>
Co-authored-by: AudricV <AudricV@users.noreply.hosted.weblate.org>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Co-authored-by: Jonatan Nyberg <jonatan@autistici.org>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: MS-PC <MSPCtranslator@gmail.com>
Co-authored-by: Milan <mobrcian@hotmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: NEXI <nexiphotographer@gmail.com>
Co-authored-by: Philip Goto <philip.goto@gmail.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Ray <ray@users.noreply.hosted.weblate.org>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Sergio Marques <so.boston.android@gmail.com>
Co-authored-by: ShareASmile <ShareASmile@users.noreply.hosted.weblate.org>
Co-authored-by: Tấn Lực Trương <september122022ios16@gmail.com>
Co-authored-by: Vasilis K <skyhirules@gmail.com>
Co-authored-by: VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Co-authored-by: abhijithkjg <abhijithkj2001@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: kaajjo <claymanoff@gmail.com>
Co-authored-by: kuragehime <kuragehime641@gmail.com>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: yosrinajar <yosron3@gmail.com>
Co-authored-by: zeineb-b <zeinebbouhejba21@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/ar/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/cs/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/de/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/es/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/hi/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/id/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/it/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/kn/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/pa/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/pl/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/pt/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/pt_PT/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/sk/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/sv/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/uk/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/vi/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/zh_Hant_HK/
Translation: NewPipe/Metadata
2024-04-23 18:00:52 +02:00
Stypox c3c39a7b24
Fix free storage space check for all APIs
See https://stackoverflow.com/q/31171838
See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html
2024-04-23 12:16:06 +02:00
Stypox 00770fc634
Update NewPipeExtractor 2024-04-20 13:11:08 +02:00
Stypox 5bf77160f7
Merge pull request #10952 from bg172/release-0.27.0
Add an intuitive prefix for the duration of lists in the UI
2024-04-11 09:27:54 +02:00
Stypox d9da84c412
Merge pull request #10957 from Stypox/fix-feed-npe
Fix NPE if avatarUrl is null when reloading feed
2024-04-11 09:26:11 +02:00
Audric V b3a6318672
Merge pull request #10959 from Stypox/fix-comment-replies-state
Fix not saving comment replies state on config change
2024-04-10 16:24:31 +02:00
Stypox 67b41b970d
Fix not saving comment replies state on config change 2024-04-10 10:52:47 +02:00
Stypox 3738e30949
Fix NPE when avatarUrl is empty 2024-04-09 20:18:21 +02:00
Stypox 0ba73b11c1
Update NewPipeExtractor 2024-04-08 00:03:37 +02:00
bg1722 13baaa31cd add an intuitive prefix for the duration of lists on UI, and avoid using the new prefix for single videos 2024-04-06 07:58:05 +02:00
TobiGr f0db2aa43c Improve documentation 2024-04-04 15:49:12 +02:00
Stypox f704721b59
Release v0.27.0 (997) 2024-04-01 14:23:48 +02:00
Stypox 7abf0f4886
Update NewPipeExtractor to YT comments fix PR
https://github.com/TeamNewPipe/NewPipeExtractor/pull/1163
2024-04-01 14:23:04 +02:00
Stypox 2756ef6d2f
Show notification when failing to import settings 2024-03-30 18:53:45 +01:00
Stypox 7da1d30010
Expose all import/export errors to the user 2024-03-30 18:47:20 +01:00
Stypox 8e192acb63
Add test zips and extensive tests for ImportExportManager
Now all possible combinations of files in the zip (present or not) are checked at the same time
2024-03-30 18:42:11 +01:00
Stypox d8423499dc
Use JSON for settings imports/exports 2024-03-30 16:58:12 +01:00
Stypox 6afdbd6fd3
Add test: vulnerable settings should fail importing 2024-03-30 16:12:41 +01:00
Stypox d8668ed226
Show snackbar error when settings import fails 2024-03-30 16:12:41 +01:00
Stypox d75a6eaa41
Fix vulnerability with whitelist-aware ObjectInputStream
Only a few specific classes are now allowed.
2024-03-30 16:12:35 +01:00
Stypox 235fb92638
Make checkstyle accept javadocs with long links 2024-03-30 15:49:06 +01:00
Stypox ea18b4ea1f
Move import export manager to separate folder 2024-03-30 15:49:05 +01:00
91 changed files with 1517 additions and 569 deletions

View File

@ -20,8 +20,8 @@ android {
resValue "string", "app_name", "NewPipe"
minSdk 21
targetSdk 33
versionCode 996
versionName "0.26.1"
versionCode 997
versionName "0.27.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -198,7 +198,7 @@ dependencies {
// name and the commit hash with the commit hash of the (pushed) commit you want to test
// This works thanks to JitPack: https://jitpack.io/
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
implementation 'com.github.Stypox:NewPipeExtractor:aaf3231fc75d7b4177549fec4aa7e672bfe84015'
implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.0'
implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
/** Checkstyle **/

View File

@ -1,6 +1,7 @@
package org.schabi.newpipe.database.subscription;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
@ -95,11 +96,12 @@ public class SubscriptionEntity {
this.name = name;
}
@Nullable
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(final String avatarUrl) {
public void setAvatarUrl(@Nullable final String avatarUrl) {
this.avatarUrl = avatarUrl;
}

View File

@ -859,20 +859,19 @@ public class DownloadDialog extends DialogFragment
return;
}
// Check for free memory space (for api 24 and up)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
final long freeSpace = mainStorage.getFreeMemory();
if (freeSpace <= size) {
Toast.makeText(context, getString(R.
string.error_insufficient_storage), Toast.LENGTH_LONG).show();
// move the user to storage setting tab
final Intent storageSettingsIntent = new Intent(Settings.
ACTION_INTERNAL_STORAGE_SETTINGS);
if (storageSettingsIntent.resolveActivity(context.getPackageManager()) != null) {
startActivity(storageSettingsIntent);
}
return;
// Check for free storage space
final long freeSpace = mainStorage.getFreeStorageSpace();
if (freeSpace <= size) {
Toast.makeText(context, getString(R.
string.error_insufficient_storage), Toast.LENGTH_LONG).show();
// move the user to storage setting tab
final Intent storageSettingsIntent = new Intent(Settings.
ACTION_INTERNAL_STORAGE_SETTINGS);
if (storageSettingsIntent.resolveActivity(context.getPackageManager())
!= null) {
startActivity(storageSettingsIntent);
}
return;
}
// check for existing file with the same name

View File

@ -6,6 +6,7 @@ package org.schabi.newpipe.error;
public enum UserAction {
USER_REPORT("user report"),
UI_ERROR("ui error"),
DATABASE_IMPORT_EXPORT("database import or export"),
SUBSCRIPTION_CHANGE("subscription change"),
SUBSCRIPTION_UPDATE("subscription update"),
SUBSCRIPTION_GET("get subscription"),

View File

@ -30,6 +30,7 @@ import org.schabi.newpipe.util.text.TextLinkifier;
import java.util.Queue;
import java.util.function.Supplier;
import icepick.State;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
@ -38,7 +39,8 @@ public final class CommentRepliesFragment
public static final String TAG = CommentRepliesFragment.class.getSimpleName();
private CommentsInfoItem commentsInfoItem; // the comment to show replies of
@State
CommentsInfoItem commentsInfoItem; // the comment to show replies of
private final CompositeDisposable disposables = new CompositeDisposable();

View File

@ -506,7 +506,7 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
Localization.concatenateStrings(
Localization.localizeStreamCount(activity, streamCount),
Localization.getDurationString(playlistOverallDurationSeconds,
isDurationComplete))
isDurationComplete, true))
);
}
}

View File

@ -18,7 +18,7 @@ data class FeedUpdateInfo(
@NotificationMode
val notificationMode: Int,
val name: String,
val avatarUrl: String,
val avatarUrl: String?,
val url: String,
val serviceId: Int,
// description and subscriberCount are null if the constructor info is from the fast feed method

View File

@ -837,7 +837,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
headerBinding.playlistStreamCount.setText(
Localization.concatenateStrings(
Localization.localizeStreamCount(activity, streamCount),
Localization.getDurationString(playlistOverallDurationSeconds))
Localization.getDurationString(playlistOverallDurationSeconds,
true, true))
);
}
}

View File

@ -100,7 +100,9 @@ class SubscriptionManager(context: Context) {
val subscriptionEntity = subscriptionTable.getSubscription(info.uid)
subscriptionEntity.name = info.name
subscriptionEntity.avatarUrl = info.avatarUrl
// some services do not provide an avatar URL
info.avatarUrl?.let { subscriptionEntity.avatarUrl = it }
// these two fields are null if the feed info was fetched using the fast feed method
info.description?.let { subscriptionEntity.description = it }

View File

@ -21,9 +21,15 @@ import androidx.core.content.ContextCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import com.grack.nanojson.JsonParserException;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.settings.export.BackupFileLocator;
import org.schabi.newpipe.settings.export.ImportExportManager;
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
import org.schabi.newpipe.streams.io.StoredFileHelper;
import org.schabi.newpipe.util.NavigationHelper;
@ -42,7 +48,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
private final SimpleDateFormat exportDateFormat =
new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
private ContentSettingsManager manager;
private ImportExportManager manager;
private String importExportDataPathKey;
private final ActivityResultLauncher<Intent> requestImportPathLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
@ -57,8 +63,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
@Nullable final String rootKey) {
final File homeDir = ContextCompat.getDataDir(requireContext());
Objects.requireNonNull(homeDir);
manager = new ContentSettingsManager(new NewPipeFileLocator(homeDir));
manager.deleteSettingsFile();
manager = new ImportExportManager(new BackupFileLocator(homeDir));
importExportDataPathKey = getString(R.string.import_export_data_path);
@ -165,7 +170,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
Toast.makeText(requireContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
.show();
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(this, "Exporting database", e);
showErrorSnackbar(e, "Exporting database and settings");
}
}
@ -182,6 +187,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
throw new IOException("Could not create databases dir");
}
// replace the current database
if (!manager.extractDb(file)) {
Toast.makeText(requireContext(), R.string.could_not_import_all_files,
Toast.LENGTH_LONG)
@ -189,9 +195,13 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
}
// if settings file exist, ask if it should be imported.
if (manager.extractSettings(file)) {
final boolean hasJsonPrefs = manager.exportHasJsonPrefs(file);
if (hasJsonPrefs || manager.exportHasSerializedPrefs(file)) {
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle(R.string.import_settings)
.setMessage(hasJsonPrefs ? null : requireContext()
.getString(R.string.import_settings_vulnerable_format))
.setOnDismissListener(dialog -> finishImport(importDataUri))
.setNegativeButton(R.string.cancel, (dialog, which) -> {
dialog.dismiss();
finishImport(importDataUri);
@ -201,7 +211,16 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
final Context context = requireContext();
final SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
manager.loadSharedPreferences(prefs);
try {
if (hasJsonPrefs) {
manager.loadJsonPrefs(file, prefs);
} else {
manager.loadSerializedPrefs(file, prefs);
}
} catch (IOException | ClassNotFoundException | JsonParserException e) {
createErrorNotification(e, "Importing preferences");
return;
}
cleanImport(context, prefs);
finishImport(importDataUri);
})
@ -210,7 +229,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
finishImport(importDataUri);
}
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(this, "Importing database", e);
showErrorSnackbar(e, "Importing database and settings");
}
}
@ -247,7 +266,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
}
/**
* Save import path and restart system.
* Save import path and restart app.
*
* @param importDataUri The import path to save
*/
@ -268,4 +287,15 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
.putString(importExportDataPathKey, importExportDataUri.toString());
editor.apply();
}
private void showErrorSnackbar(final Throwable e, final String request) {
ErrorUtil.showSnackbar(this, new ErrorInfo(e, UserAction.DATABASE_IMPORT_EXPORT, request));
}
private void createErrorNotification(final Throwable e, final String request) {
ErrorUtil.createNotification(
requireContext(),
new ErrorInfo(e, UserAction.DATABASE_IMPORT_EXPORT, request)
);
}
}

View File

@ -1,120 +0,0 @@
package org.schabi.newpipe.settings
import android.content.SharedPreferences
import android.util.Log
import org.schabi.newpipe.MainActivity.DEBUG
import org.schabi.newpipe.streams.io.SharpOutputStream
import org.schabi.newpipe.streams.io.StoredFileHelper
import org.schabi.newpipe.util.ZipHelper
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.util.zip.ZipOutputStream
class ContentSettingsManager(private val fileLocator: NewPipeFileLocator) {
companion object {
const val TAG = "ContentSetManager"
}
/**
* Exports given [SharedPreferences] to the file in given outputPath.
* It also creates the file.
*/
@Throws(Exception::class)
fun exportDatabase(preferences: SharedPreferences, file: StoredFileHelper) {
file.create()
ZipOutputStream(SharpOutputStream(file.stream).buffered())
.use { outZip ->
ZipHelper.addFileToZip(outZip, fileLocator.db.path, "newpipe.db")
try {
ObjectOutputStream(fileLocator.settings.outputStream()).use { output ->
output.writeObject(preferences.all)
output.flush()
}
} catch (e: IOException) {
if (DEBUG) {
Log.e(TAG, "Unable to exportDatabase", e)
}
}
ZipHelper.addFileToZip(outZip, fileLocator.settings.path, "newpipe.settings")
}
}
fun deleteSettingsFile() {
fileLocator.settings.delete()
}
/**
* Tries to create database directory if it does not exist.
*
* @return Whether the directory exists afterwards.
*/
fun ensureDbDirectoryExists(): Boolean {
return fileLocator.dbDir.exists() || fileLocator.dbDir.mkdir()
}
fun extractDb(file: StoredFileHelper): Boolean {
val success = ZipHelper.extractFileFromZip(file, fileLocator.db.path, "newpipe.db")
if (success) {
fileLocator.dbJournal.delete()
fileLocator.dbWal.delete()
fileLocator.dbShm.delete()
}
return success
}
fun extractSettings(file: StoredFileHelper): Boolean {
return ZipHelper.extractFileFromZip(file, fileLocator.settings.path, "newpipe.settings")
}
/**
* Remove all shared preferences from the app and load the preferences supplied to the manager.
*/
fun loadSharedPreferences(preferences: SharedPreferences) {
try {
val preferenceEditor = preferences.edit()
ObjectInputStream(fileLocator.settings.inputStream()).use { input ->
preferenceEditor.clear()
@Suppress("UNCHECKED_CAST")
val entries = input.readObject() as Map<String, *>
for ((key, value) in entries) {
when (value) {
is Boolean -> {
preferenceEditor.putBoolean(key, value)
}
is Float -> {
preferenceEditor.putFloat(key, value)
}
is Int -> {
preferenceEditor.putInt(key, value)
}
is Long -> {
preferenceEditor.putLong(key, value)
}
is String -> {
preferenceEditor.putString(key, value)
}
is Set<*> -> {
// There are currently only Sets with type String possible
@Suppress("UNCHECKED_CAST")
preferenceEditor.putStringSet(key, value as Set<String>?)
}
}
}
preferenceEditor.commit()
}
} catch (e: IOException) {
if (DEBUG) {
Log.e(TAG, "Unable to loadSharedPreferences", e)
}
} catch (e: ClassNotFoundException) {
if (DEBUG) {
Log.e(TAG, "Unable to loadSharedPreferences", e)
}
}
}
}

View File

@ -1,21 +0,0 @@
package org.schabi.newpipe.settings
import java.io.File
/**
* Locates specific files of NewPipe based on the home directory of the app.
*/
class NewPipeFileLocator(private val homeDir: File) {
val dbDir by lazy { File(homeDir, "/databases") }
val db by lazy { File(homeDir, "/databases/newpipe.db") }
val dbJournal by lazy { File(homeDir, "/databases/newpipe.db-journal") }
val dbShm by lazy { File(homeDir, "/databases/newpipe.db-shm") }
val dbWal by lazy { File(homeDir, "/databases/newpipe.db-wal") }
val settings by lazy { File(homeDir, "/databases/newpipe.settings") }
}

View File

@ -0,0 +1,28 @@
package org.schabi.newpipe.settings.export
import java.io.File
/**
* Locates specific files of NewPipe based on the home directory of the app.
*/
class BackupFileLocator(private val homeDir: File) {
companion object {
const val FILE_NAME_DB = "newpipe.db"
@Deprecated(
"Serializing preferences with Java's ObjectOutputStream is vulnerable to injections",
replaceWith = ReplaceWith("FILE_NAME_JSON_PREFS")
)
const val FILE_NAME_SERIALIZED_PREFS = "newpipe.settings"
const val FILE_NAME_JSON_PREFS = "preferences.json"
}
val dbDir by lazy { File(homeDir, "/databases") }
val db by lazy { File(dbDir, FILE_NAME_DB) }
val dbJournal by lazy { File(dbDir, "$FILE_NAME_DB-journal") }
val dbShm by lazy { File(dbDir, "$FILE_NAME_DB-shm") }
val dbWal by lazy { File(dbDir, "$FILE_NAME_DB-wal") }
}

View File

@ -0,0 +1,180 @@
package org.schabi.newpipe.settings.export
import android.content.SharedPreferences
import com.grack.nanojson.JsonArray
import com.grack.nanojson.JsonParser
import com.grack.nanojson.JsonParserException
import com.grack.nanojson.JsonWriter
import org.schabi.newpipe.streams.io.SharpOutputStream
import org.schabi.newpipe.streams.io.StoredFileHelper
import org.schabi.newpipe.util.ZipHelper
import java.io.FileNotFoundException
import java.io.IOException
import java.io.ObjectOutputStream
import java.util.zip.ZipOutputStream
class ImportExportManager(private val fileLocator: BackupFileLocator) {
companion object {
const val TAG = "ImportExportManager"
}
/**
* Exports given [SharedPreferences] to the file in given outputPath.
* It also creates the file.
*/
@Throws(Exception::class)
fun exportDatabase(preferences: SharedPreferences, file: StoredFileHelper) {
file.create()
ZipOutputStream(SharpOutputStream(file.stream).buffered()).use { outZip ->
// add the database
ZipHelper.addFileToZip(
outZip,
BackupFileLocator.FILE_NAME_DB,
fileLocator.db.path,
)
// add the legacy vulnerable serialized preferences (will be removed in the future)
ZipHelper.addFileToZip(
outZip,
BackupFileLocator.FILE_NAME_SERIALIZED_PREFS
) { byteOutput ->
ObjectOutputStream(byteOutput).use { output ->
output.writeObject(preferences.all)
output.flush()
}
}
// add the JSON preferences
ZipHelper.addFileToZip(
outZip,
BackupFileLocator.FILE_NAME_JSON_PREFS
) { byteOutput ->
JsonWriter
.indent("")
.on(byteOutput)
.`object`(preferences.all)
.done()
}
}
}
/**
* Tries to create database directory if it does not exist.
*
* @return Whether the directory exists afterwards.
*/
fun ensureDbDirectoryExists(): Boolean {
return fileLocator.dbDir.exists() || fileLocator.dbDir.mkdir()
}
/**
* Extracts the database from the given file to the app's database directory.
* The current app's database will be overwritten.
* @param file the .zip file to extract the database from
* @return true if the database was successfully extracted, false otherwise
*/
fun extractDb(file: StoredFileHelper): Boolean {
val success = ZipHelper.extractFileFromZip(
file,
BackupFileLocator.FILE_NAME_DB,
fileLocator.db.path,
)
if (success) {
fileLocator.dbJournal.delete()
fileLocator.dbWal.delete()
fileLocator.dbShm.delete()
}
return success
}
@Deprecated(
"Serializing preferences with Java's ObjectOutputStream is vulnerable to injections",
replaceWith = ReplaceWith("exportHasJsonPrefs")
)
fun exportHasSerializedPrefs(zipFile: StoredFileHelper): Boolean {
return ZipHelper.zipContainsFile(zipFile, BackupFileLocator.FILE_NAME_SERIALIZED_PREFS)
}
fun exportHasJsonPrefs(zipFile: StoredFileHelper): Boolean {
return ZipHelper.zipContainsFile(zipFile, BackupFileLocator.FILE_NAME_JSON_PREFS)
}
/**
* Remove all shared preferences from the app and load the preferences supplied to the manager.
*/
@Deprecated(
"Serializing preferences with Java's ObjectOutputStream is vulnerable to injections",
replaceWith = ReplaceWith("loadJsonPrefs")
)
@Throws(IOException::class, ClassNotFoundException::class)
fun loadSerializedPrefs(zipFile: StoredFileHelper, preferences: SharedPreferences) {
ZipHelper.extractFileFromZip(zipFile, BackupFileLocator.FILE_NAME_SERIALIZED_PREFS) {
PreferencesObjectInputStream(it).use { input ->
@Suppress("UNCHECKED_CAST")
val entries = input.readObject() as Map<String, *>
val editor = preferences.edit()
editor.clear()
for ((key, value) in entries) {
when (value) {
is Boolean -> editor.putBoolean(key, value)
is Float -> editor.putFloat(key, value)
is Int -> editor.putInt(key, value)
is Long -> editor.putLong(key, value)
is String -> editor.putString(key, value)
is Set<*> -> {
// There are currently only Sets with type String possible
@Suppress("UNCHECKED_CAST")
editor.putStringSet(key, value as Set<String>?)
}
}
}
if (!editor.commit()) {
throw IOException("Unable to commit loadSerializedPrefs")
}
}
}.let { fileExists ->
if (!fileExists) {
throw FileNotFoundException(BackupFileLocator.FILE_NAME_SERIALIZED_PREFS)
}
}
}
/**
* Remove all shared preferences from the app and load the preferences supplied to the manager.
*/
@Throws(IOException::class, JsonParserException::class)
fun loadJsonPrefs(zipFile: StoredFileHelper, preferences: SharedPreferences) {
ZipHelper.extractFileFromZip(zipFile, BackupFileLocator.FILE_NAME_JSON_PREFS) {
val jsonObject = JsonParser.`object`().from(it)
val editor = preferences.edit()
editor.clear()
for ((key, value) in jsonObject) {
when (value) {
is Boolean -> editor.putBoolean(key, value)
is Float -> editor.putFloat(key, value)
is Int -> editor.putInt(key, value)
is Long -> editor.putLong(key, value)
is String -> editor.putString(key, value)
is JsonArray -> {
editor.putStringSet(key, value.mapNotNull { e -> e as? String }.toSet())
}
}
}
if (!editor.commit()) {
throw IOException("Unable to commit loadJsonPrefs")
}
}.let { fileExists ->
if (!fileExists) {
throw FileNotFoundException(BackupFileLocator.FILE_NAME_JSON_PREFS)
}
}
}
}

View File

@ -0,0 +1,58 @@
package org.schabi.newpipe.settings.export;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.util.Set;
/**
* An {@link ObjectInputStream} that only allows preferences-related types to be deserialized, to
* prevent injections. The only allowed types are: all primitive types, all boxed primitive types,
* null, strings. HashMap, HashSet and arrays of previously defined types are also allowed. Sources:
* <a href="https://wiki.sei.cmu.edu/confluence/display/java/SER00-J.+Enable+serialization+compatibility+during+class+evolution">
* cmu.edu
* </a>,
* <a href="https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#harden-your-own-javaioobjectinputstream">
* OWASP cheatsheet
* </a>,
* <a href="https://commons.apache.org/proper/commons-io/apidocs/src-html/org/apache/commons/io/serialization/ValidatingObjectInputStream.html#line-118">
* Apache's {@code ValidatingObjectInputStream}
* </a>
*/
public class PreferencesObjectInputStream extends ObjectInputStream {
/**
* Primitive types, strings and other built-in types do not pass through resolveClass() but
* instead have a custom encoding; see
* <a href="https://docs.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html#10152">
* official docs</a>.
*/
private static final Set<String> CLASS_WHITELIST = Set.of(
"java.lang.Boolean",
"java.lang.Byte",
"java.lang.Character",
"java.lang.Short",
"java.lang.Integer",
"java.lang.Long",
"java.lang.Float",
"java.lang.Double",
"java.lang.Void",
"java.util.HashMap",
"java.util.HashSet"
);
public PreferencesObjectInputStream(final InputStream in) throws IOException {
super(in);
}
@Override
protected Class<?> resolveClass(final ObjectStreamClass desc)
throws ClassNotFoundException, IOException {
if (CLASS_WHITELIST.contains(desc.getName())) {
return super.resolveClass(desc);
} else {
throw new ClassNotFoundException("Class not allowed: " + desc.getName());
}
}
}

View File

@ -1,24 +1,28 @@
package org.schabi.newpipe.streams.io;
import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME;
import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.system.Os;
import android.system.StructStatVfs;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.documentfile.provider.DocumentFile;
import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.util.FilePickerActivityHelper;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
@ -27,16 +31,9 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME;
import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import us.shandian.giga.util.Utility;
public class StoredDirectoryHelper {
private static final String TAG = StoredDirectoryHelper.class.getSimpleName();
public static final int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
@ -45,6 +42,10 @@ public class StoredDirectoryHelper {
private Path ioTree;
private DocumentFile docTree;
/**
* Context is `null` for non-SAF files, i.e. files that use `ioTree`.
*/
@Nullable
private Context context;
private final String tag;
@ -176,41 +177,43 @@ public class StoredDirectoryHelper {
}
/**
* Get free memory of the storage partition (root of the directory).
* @return amount of free memory in the volume of current directory (bytes)
* Get free memory of the storage partition this file belongs to (root of the directory).
* See <a href="https://stackoverflow.com/q/31171838">StackOverflow</a> and
* <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html">
* {@code statvfs()} and {@code fstatvfs()} docs</a>
*
* @return amount of free memory in the volume of current directory (bytes), or {@link
* Long#MAX_VALUE} if an error occurred
*/
@RequiresApi(api = Build.VERSION_CODES.N) // Necessary for `getStorageVolume()`
public long getFreeMemory() {
final Uri uri = getUri();
final StorageManager storageManager = (StorageManager) context.
getSystemService(Context.STORAGE_SERVICE);
final List<StorageVolume> volumes = storageManager.getStorageVolumes();
public long getFreeStorageSpace() {
try {
final StructStatVfs stat;
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
if (split.length > 0) {
final String volumeId = split[0];
if (ioTree != null) {
// non-SAF file, use statvfs with the path directly (also, `context` would be null
// for non-SAF files, so we wouldn't be able to call `getContentResolver` anyway)
stat = Os.statvfs(ioTree.toString());
for (final StorageVolume volume : volumes) {
// if the volume is an internal system volume
if (volume.isPrimary() && volumeId.equalsIgnoreCase("primary")) {
return Utility.getSystemFreeMemory();
}
// if the volume is a removable volume (normally an SD card)
if (volume.isRemovable() && !volume.isPrimary()) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
try {
final String sdCardUUID = volume.getUuid();
return storageManager.getAllocatableBytes(UUID.fromString(sdCardUUID));
} catch (final Exception e) {
// do nothing
}
} else {
// SAF file, we can't get a path directly, so obtain a file descriptor first
// and then use fstatvfs with the file descriptor
try (ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(getUri(), "r")) {
if (parcelFileDescriptor == null) {
return Long.MAX_VALUE;
}
final FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
stat = Os.fstatvfs(fileDescriptor);
}
}
// this is the same formula used inside the FsStat class
return stat.f_bavail * stat.f_frsize;
} catch (final Throwable e) {
// ignore any error
Log.e(TAG, "Could not get free storage space", e);
return Long.MAX_VALUE;
}
return Long.MAX_VALUE;
}
/**

View File

@ -245,7 +245,7 @@ public final class Localization {
* @return a formatted duration String or {@code 0:00} if the duration is zero.
*/
public static String getDurationString(final long duration) {
return getDurationString(duration, true);
return getDurationString(duration, true, false);
}
/**
@ -254,9 +254,11 @@ public final class Localization {
* duration string.
* @param duration the duration in seconds
* @param isDurationComplete whether the given duration is complete or whether info is missing
* @param showDurationPrefix whether the duration-prefix shall be shown
* @return a formatted duration String or {@code 0:00} if the duration is zero.
*/
public static String getDurationString(final long duration, final boolean isDurationComplete) {
public static String getDurationString(final long duration, final boolean isDurationComplete,
final boolean showDurationPrefix) {
final String output;
final long days = duration / (24 * 60 * 60L); /* greater than a day */
@ -274,8 +276,9 @@ public final class Localization {
} else {
output = String.format(Locale.US, "%d:%02d", minutes, seconds);
}
final String durationPrefix = showDurationPrefix ? "" : "";
final String durationPostfix = isDurationComplete ? "" : "+";
return output + durationPostfix;
return durationPrefix + output + durationPostfix;
}
/**

View File

@ -1,18 +1,21 @@
package org.schabi.newpipe.util;
import org.schabi.newpipe.streams.io.SharpInputStream;
import org.schabi.newpipe.streams.io.StoredFileHelper;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.schabi.newpipe.streams.io.StoredFileHelper;
/**
* Created by Christian Schabesberger on 28.01.18.
* Copyright 2018 Christian Schabesberger <chris.schabesberger@mailbox.org>
@ -34,73 +37,154 @@ import org.schabi.newpipe.streams.io.StoredFileHelper;
*/
public final class ZipHelper {
private ZipHelper() { }
private static final int BUFFER_SIZE = 2048;
@FunctionalInterface
public interface InputStreamConsumer {
void acceptStream(InputStream inputStream) throws IOException;
}
@FunctionalInterface
public interface OutputStreamConsumer {
void acceptStream(OutputStream outputStream) throws IOException;
}
private ZipHelper() { }
/**
* This function helps to create zip files.
* Caution this will override the original file.
* This function helps to create zip files. Caution this will overwrite the original file.
*
* @param outZip The ZipOutputStream where the data should be stored in
* @param file The path of the file that should be added to zip.
* @param name The path of the file inside the zip.
* @throws Exception
* @param outZip the ZipOutputStream where the data should be stored in
* @param nameInZip the path of the file inside the zip
* @param fileOnDisk the path of the file on the disk that should be added to zip
*/
public static void addFileToZip(final ZipOutputStream outZip, final String file,
final String name) throws Exception {
public static void addFileToZip(final ZipOutputStream outZip,
final String nameInZip,
final String fileOnDisk) throws IOException {
try (FileInputStream fi = new FileInputStream(fileOnDisk)) {
addFileToZip(outZip, nameInZip, fi);
}
}
/**
* This function helps to create zip files. Caution this will overwrite the original file.
*
* @param outZip the ZipOutputStream where the data should be stored in
* @param nameInZip the path of the file inside the zip
* @param streamConsumer will be called with an output stream that will go to the output file
*/
public static void addFileToZip(final ZipOutputStream outZip,
final String nameInZip,
final OutputStreamConsumer streamConsumer) throws IOException {
final byte[] bytes;
try (ByteArrayOutputStream byteOutput = new ByteArrayOutputStream()) {
streamConsumer.acceptStream(byteOutput);
bytes = byteOutput.toByteArray();
}
try (ByteArrayInputStream byteInput = new ByteArrayInputStream(bytes)) {
ZipHelper.addFileToZip(outZip, nameInZip, byteInput);
}
}
/**
* This function helps to create zip files. Caution this will overwrite the original file.
*
* @param outZip the ZipOutputStream where the data should be stored in
* @param nameInZip the path of the file inside the zip
* @param inputStream the content to put inside the file
*/
public static void addFileToZip(final ZipOutputStream outZip,
final String nameInZip,
final InputStream inputStream) throws IOException {
final byte[] data = new byte[BUFFER_SIZE];
try (FileInputStream fi = new FileInputStream(file);
BufferedInputStream inputStream = new BufferedInputStream(fi, BUFFER_SIZE)) {
final ZipEntry entry = new ZipEntry(name);
try (BufferedInputStream bufferedInputStream =
new BufferedInputStream(inputStream, BUFFER_SIZE)) {
final ZipEntry entry = new ZipEntry(nameInZip);
outZip.putNextEntry(entry);
int count;
while ((count = inputStream.read(data, 0, BUFFER_SIZE)) != -1) {
while ((count = bufferedInputStream.read(data, 0, BUFFER_SIZE)) != -1) {
outZip.write(data, 0, count);
}
}
}
/**
* This will extract data from ZipInputStream.
* Caution this will override the original file.
* This will extract data from ZipInputStream. Caution this will overwrite the original file.
*
* @param zipFile The zip file
* @param file The path of the file on the disk where the data should be extracted to.
* @param name The path of the file inside the zip.
* @param zipFile the zip file to extract from
* @param nameInZip the path of the file inside the zip
* @param fileOnDisk the path of the file on the disk where the data should be extracted to
* @return will return true if the file was found within the zip file
* @throws Exception
*/
public static boolean extractFileFromZip(final StoredFileHelper zipFile, final String file,
final String name) throws Exception {
public static boolean extractFileFromZip(final StoredFileHelper zipFile,
final String nameInZip,
final String fileOnDisk) throws IOException {
return extractFileFromZip(zipFile, nameInZip, input -> {
// delete old file first
final File oldFile = new File(fileOnDisk);
if (oldFile.exists()) {
if (!oldFile.delete()) {
throw new IOException("Could not delete " + fileOnDisk);
}
}
final byte[] data = new byte[BUFFER_SIZE];
try (FileOutputStream outFile = new FileOutputStream(fileOnDisk)) {
int count;
while ((count = input.read(data)) != -1) {
outFile.write(data, 0, count);
}
}
});
}
/**
* This will extract data from ZipInputStream.
*
* @param zipFile the zip file to extract from
* @param nameInZip the path of the file inside the zip
* @param streamConsumer will be called with the input stream from the file inside the zip
* @return will return true if the file was found within the zip file
*/
public static boolean extractFileFromZip(final StoredFileHelper zipFile,
final String nameInZip,
final InputStreamConsumer streamConsumer)
throws IOException {
try (ZipInputStream inZip = new ZipInputStream(new BufferedInputStream(
new SharpInputStream(zipFile.getStream())))) {
ZipEntry ze;
while ((ze = inZip.getNextEntry()) != null) {
if (ze.getName().equals(nameInZip)) {
streamConsumer.acceptStream(inZip);
return true;
}
}
return false;
}
}
/**
* @param zipFile the zip file
* @param fileInZip the filename to check
* @return whether the provided filename is in the zip; only the first level is checked
*/
public static boolean zipContainsFile(final StoredFileHelper zipFile, final String fileInZip)
throws Exception {
try (ZipInputStream inZip = new ZipInputStream(new BufferedInputStream(
new SharpInputStream(zipFile.getStream())))) {
final byte[] data = new byte[BUFFER_SIZE];
boolean found = false;
ZipEntry ze;
while ((ze = inZip.getNextEntry()) != null) {
if (ze.getName().equals(name)) {
found = true;
// delete old file first
final File oldFile = new File(file);
if (oldFile.exists()) {
if (!oldFile.delete()) {
throw new Exception("Could not delete " + file);
}
}
try (FileOutputStream outFile = new FileOutputStream(file)) {
int count = 0;
while ((count = inZip.read(data)) != -1) {
outFile.write(data, 0, count);
}
}
inZip.closeEntry();
if (ze.getName().equals(fileInZip)) {
return true;
}
}
return found;
return false;
}
}

View File

@ -40,20 +40,6 @@ public class Utility {
UNKNOWN
}
/**
* Get amount of free system's memory.
* @return free memory (bytes)
*/
public static long getSystemFreeMemory() {
try {
final StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
return statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong();
} catch (final Exception e) {
// do nothing
}
return -1;
}
public static String formatBytes(long bytes) {
Locale locale = Locale.getDefault();
if (bytes < 1024) {

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View File

@ -819,4 +819,9 @@
<string name="yes">Ja</string>
<string name="no">Nein</string>
<string name="settings_category_backup_restore_title">Sichern und Wiederherstellen</string>
<string name="auto_update_check_description">NewPipe kann von Zeit zu Zeit automatisch nach neuen Versionen suchen und dich benachrichtigen, sobald sie verfügbar sind.
\nMöchtest du dies aktivieren?</string>
<string name="reset_all_settings">Wenn du alle Einstellungen zurücksetzt, werden alle deine bevorzugten Einstellungen verworfen und die App wird neu gestartet.
\n
\nMöchtest du wirklich fortfahren?</string>
</resources>

View File

@ -813,4 +813,15 @@
<string name="show_more">Εμφάνιση περισσοτέρων</string>
<string name="show_less">Εμφάνιση λιγότερων</string>
<string name="notification_actions_summary_android13">Επεξεργαστείτε κάθε ενέργεια ειδοποίησης παρακάτω πατώντας σε αυτήν. Οι τρεις πρώτες ενέργειες (αναπαραγωγή/παύση, προηγούμενηο και επόμενο) ορίζονται από το σύστημα και δεν μπορούν να τροποποιηθούν.</string>
<string name="error_insufficient_storage">Δεν υπάρχει αρκετός ελεύθερος χώρος στη συσκευή</string>
<string name="no">Όχι</string>
<string name="yes">Ναι</string>
<string name="settings_category_backup_restore_title">Αντίγραφο ασφαλείας και επαναφορά</string>
<string name="auto_update_check_description">Το NewPipe μπορεί να ελέγχει αυτόματα για νέες εκδόσεις και να σας ειδοποιεί μόλις είναι διαθέσιμες.
\nΘέλετε να το ενεργοποιήσετε;</string>
<string name="reset_settings_title">Επαναφορά ρυθμίσεων</string>
<string name="reset_settings_summary">Επαναφορά όλων των ρυθμίσεων στις αρχικές τιμές τους</string>
<string name="reset_all_settings">Η επαναφορά όλων των ρυθμίσεων θα απορρίψει όλες τις τροποποιημένες ρυθμίσεις σας και θα επανεκκινήσει την εφαρμογή.
\n
\nΕίστε βέβαιοι ότι θέλετε να συνεχίσετε;</string>
</resources>

View File

@ -782,7 +782,7 @@
<string name="metadata_subscribers">Suscriptores</string>
<string name="show_channel_tabs_summary">Qué pestañas se muestran en las páginas de los canales</string>
<string name="show_channel_tabs">Pestañas del canal</string>
<string name="channel_tab_shorts">Cortos</string>
<string name="channel_tab_shorts">Shorts</string>
<string name="loading_metadata_title">Cargando los metadatos…</string>
<string name="feed_fetch_channel_tabs">Recuperar las fichas del canal</string>
<string name="channel_tab_about">Acerca de</string>

View File

@ -829,4 +829,15 @@
<string name="notification_actions_summary_android13">Modifiez chaque action de notification ci-dessous en appuyant dessus. Les trois premières actions (lire/pause, précédent, suivant) sont définies par le système et ne peuvent pas être personnalisées.</string>
<string name="show_more">Afficher plus</string>
<string name="show_less">Afficher moins</string>
<string name="reset_settings_summary">Réinitialiser tous les paramètres à leurs valeurs par défaut</string>
<string name="no">Non</string>
<string name="reset_all_settings">La réinitialisation de tous les paramètres va supprimer toutes vos préférences de paramètres et redémarrer l\'application.
\n
\nÊtes-vous sûr de vouloir poursuivre?</string>
<string name="settings_category_backup_restore_title">Sauvegarde et restauration</string>
<string name="yes">Oui</string>
<string name="auto_update_check_description">NewPipe peut automatiquement vérifier la disponibilité de nouvelles versions de temps en temps et vous notifier lorsqu\'elles sont disponibles.
\nVoulez-vous activer cette vérification?</string>
<string name="reset_settings_title">Réinitialiser les paramètres</string>
<string name="error_insufficient_storage">Pas assez d\'espace disponible sur l\'appareil</string>
</resources>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="no_player_found">aucun streamer trouvé . Installez VLC?</string>
<string name="no">non</string>
<string name="open_in_browser">ouvrir dans le browser</string>
<string name="open_in_popup_mode">ouvrir dans le popup mode</string>
<string name="open_with">ouvrir avec</string>
<string name="share">partagez</string>
<string name="controls_download_desc">installer le fichier stream</string>
<string name="search">chercher</string>
<string name="settings">parameters</string>
<string name="download">installer</string>
<string name="install">Installer</string>
<string name="mark_as_watched">marquer comme vu</string>
<string name="upload_date_text">"publié le %1$s"</string>
<string name="no_player_found_toast">aucun joueur de stream n\'est trouvé ( vous pouvez installez VLC pour jouer)</string>
<string name="cancel">Annuler</string>
<string name="ok">OK</string>
<string name="yes">Oui</string>
</resources>

View File

@ -813,4 +813,15 @@
<string name="show_more">और दिखाओ</string>
<string name="notification_actions_summary_android13">नीचे दी गई प्रत्येक अधिसूचना कार्रवाई पर टैप करके उसे संपादित करें। पहली तीन क्रियाएँ (चलाएँ/रोकें, पिछली और अगली) सिस्टम द्वारा निर्धारित की जाती हैं और इन्हें अनुकूलित नहीं किया जा सकता है।</string>
<string name="show_less">कम दिखाएं</string>
<string name="auto_update_check_description">न्यूपाइप समय-समय पर स्वचालित रूप से नए संस्करणों की जांच कर सकती है और उपलब्ध होने पर आपको सूचित कर सकती है।
\nक्या आप इसे सक्षम करना चाहते हैं?</string>
<string name="reset_settings_title">सेटिंग्स रीसेट करें</string>
<string name="reset_settings_summary">सभी सेटिंग्स को उनके डिफ़ॉल्ट मानों पर रीसेट करें</string>
<string name="reset_all_settings">सभी सेटिंग्स को रीसेट करने से आपकी सभी पसंदीदा सेटिंग्स खारिज हो जाएंगी और ऐप पुनः प्रारंभ हो जाएगा।
\n
\nक्या आप सुनिश्चित रूप से आगे बढ़ना चाहते हैं?</string>
<string name="yes">हाँ</string>
<string name="no">नहीं</string>
<string name="error_insufficient_storage">डिवाइस पर पर्याप्त खाली स्थान नहीं है</string>
<string name="settings_category_backup_restore_title">बैकअप और रिस्टोर</string>
</resources>

View File

@ -574,7 +574,7 @@
\nYouTube je primjer usluge koja nudi ovaj brzi način sa svojim RSS feedom.
\n
\nDakle, izbor se svodi na ono što više voliš: brzinu ili precizne informacije.</string>
<string name="msg_calculating_hash">Izračunavanje šifriranja</string>
<string name="msg_calculating_hash">Izračunavanje šifre</string>
<string name="hash_channel_name">Obavijest šifriranja videa</string>
<string name="hash_channel_description">Obavijesti o napretku šifriranja videa</string>
<string name="recent">Nedavni</string>
@ -733,7 +733,7 @@
<string name="feed_show_upcoming">Najava</string>
<string name="sort">Razvrstaj</string>
<string name="use_exoplayer_decoder_fallback_title">Koristi razervnu funkciju ExoPlayer dekodera</string>
<string name="ignore_hardware_media_buttons_title">Ignoriranje hardverskih medijskih gumba</string>
<string name="ignore_hardware_media_buttons_title">Ignoriraj događaje hardverskih medijskih gumba</string>
<string name="ignore_hardware_media_buttons_summary">Korisno, na primjer, ako koristite slušalice s pokvarenim fizičkim gumbima</string>
<string name="prefer_descriptive_audio_summary">Odaberite zvučni zapis s opisima za slabovidne osobe ako je dostupan</string>
<string name="prefer_original_audio_title">Preferiraj originalni zvuk</string>
@ -821,4 +821,16 @@
<item quantity="other">%s odgovora</item>
</plurals>
<string name="disable_media_tunneling_automatic_info">Tuneliranje medija je standardno deaktivirano na tvom uređaju jer je poznato da model tvog uređaja to ne podržava.</string>
<string name="yes">Da</string>
<string name="no">Ne</string>
<string name="use_exoplayer_decoder_fallback_summary">Aktiviraj ovu opciju ako imaš problema s inicijaliziranjem dekodera, što vraća dekodere nižeg prioriteta ako inicijaliziranje primarnih dekodera ne uspije. To može rezultirati lošijim performansama reprodukcije u odnosu na korištenje primarnih dekodera</string>
<string name="error_insufficient_storage">Nedovoljno memorije na uređaju</string>
<string name="settings_category_backup_restore_title">Spremanje sigurnosne kopije i obnavljanje</string>
<string name="auto_update_check_description">NewPipe može automatski tražiti nove verzije i obavijestiti te.
\nŽeliš li aktivirati tu mogućnost?</string>
<string name="reset_settings_title">Obnovi postavke</string>
<string name="reset_settings_summary">Obnovi sve postavke na zadane vrijednosti</string>
<string name="reset_all_settings">Obnavljanje svih postavki odbacit će sve tvoje postavljene postavke i aplikacija će se ponovo pokrenuti.
\n
\nStvarno želiš nastaviti?</string>
</resources>

View File

@ -834,4 +834,8 @@
\n
\nSei sicuro di voler procedere?</string>
<string name="reset_settings_summary">Azzera tutte le impostazioni ai loro valori predefiniti</string>
<string name="yes"></string>
<string name="no">No</string>
<string name="auto_update_check_description">NewPipe può cercare automaticamente nuove versioni di tanto in tanto e avvisarti quando sono disponibili.
\nVuoi attivarlo?</string>
</resources>

View File

@ -800,4 +800,14 @@
<string name="show_less">表示を少なくする</string>
<string name="notification_actions_summary_android13">以下の通知アクションをタップして編集します。 最初の3つのアクション (再生/一時停止、前へ、次へ)はシステムによって設定されており、カスタマイズすることはできません。</string>
<string name="error_insufficient_storage">デバイスの空き容量が不足しています</string>
<string name="settings_category_backup_restore_title">バックアップと復元</string>
<string name="yes">はい</string>
<string name="no">いいえ</string>
<string name="auto_update_check_description">NewPipe は定期的に新しいバージョンを自動的にチェックし、更新可能になると通知します。
\n有効にしますか</string>
<string name="reset_settings_title">設定をリセット</string>
<string name="reset_settings_summary">全ての設定をデフォルト状態にリセットします</string>
<string name="reset_all_settings">全ての設定をリセットすると、優先設定が全て破棄され、アプリが再起動します。
\n
\n続行しますか</string>
</resources>

View File

@ -40,4 +40,6 @@
<string name="tab_choose">ಟ್ಯಾಬ್ ಆಯ್ಕೆಮಾಡಿ</string>
<string name="controls_background_title">ಹಿನ್ನೆಲೆ</string>
<string name="unsubscribe">ಅನ್‌ಸಬ್‌ಸ್ಕ್ರೈಬ್ ಮಾಡಿ</string>
<string name="yes">ಹೌದು</string>
<string name="no">ಇಲ್ಲ</string>
</resources>

View File

@ -205,8 +205,8 @@
<string name="popup_player">Pop-upspeler</string>
<string name="preferred_player_fetcher_notification_title">Bezig met ophalen van informatie…</string>
<string name="preferred_player_fetcher_notification_message">Bezig met laden van gevraagde inhoud</string>
<string name="import_data_title">Databank importeren</string>
<string name="export_data_title">Databank exporteren</string>
<string name="import_data_title">Data­base importeren</string>
<string name="export_data_title">Data­base exporteren</string>
<string name="import_data_summary">Dit overschrijft je huidige geschiedenis, abonnementen, afspeellijsten en instellingen</string>
<string name="export_data_summary">Exporteer geschiedenis, abonnementen, afspeellijsten en instellingen</string>
<string name="export_complete_toast">Geëxporteerd</string>
@ -637,7 +637,7 @@
<string name="comments_are_disabled">Reacties zijn uitgeschakeld</string>
<string name="remote_search_suggestions">Zoeksuggesties op afstand</string>
<string name="local_search_suggestions">Lokale zoeksuggesties</string>
<string name="mark_as_watched">Markeer als bekeken</string>
<string name="mark_as_watched">Markeren als bekeken</string>
<plurals name="deleted_downloads_toast">
<item quantity="one">%1$s download verwijderd</item>
<item quantity="other">%1$s downloads verwijderd</item>

View File

@ -813,4 +813,15 @@
<string name="show_more">ਹੋਰ ਵਿਖਾਓ</string>
<string name="notification_actions_summary_android13">ਇਸ \'ਤੇ ਟੈਪ ਕਰਕੇ ਹੇਠਾਂ ਹਰੇਕ ਸੂਚਨਾ ਕਾਰਵਾਈ ਨੂੰ ਸੰਪਾਦਿਤ ਕਰੋ। ਪਹਿਲੀਆਂ ਤਿੰਨ ਕਾਰਵਾਈਆਂ (ਪਲੇ/ਪੌਜ਼, ਪਿਛਲਾ ਅਤੇ ਅਗਲਾ) ਸਿਸਟਮ ਦੁਆਰਾ ਸੈੱਟ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਅਨੁਕੂਲਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।</string>
<string name="show_less">ਘੱਟ ਦਿਖਾਓ</string>
<string name="yes">ਹਾਂ</string>
<string name="auto_update_check_description">ਨਿਊਪਾਈਪ ਸਮੇਂ-ਸਮੇਂ \'ਤੇ ਨਵੇਂ ਸੰਸਕਰਣਾਂ ਦੀ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਜਾਂਚ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਇੱਕ ਵਾਰ ਉਪਲਬਧ ਹੋਣ \'ਤੇ ਤੁਹਾਨੂੰ ਸੂਚਿਤ ਕਰ ਸਕਦੀ ਹੈ।
\nਕੀ ਤੁਸੀਂ ਇਸਨੂੰ ਇਨੇਬਲ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?</string>
<string name="settings_category_backup_restore_title">ਬੈਕਅੱਪ ਅਤੇ ਰੀਸਟੋਰ</string>
<string name="reset_settings_title">ਸੈਟਿੰਗਾਂ ਨੂੰ ਰੀਸੈਟ ਕਰੋ</string>
<string name="reset_settings_summary">ਸਾਰੀਆਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਉਹਨਾਂ ਦੇ ਡਿਫ਼ਾਲਟ ਮੁੱਲਾਂ \'ਤੇ ਰੀਸੈਟ ਕਰੋ</string>
<string name="reset_all_settings">ਸਾਰੀਆਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨ ਨਾਲ ਤੁਹਾਡੀਆਂ ਸਾਰੀਆਂ ਤਰਜੀਹੀ ਸੈਟਿੰਗਾਂ ਰੱਦ ਹੋ ਜਾਣਗੀਆਂ ਅਤੇ ਐਪ ਰੀਸਟਾਰਟ ਹੋ ਜਾਵੇਗਾ।
\n
\nਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ \'ਤੇ ਅੱਗੇ ਵਧਣਾ ਚਾਹੁੰਦੇ ਹੋ?</string>
<string name="error_insufficient_storage">ਡਿਵਾਈਸ \'ਤੇ ਲੋੜੀਂਦੀ ਖਾਲੀ ਥਾਂ ਨਹੀਂ ਹੈ</string>
<string name="no">ਨਹੀਂ</string>
</resources>

View File

@ -17,8 +17,8 @@
<string name="delete">Excluir</string>
<string name="detail_dislikes_img_view_description">Não gostei</string>
<string name="detail_likes_img_view_description">Curtidas</string>
<string name="download">Baixar</string>
<string name="download_dialog_title">Baixar</string>
<string name="download">Download</string>
<string name="download_dialog_title">Download</string>
<string name="error_details_headline">Detalhes:</string>
<string name="error_report_button_text">Relatar por e-mail</string>
<string name="error_report_title">Relatório de erro</string>
@ -31,7 +31,7 @@
<string name="msg_error">Erro</string>
<string name="msg_copied">Copiado para a área de transferência</string>
<string name="msg_name">Nome do arquivo</string>
<string name="msg_running_detail">Toque para detalhes</string>
<string name="msg_running_detail">Toque para mais detalhes</string>
<string name="msg_running">O NewPipe está baixando</string>
<string name="msg_wait">Por favor, espere…</string>
<string name="network_error">Erro de rede</string>
@ -57,30 +57,30 @@
<string name="downloads">Downloads</string>
<string name="downloads_title">Downloads</string>
<string name="did_you_mean">Você quis dizer \"%1$s\"\?</string>
<string name="app_ui_crash">Aplicativo/IU parou</string>
<string name="app_ui_crash">O aplicativo travou</string>
<string name="background_player_playing_toast">Reproduzindo em segundo plano</string>
<string name="could_not_setup_download_menu">O menu de download não pôde ser configurado</string>
<string name="detail_thumbnail_view_description">Reproduzir vídeo, duração:</string>
<string name="detail_uploader_thumbnail_view_description">Miniatura do avatar do uploader</string>
<string name="detail_uploader_thumbnail_view_description">Foto de perfil do autor</string>
<string name="download_path_audio_dialog_title">Escolha a pasta de download para arquivos de áudio</string>
<string name="download_path_audio_summary">Áudios baixados são salvos aqui</string>
<string name="download_path_audio_title">Pasta para áudios baixados</string>
<string name="download_path_dialog_title">Escolha a pasta de download para arquivos de vídeo</string>
<string name="download_path_summary">Vídeos baixados são salvos aqui</string>
<string name="download_path_title">Pasta para vídeos baixados</string>
<string name="kore_not_found">Instalar o aplicativo Kore\?</string>
<string name="kore_not_found">Instalar Kore?</string>
<string name="main_bg_subtitle">Toque na lupa para começar.</string>
<string name="msg_threads">Threads</string>
<string name="msg_threads">Processos</string>
<string name="no_available_dir">Por favor, defina uma pasta de download depois nas configurações</string>
<string name="no_player_found">Sem reprodutor de transmissão. Instalar VLC?</string>
<string name="no_player_found">Player de vídeo não encontrado. Instalar VLC?</string>
<string name="parsing_error">O site não pôde ser analisado</string>
<string name="play_audio">Áudio</string>
<string name="play_with_kodi_title">Reproduzir com Kodi</string>
<string name="play_with_kodi_title">Reproduzir no Kodi</string>
<string name="search">Pesquisar</string>
<string name="show_play_with_kodi_summary">Mostra uma opção para ver vídeo pelo media center do Kodi</string>
<string name="use_external_audio_player_title">Usar reprodutor de áudio externo</string>
<string name="use_external_video_player_title">Usar reprodutor de vídeo externo</string>
<string name="show_play_with_kodi_title">Mostrar opção \"Reproduzir com Kodi\"</string>
<string name="show_play_with_kodi_summary">Mostrar opção para reproduzir o vídeo no Kodi</string>
<string name="use_external_audio_player_title">Usar player de áudio externo</string>
<string name="use_external_video_player_title">Usar player de vídeo externo</string>
<string name="show_play_with_kodi_title">Mostrar opção \"Reproduzir no Kodi\"</string>
<string name="info_labels">O que aconteceu:\\nPedido:\\nIdioma do conteúdo:\\nPaís do conteúdo:\\nIdioma do aplicativo:\\nServiço:\\nHora GMT:\\nPacote:\\nVersão:\\nVersão do SO:</string>
<string name="open_in_popup_mode">Abrir no modo Popup</string>
<string name="default_popup_resolution_title">Resolução padrão do Popup</string>
@ -88,11 +88,11 @@
<string name="show_higher_resolutions_summary">Apenas alguns dispositivos suportam vídeos em 2K/4K</string>
<string name="default_video_format_title">Formato de vídeo padrão</string>
<string name="popup_playing_toast">Reproduzindo em modo Popup</string>
<string name="all">Tudo</string>
<string name="all">Todos</string>
<string name="disabled">Desativado</string>
<string name="short_thousand">k</string>
<string name="short_million">M</string>
<string name="short_billion">Bi</string>
<string name="short_thousand">mil</string>
<string name="short_million">mi</string>
<string name="short_billion">bi</string>
<string name="msg_popup_permission">Essa permissão é necessária
\npara abrir em modo Popup</string>
<string name="clear">Limpar</string>
@ -100,7 +100,7 @@
<string name="controls_background_title">Segundo plano</string>
<string name="popup_remember_size_pos_title">Lembrar propriedades do Popup</string>
<string name="popup_remember_size_pos_summary">Lembrar último tamanho e posição do Popup</string>
<string name="use_external_video_player_summary">Remove o som em algumas resoluções</string>
<string name="use_external_video_player_summary">Remove áudio em algumas resoluções</string>
<string name="show_search_suggestions_title">Sugestões de pesquisa</string>
<string name="show_search_suggestions_summary">Escolha as sugestões a serem exibidas enquanto estiver buscando</string>
<string name="best_resolution">Melhor resolução</string>
@ -115,7 +115,7 @@
<string name="contribution_title">Colaborar</string>
<string name="copyright" formatted="true">© %1$s %2$s protegido pela licença %3$s</string>
<string name="title_activity_about">Sobre o NewPipe</string>
<string name="settings_category_downloads_title">Baixar</string>
<string name="settings_category_downloads_title">Download</string>
<string name="settings_file_charset_title">Caracteres permitidos em nome de arquivos</string>
<string name="settings_file_replacement_character_summary">Os caracteres inválidos são substituídos por este valor</string>
<string name="settings_file_replacement_character_title">Caractere de substituição</string>
@ -124,20 +124,20 @@
<string name="subscribe_button_title">Inscrever-se</string>
<string name="subscribed_button_title">Inscrito</string>
<string name="channel_unsubscribed">Inscrição cancelada</string>
<string name="subscription_change_failed">Não foi possível alterar inscrição</string>
<string name="subscription_update_failed">Não foi possível atualizar inscrição</string>
<string name="subscription_change_failed">Não foi possível alterar a inscrição</string>
<string name="subscription_update_failed">Não foi possível atualizar a inscrição</string>
<string name="tab_subscriptions">Inscrições</string>
<string name="fragment_feed_title">Novidades</string>
<string name="resume_on_audio_focus_gain_title">Continuar reprodução</string>
<string name="resume_on_audio_focus_gain_summary">Continua vídeo após interrupções (ex: ligações)</string>
<string name="enable_search_history_title">Histórico de pesquisa</string>
<string name="enable_search_history_summary">Armazena histórico de pesquisa localmente</string>
<string name="enable_watch_history_title">Histórico de vídeo</string>
<string name="enable_watch_history_summary">Armazena histórico de vídeos assistidos</string>
<string name="enable_watch_history_title">Histórico de exibição</string>
<string name="enable_watch_history_summary">Mantenha o controle dos vídeos assistidos</string>
<string name="title_activity_history">Histórico</string>
<string name="action_history">Histórico</string>
<string name="notification_channel_name">Notificação do NewPipe</string>
<string name="notification_channel_description">Notificações para o reprodutor do NewPipe</string>
<string name="notification_channel_description">Notificações para o player NewPipe</string>
<string name="settings_category_player_behavior_title">Comportamento</string>
<string name="settings_category_history_title">Histórico e cache</string>
<string name="undo">Desfazer</string>
@ -160,29 +160,29 @@
<item quantity="many">%s vídeos</item>
<item quantity="other">%s vídeos</item>
</plurals>
<string name="settings_category_player_title">Reprodutor</string>
<string name="settings_category_player_title">Player</string>
<string name="empty_list_subtitle">Nada aqui além de grilos</string>
<string name="delete_item_search_history">Deseja excluir este item do histórico de busca\?</string>
<string name="main_page_content">Conteúdo da página inicial</string>
<string name="blank_page_summary">Página em branco</string>
<string name="kiosk_page_summary">Página do Quiosque</string>
<string name="channel_page_summary">Página de canais</string>
<string name="kiosk_page_summary">Página do Kiosk</string>
<string name="channel_page_summary">Página do canal</string>
<string name="select_a_channel">Selecione um canal</string>
<string name="no_channel_subscribed_yet">Nenhuma inscrição ainda</string>
<string name="select_a_kiosk">Selecione uma banca</string>
<string name="select_a_kiosk">Selecione um Kiosk</string>
<string name="trending">Em Alta</string>
<string name="top_50">Top 50</string>
<string name="new_and_hot">Novos e tendências</string>
<string name="show_hold_to_append_title">Mostrar dica \"Segure para pôr na fila\"</string>
<string name="show_hold_to_append_summary">Mostra dica ao tocar no botão segundo plano ou Popup em \"Detalhes:\" do vídeo</string>
<string name="play_all">Reproduzir tudo</string>
<string name="player_stream_failure">Não é possível reproduzir esta transmissão</string>
<string name="player_unrecoverable_failure">Ocorreu um erro irrecuperável no reprodutor</string>
<string name="player_recoverable_failure">Se recuperando do erro do reprodutor</string>
<string name="player_stream_failure">Não é possível reproduzir este vídeo</string>
<string name="player_unrecoverable_failure">Ocorreu um erro irrecuperável na reprodução</string>
<string name="player_recoverable_failure">Se recuperando de um erro durante a reprodução</string>
<string name="play_queue_remove">Remover</string>
<string name="play_queue_stream_detail">Detalhes</string>
<string name="play_queue_audio_settings">Configurações de áudio</string>
<string name="hold_to_append">Segure para pôr na fila</string>
<string name="hold_to_append">Toque longo para pôr na fila</string>
<string name="unknown_content">[Desconhecido]</string>
<string name="start_here_on_background">Reproduzir em segundo plano</string>
<string name="start_here_on_popup">Reproduzir em um Popup</string>
@ -191,52 +191,52 @@
<string name="give_back">Retribuir</string>
<string name="website_title">Site oficial</string>
<string name="website_encouragement">Visite o site do NewPipe para mais informações e novidades.</string>
<string name="no_player_found_toast">Reprodutor de transmissão não encontrado (pode instalar o VLC para assistir).</string>
<string name="no_player_found_toast">Player de vídeo não encontrado (você pode instalar o VLC para reproduzi-lo).</string>
<string name="default_content_country_title">País padrão do conteúdo</string>
<string name="always">Sempre</string>
<string name="just_once">Uma vez</string>
<string name="just_once">Apenas uma vez</string>
<string name="switch_to_background">Mudar para segundo plano</string>
<string name="switch_to_popup">Mudar para Popup</string>
<string name="switch_to_main">Mudar para principal</string>
<string name="external_player_unsupported_link_type">Reprodutores externos não suportam estes tipos de URL</string>
<string name="external_player_unsupported_link_type">Players externos não suportam estes tipos de URL</string>
<string name="video_streams_empty">Nenhuma transmissão de vídeo encontrada</string>
<string name="audio_streams_empty">Nenhuma transmissão de áudio encontrada</string>
<string name="video_player">Reprodutor de vídeo</string>
<string name="background_player">Reprodutor em segundo plano</string>
<string name="popup_player">Reprodutor Popup</string>
<string name="video_player">Player de vídeo</string>
<string name="background_player">Reprodução em segundo plano</string>
<string name="popup_player">Reprodução em Popup</string>
<string name="preferred_player_fetcher_notification_title">Obtendo informação…</string>
<string name="preferred_player_fetcher_notification_message">Carregando conteúdo solicitado</string>
<string name="import_data_title">Importar base de dados</string>
<string name="export_data_title">Exportar base de dados</string>
<string name="import_data_summary">Substitui seu histórico atual, inscrições, listas de reprodução e (opcionalmente) configurações</string>
<string name="export_data_summary">Exporta histórico, inscrições, listas de reprodução e configurações</string>
<string name="import_data_summary">Substitui seu histórico atual, inscrições, playlists e (opcionalmente) configurações</string>
<string name="export_data_summary">Exporta histórico, inscrições, playlists e configurações</string>
<string name="export_complete_toast">Exportado</string>
<string name="import_complete_toast">Importado</string>
<string name="no_valid_zip_file">Nenhum arquivo ZIP válido</string>
<string name="could_not_import_all_files">Aviso: Não foi possível importar todos os arquivos.</string>
<string name="override_current_data">Isso irá sobrescrever suas configurações atuais.</string>
<string name="controls_download_desc">Baixar arquivo de transmissão</string>
<string name="controls_download_desc">Baixar arquivo</string>
<string name="show_info">Mostrar informação</string>
<string name="tab_bookmarks">Listas de reprodução favoritas</string>
<string name="tab_bookmarks">Playlists favoritas</string>
<string name="controls_add_to_playlist_title">Adicionar a</string>
<string name="detail_drag_description">Arraste para ordenar</string>
<string name="create">Criar</string>
<string name="dismiss">Dispensar</string>
<string name="dismiss">Descartar</string>
<string name="rename">Renomear</string>
<string name="title_last_played">Último reproduzido</string>
<string name="title_most_played">Mais reproduzido</string>
<string name="title_last_played">Última reprodução</string>
<string name="title_most_played">Mais assistidos</string>
<string name="always_ask_open_action">Sempre perguntar</string>
<string name="create_playlist">Nova lista de reprodução</string>
<string name="create_playlist">Nova playlist</string>
<string name="rename_playlist">Renomear</string>
<string name="name">Nome</string>
<string name="add_to_playlist">Adicionar à lista de reprodução</string>
<string name="set_as_playlist_thumbnail">Definir como miniatura da lista de reprodução</string>
<string name="bookmark_playlist">Favoritar lista de reprodução</string>
<string name="add_to_playlist">Adicionar à playlist</string>
<string name="set_as_playlist_thumbnail">Definir como miniatura da playlist</string>
<string name="bookmark_playlist">Salvar como playlist favorita</string>
<string name="unbookmark_playlist">Remover dos favoritos</string>
<string name="delete_playlist_prompt">Excluir esta lista de reprodução?</string>
<string name="playlist_creation_success">lista de reprodução criada</string>
<string name="playlist_add_stream_success">Adicionado à lista de reprodução</string>
<string name="playlist_thumbnail_change_success">Miniatura da lista de reprodução alterada.</string>
<string name="delete_playlist_prompt">Excluir esta playlist?</string>
<string name="playlist_creation_success">Playlist criada</string>
<string name="playlist_add_stream_success">Adicionado à playlist</string>
<string name="playlist_thumbnail_change_success">Miniatura da playlist alterada.</string>
<string name="caption_none">Sem legendas</string>
<string name="resize_fit">Ajustar</string>
<string name="resize_fill">Preencher</string>
@ -246,11 +246,11 @@
<string name="enable_disposed_exceptions_title">Reportar erros de out-of-lifecycle</string>
<string name="enable_disposed_exceptions_summary">Forçar entrega de relatórios de erros Rx fora de um fragmento ou atividade de lifecycle após o descarte</string>
<string name="use_inexact_seek_title">Usar busca de posição rápida (inexata)</string>
<string name="use_inexact_seek_summary">A busca inexata permite que o reprodutor de vídeo ache posições mais rápido com a precisão reduzida. Não funciona para voltar ou avançar 5, 15 ou 25 segundos</string>
<string name="use_inexact_seek_summary">A busca inexata permite que o player de vídeo ache posições mais rápido com a precisão reduzida. Não funciona para voltar ou avançar 5, 15 ou 25 segundos</string>
<string name="auto_queue_title">Enfileirar a próxima transmissão automaticamente</string>
<string name="auto_queue_summary">Continua a reprodução da fila (sem repetição) adicionando mais transmissões similares</string>
<string name="file">Arquivo</string>
<string name="invalid_directory">Pasta não existe</string>
<string name="invalid_directory">Essa pasta não existe</string>
<string name="invalid_source">Arquivo/fonte do conteúdo não existe</string>
<string name="invalid_file">O arquivo não existe ou não há permissão para leitura ou escrita</string>
<string name="file_name_empty_error">O nome do arquivo não pode ficar vazio</string>
@ -262,78 +262,78 @@
<string name="export_ongoing">Exportando…</string>
<string name="import_file_title">Importar arquivo</string>
<string name="previous_export">Exportação anterior</string>
<string name="subscriptions_import_unsuccessful">Não foi possível importar inscrições</string>
<string name="subscriptions_export_unsuccessful">Não foi possível exportar inscrições</string>
<string name="import_youtube_instructions">Importe inscrições do YouTube pelo Google takeout:
<string name="subscriptions_import_unsuccessful">Não foi possível importar as inscrições</string>
<string name="subscriptions_export_unsuccessful">Não foi possível exportar as inscrições</string>
<string name="import_youtube_instructions">Importar inscrições do YouTube em Google Takeout:
\n
\n1. Acesse este URL: %1$s
\n2. Faça login quando solicitado
\n3. Clique em \"Todos os dados incluídos\", depois em \"Desmarcar todos\", em seguida, selecione apenas \"assinaturas\" e clique em \"OK\"
\n4. Clique em \"Próximo passo\" e em seguida, em \"Criar exportação\"
\n5. Clique no botão \"Baixar\" quando ele aparecer
\n3. Clique em \"Todos os dados incluídos\", depois em \"Desmarcar todos\", selecione apenas \"Inscrições\" e clique em \"OK\"
\n4. Clique em \"Próxima etapa\" e, em seguida, em \"Criar exportação\"
\n5. Clique no botão \"Download\" quando ele aparecer
\n6. Clique em IMPORTAR ARQUIVO abaixo e selecione o arquivo .zip baixado
\n7. Caso a importação do arquivo .zip falhe: Extraia o arquivo .csv (geralmente em \"YouTube e YouTube Music/subscriptions/subscriptions.csv\", clique em IMPORTAR ARQUIVO abaixo e selecione o arquivo csv extraído</string>
<string name="import_soundcloud_instructions">Importe um perfil do SoundCloud digitando o URL ou seu ID:
\n7. [Se a importação do .zip falhar] Extraia o arquivo .csv (geralmente em \"YouTube e YouTube Music/subscriptions/subscriptions.csv\"), clique em IMPORTAR ARQUIVO abaixo e selecione o arquivo csv extraído</string>
<string name="import_soundcloud_instructions">Importar um perfil do SoundCloud digitando o URL ou seu ID:
\n
\n1. Ative o \"modo desktop\" em um navegador (o site não está disponível em aparelhos celulares)
\n1. Ative o \"Modo desktop (computador)\" em um navegador da Web (o site não está disponível para dispositivos móveis)
\n2. Acesse este URL: %1$s
\n3. Faça login quando solicitado
\n4. Copie o URL do perfil que você foi redirecionado.</string>
\n4. Copie o URL do perfil para o qual você foi redirecionado.</string>
<string name="import_soundcloud_instructions_hint">seuID, soundcloud.com/seuid</string>
<string name="import_network_expensive_warning">Tenha em mente que esta operação poderá consumir muitos dados.
\n
\nVocê deseja continuar\?</string>
<string name="thumbnail_cache_wipe_complete_notice">Cache de imagens limpo</string>
<string name="thumbnail_cache_wipe_complete_notice">Cache de imagens removidos</string>
<string name="metadata_cache_wipe_title">Limpar cache de metadados</string>
<string name="metadata_cache_wipe_summary">Remove todos os dados de páginas em cache</string>
<string name="metadata_cache_wipe_complete_notice">Cache de metadados limpo</string>
<string name="playback_speed_control">Controles de velocidade de reprodução</string>
<string name="metadata_cache_wipe_complete_notice">Cache de metadados removidos</string>
<string name="playback_speed_control">Controles para velocidade de reprodução</string>
<string name="playback_tempo">Velocidade</string>
<string name="playback_pitch">Afinação</string>
<string name="unhook_checkbox">Desvincular (pode causar distorção)</string>
<string name="preferred_open_action_settings_title">Ação de \'abrir\' preferida</string>
<string name="preferred_open_action_settings_summary">Ação padrão ao abrir conteúdo — %s</string>
<string name="no_streams_available_download">Nenhuma transmissão disponível para baixar</string>
<string name="no_streams_available_download">Nenhum vídeo disponível para download</string>
<string name="drawer_open">Abrir gaveta</string>
<string name="drawer_close">Fechar gaveta</string>
<string name="caption_setting_title">Legendas</string>
<string name="caption_setting_description">Mudar tamanho da legenda e estilos de plano de fundo. Requer reiniciar o aplicativo para ter efeito</string>
<string name="clear_views_history_title">Excluir histórico de vídeo</string>
<string name="clear_views_history_summary">Exclui o histórico de transmissões exibidas e as posições de reprodução</string>
<string name="delete_view_history_alert">Excluir todo o histórico de vídeo\?</string>
<string name="watch_history_deleted">Histórico de vídeos excluído</string>
<string name="clear_search_history_title">Excluir histórico de pesquisa</string>
<string name="clear_search_history_summary">Exclui o histórico de palavras-chave de pesquisa</string>
<string name="delete_search_history_alert">Excluir todo o histórico de pesquisa\?</string>
<string name="search_history_deleted">Histórico de busca limpo</string>
<string name="clear_views_history_title">Limpar histórico de exibição</string>
<string name="clear_views_history_summary">Remove histórico de vídeos assistidos e as posições de reprodução</string>
<string name="delete_view_history_alert">Remover todo o histórico de exibição?</string>
<string name="watch_history_deleted">Histórico de exibição removido</string>
<string name="clear_search_history_title">Remover histórico de pesquisas</string>
<string name="clear_search_history_summary">Remove histórico de pesquisas</string>
<string name="delete_search_history_alert">Remover todo histórico de pesquisas?</string>
<string name="search_history_deleted">Histórico de pesquisa removido</string>
<string name="one_item_deleted">1 item excluído.</string>
<string name="app_license">NewPipe é um copyleft de software livre: Você pode usar, estudar, compartilhar e melhorar a seu gosto. Especificamente você pode redistribuir e/ou modificá-lo sob os termos da GNU General Public License como publicado pela Fundação de Software Livre, na versão 3 da Licença, ou (a seu critério) qualquer versão posterior.</string>
<string name="import_settings">Você também quer importar as configurações?</string>
<string name="privacy_policy_title">Política de privacidade do NewPipe</string>
<string name="privacy_policy_encouragement">O projeto NewPipe leva sua privacidade muito a sério. Por isso, o aplicativo não coleta nenhum dado sem seu consentimento.
\nA política de privacidade do NewPipe explica em detalhes quais dados são envidados e salvos quando você manda um relatório de erro.</string>
<string name="read_privacy_policy">Ler a política de privacidade</string>
<string name="read_privacy_policy">Ver política de privacidade</string>
<string name="start_accept_privacy_policy">A fim de cumprir com o Regulamento Geral sobre a Proteção de Dados da UE (RGPD), chamamos sua atenção para a política de privacidade do NewPipe. Por favor, leia com atenção.
\nVocê deve aceitá-la para nos enviar o relatório de erros.</string>
<string name="accept">Aceitar</string>
<string name="decline">Recusar</string>
<string name="limit_data_usage_none_description">Ilimitado</string>
<string name="limit_mobile_data_usage_title">Limitar a resolução quando estiver usando dados móveis</string>
<string name="minimize_on_exit_title">Minimizar ao trocar entre aplicativos</string>
<string name="minimize_on_exit_summary">Ação ao mudar para outro aplicativo a partir do reprodutor de vídeo principal — %s</string>
<string name="limit_mobile_data_usage_title">Limitar resolução de vídeos ao usar dados móveis</string>
<string name="minimize_on_exit_title">Minimizar ao mudar de aplicativos</string>
<string name="minimize_on_exit_summary">Ação ao mudar de aplicativo a partir do player principal - %s</string>
<string name="minimize_on_exit_none_description">Nenhum</string>
<string name="minimize_on_exit_background_description">Minimizar para segundo plano</string>
<string name="minimize_on_exit_popup_description">Minimizar para reprodutor Popup</string>
<string name="minimize_on_exit_background_description">Minimizar reprodução para o modo de segundo plano</string>
<string name="minimize_on_exit_popup_description">Minimizar reprodução para o modo Popup</string>
<string name="skip_silence_checkbox">Avançar durante o silêncio</string>
<string name="playback_step">Passo</string>
<string name="playback_reset">Redefinir</string>
<string name="channels">Canais</string>
<string name="playlists">Listas de reprodução</string>
<string name="playlists">Playlists</string>
<string name="tracks">Faixas</string>
<string name="users">Usuários</string>
<string name="unsubscribe">Cancelar inscrição</string>
<string name="tab_choose">Selecionar aba</string>
<string name="settings_category_debug_title">Debug</string>
<string name="tab_choose">Escolha a guia</string>
<string name="settings_category_debug_title">Depuração</string>
<string name="settings_category_updates_title">Atualizações</string>
<string name="events">Eventos</string>
<string name="file_deleted">Arquivo excluído</string>
@ -341,26 +341,26 @@
<string name="app_update_notification_channel_description">Notificações para novas versões do NewPipe</string>
<string name="download_to_sdcard_error_title">Armazenamento externo indisponível</string>
<string name="download_to_sdcard_error_message">Não é possível baixar para o cartão SD externo. Redefinir o local da pasta de download\?</string>
<string name="saved_tabs_invalid_json">Não foi possível carregar as abas salvas, carregando as abas padrão</string>
<string name="restore_defaults">Restaurar padrões</string>
<string name="restore_defaults_confirmation">Deseja restaurar padrões\?</string>
<string name="saved_tabs_invalid_json">Não foi possível ler as guias salvas, portanto, usamos as guias padrão</string>
<string name="restore_defaults">Restaurar configurações</string>
<string name="restore_defaults_confirmation">Deseja restaurar os padrões?</string>
<string name="subscribers_count_not_available">Número de inscritos indisponível</string>
<string name="main_page_content_summary">Que abas são visíveis na página inicial</string>
<string name="main_page_content_summary">Quais guias são exibidas na página inicial</string>
<string name="conferences">Conferências</string>
<string name="updates_setting_title">Atualizações</string>
<string name="updates_setting_description">Notificar quando uma nova versão do aplicativo estiver disponível</string>
<string name="list_view_mode">Modo de exibição em lista</string>
<string name="list_view_mode">Modo de exibição da lista</string>
<string name="list">Lista</string>
<string name="grid">Grade</string>
<string name="auto">Automático</string>
<string name="app_update_available_notification_title">Atualização do NewPipe disponível!</string>
<string name="app_update_available_notification_title">Uma atualização do NewPipe está disponível!</string>
<string name="missions_header_finished">Finalizado</string>
<string name="paused">pausado</string>
<string name="queued">na fila</string>
<string name="post_processing">pós-processamento</string>
<string name="enqueue">Fila</string>
<string name="enqueue">Colocar na fila</string>
<string name="permission_denied">Ação negada pelo sistema</string>
<string name="download_failed">O download falhou</string>
<string name="download_failed">Download falhou</string>
<string name="generate_unique_name">Gerar nome único</string>
<string name="overwrite">Sobrescrever</string>
<string name="overwrite_finished_warning">Um arquivo baixado com esse nome já existe</string>
@ -368,11 +368,11 @@
<string name="show_error">Mostrar erro</string>
<string name="error_file_creation">O arquivo não pode ser criado</string>
<string name="error_path_creation">A pasta de destino não pode ser criada</string>
<string name="error_ssl_exception">Uma conexão segura não pôde ser estabelecida</string>
<string name="error_unknown_host">O servidor não pôde ser encontrado</string>
<string name="error_ssl_exception">Não foi possível estabelecer uma conexão segura</string>
<string name="error_unknown_host">Não foi possível encontrar o servidor</string>
<string name="error_connect_host">Não foi possível se conectar ao servidor</string>
<string name="error_http_no_content">O servidor não envia dados</string>
<string name="error_http_unsupported_range">O servidor não aceita downloads em multi-thread, tente de novo com @string/msg_threads = 1</string>
<string name="error_http_unsupported_range">O servidor não aceita downloads multi-processo, tente novamente com @string/msg_threads = 1</string>
<string name="error_http_not_found">Não encontrado</string>
<string name="error_postprocessing_failed">Falha no pós-processamento</string>
<string name="stop">Parar</string>
@ -392,7 +392,7 @@
<string name="enable_playback_state_lists_title">Posições em listas</string>
<string name="enable_playback_state_lists_summary">Mostra indicadores de posição de reprodução em listas</string>
<string name="settings_category_clear_data_title">Excluir dados</string>
<string name="watch_history_states_deleted">Posições de reprodução limpas</string>
<string name="watch_history_states_deleted">Posições de reprodução removidas</string>
<string name="missing_file">Arquivo movido ou excluído</string>
<string name="overwrite_unrelated_warning">Já existe um arquivo com este nome</string>
<string name="overwrite_failed">O arquivo não pode ser sobrescrito</string>
@ -403,24 +403,24 @@
<string name="error_timeout">Tempo limite de conexão</string>
<string name="confirm_prompt">Excluir todo o histórico de downloads ou excluir todos os arquivos baixados\?</string>
<string name="enable_queue_limit">Limitar fila de downloads</string>
<string name="enable_queue_limit_desc">Faz downloads um de cada vez</string>
<string name="enable_queue_limit_desc">Permitir apenas um download de cada vez</string>
<string name="start_downloads">Iniciar downloads</string>
<string name="pause_downloads">Pausar downloads</string>
<string name="downloads_storage_ask_title">Perguntar onde salvar o arquivo</string>
<string name="downloads_storage_ask_summary">Você será questionado onde salvar cada download.
\nAtive o seletor de pasta do sistema (SAF) se você quiser baixar em um cartão SD externo</string>
<string name="downloads_storage_use_saf_title">Usar o seletor de pastas do sistema (SAF)</string>
<string name="downloads_storage_use_saf_summary">O \'Storage Access Framework\' permite baixar em um cartão SD externo</string>
<string name="clear_playback_states_title">Excluir posição das reproduções</string>
<string name="clear_playback_states_summary">Exclui todas as posições de reprodução</string>
<string name="delete_playback_states_alert">Excluir todas as posições de reprodução\?</string>
<string name="drawer_header_description">Alternar serviço, selecionados:</string>
<string name="default_kiosk_page_summary">Quiosque Padrão</string>
<string name="no_one_watching">Ninguém está vendo</string>
<string name="downloads_storage_use_saf_summary">A \"Estrutura de acesso ao armazenamento\" permite baixar em um cartão SD externo</string>
<string name="clear_playback_states_title">Remover posições de reprodução</string>
<string name="clear_playback_states_summary">Remove todas as posições de reprodução</string>
<string name="delete_playback_states_alert">Remover todas as posições de reprodução?</string>
<string name="drawer_header_description">Alternar serviço, atualmente selecionado:</string>
<string name="default_kiosk_page_summary">Kiosk padrão</string>
<string name="no_one_watching">Ninguém está assistindo</string>
<plurals name="watching">
<item quantity="one">%s assistindo</item>
<item quantity="many">%s assistindo</item>
<item quantity="other">%s estão vendo</item>
<item quantity="other">%s assistindo</item>
</plurals>
<string name="no_one_listening">Ninguém está ouvindo</string>
<plurals name="listening">
@ -429,14 +429,14 @@
<item quantity="other">%s ouvintes</item>
</plurals>
<string name="localization_changes_requires_app_restart">O idioma será alterado após reiniciar o aplicativo</string>
<string name="seek_duration_title">Duração do salto para avançar/retroceder</string>
<string name="peertube_instance_url_title">Instâncias do PeerTube</string>
<string name="peertube_instance_url_summary">Escolha suas instâncias do PeerTube favoritas</string>
<string name="seek_duration_title">Duração de avanço/retrocesso rápido</string>
<string name="peertube_instance_url_title">Instâncias PeerTube</string>
<string name="peertube_instance_url_summary">Selecione suas instâncias favoritas do PeerTube</string>
<string name="peertube_instance_url_help">Encontre as instâncias que gosta em %s</string>
<string name="peertube_instance_add_title">Adicionar instância</string>
<string name="peertube_instance_add_help">Insira o URL da instância</string>
<string name="peertube_instance_add_fail">Erro ao validar a instância</string>
<string name="peertube_instance_add_https_only">Apenas os URL HTTPS são suportados</string>
<string name="peertube_instance_add_https_only">Somente URL HTTPS são compatíveis</string>
<string name="peertube_instance_add_exists">A instância já existe</string>
<string name="local">Local</string>
<string name="recently_added">Adicionado recentemente</string>
@ -447,7 +447,7 @@
<string name="choose_instance_prompt">Escolha uma instância</string>
<string name="clear_download_history">Limpar histórico de downloads</string>
<string name="delete_downloaded_files">Excluir arquivos baixados</string>
<string name="permission_display_over_apps">Dar permissão para mostrar por cima de outros aplicativos</string>
<string name="permission_display_over_apps">Obter permissão para exibir sobre outros aplicativos</string>
<string name="app_language_title">Idioma do aplicativo</string>
<string name="systems_language">Padrão do sistema</string>
<string name="subtitle_activity_recaptcha">Toque em \"Pronto\" ao resolver</string>
@ -521,34 +521,34 @@
<string name="restricted_video">Este vídeo tem restrição de idade.
\n
\nAtive \"%1$s\" nas configurações se quiser vê-lo.</string>
<string name="remove_watched_popup_yes_and_partially_watched_videos">Sim, e vídeos parcialmente vistos</string>
<string name="remove_watched_popup_warning">Os vídeos que foram vistos antes e depois de terem sidos adicionados à lista de reprodução serão removidos.
<string name="remove_watched_popup_yes_and_partially_watched_videos">Sim, e vídeos parcialmente assistidos</string>
<string name="remove_watched_popup_warning">Os vídeos que foram assistidos antes e depois de terem sidos adicionados à playlist serão removidos.
\nTem certeza? Esta ação não pode ser desfeita!</string>
<string name="remove_watched_popup_title">Remover vídeos vistos\?</string>
<string name="remove_watched">Remover vistos</string>
<string name="remove_watched_popup_title">Remover vídeos assistidos?</string>
<string name="remove_watched">Remover assistidos</string>
<string name="show_original_time_ago_summary">Textos originais dos serviços serão visíveis nos itens de transmissão</string>
<string name="show_original_time_ago_title">Mostrar tempo original nos itens</string>
<string name="youtube_restricted_mode_enabled_title">Ativar o \"Modo Restrito\" do YouTube</string>
<string name="video_detail_by">Por %s</string>
<string name="channel_created_by">Criado por %s</string>
<string name="detail_sub_channel_thumbnail_view_description">Miniatura do avatar do canal</string>
<string name="detail_sub_channel_thumbnail_view_description">Foto de perfil do canal</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Mostrar apenas inscrições não agrupadas</string>
<string name="search_showing_result_for">Mostrando resultados para: %s</string>
<string name="no_playlist_bookmarked_yet">Ainda não há listas de reprodução favoritas</string>
<string name="playlist_page_summary">Página da lista de reprodução</string>
<string name="select_a_playlist">Selecione uma lista de reprodução</string>
<string name="error_report_open_github_notice">Por favor verifique se uma issue discutindo este problema já existe. Ao criar tickets duplicados, você tira de nós um tempo no qual poderíamos estar usando para corrigir um bug real.</string>
<string name="no_playlist_bookmarked_yet">Ainda não há playlist favoritas</string>
<string name="playlist_page_summary">Página da playlist</string>
<string name="select_a_playlist">Selecione uma playlist</string>
<string name="error_report_open_github_notice">Verifique se o erro já foi informado. Ao informar erros duplicados, você nos toma o tempo que poderíamos dedicar a outras correções de erros.</string>
<string name="error_report_open_issue_button_text">Reporte no GitHub</string>
<string name="copy_for_github">Copiar relatório formatado</string>
<string name="never">Nunca</string>
<string name="wifi_only">Apenas no Wi-Fi</string>
<string name="wifi_only">Apenas em Wi-Fi</string>
<string name="autoplay_summary">Iniciar reprodução automaticamente — %s</string>
<string name="title_activity_play_queue">Reproduzir fila</string>
<string name="title_activity_play_queue">Fila de reprodução</string>
<string name="unsupported_url_dialog_message">Não foi possível reconhecer a URL. Abrir com outro aplicativo\?</string>
<string name="auto_queue_toggle">Pôr na fila automaticamente</string>
<string name="clear_queue_confirmation_description">A fila do reprodutor ativo será substituída</string>
<string name="clear_queue_confirmation_summary">Mudar de um reprodutor de vídeo para outro pode substituir sua fila</string>
<string name="clear_queue_confirmation_title">Pedir confirmação antes de limpar uma fila</string>
<string name="clear_queue_confirmation_description">A fila de reprodução atual será substituída</string>
<string name="clear_queue_confirmation_summary">Mudar de um player para outro pode substituir sua fila</string>
<string name="clear_queue_confirmation_title">Pedir confirmação antes de limpar a fila</string>
<string name="notification_action_shuffle">Aleatório</string>
<string name="notification_action_buffering">Carregando</string>
<string name="notification_action_nothing">Nada</string>
@ -560,8 +560,8 @@
<string name="notification_action_2_title">Terceiro botão de ação</string>
<string name="notification_action_1_title">Segundo botão de ação</string>
<string name="notification_action_0_title">Primeiro botão de ação</string>
<string name="notification_scale_to_square_image_summary">Cortar a miniatura do vídeo mostrada na notificação da proporção 16:9 para 1:1</string>
<string name="notification_scale_to_square_image_title">Cortar a miniatura para a proporção de 1:1</string>
<string name="notification_scale_to_square_image_summary">Ajustar miniatura de vídeo mostrada na notificação de 16:9 para 1:1</string>
<string name="notification_scale_to_square_image_title">Ajustar miniatura para a proporção de 1:1</string>
<string name="show_memory_leaks">Mostrar vazamentos de memória</string>
<string name="enqueued">Na fila</string>
<string name="enqueue_stream">Pôr na fila</string>
@ -575,8 +575,8 @@
<string name="show_thumbnail_summary">Usar miniatura para o plano de fundo da tela de bloqueio e notificações</string>
<string name="show_thumbnail_title">Mostrar miniatura</string>
<string name="msg_calculating_hash">Calculando hash</string>
<string name="hash_channel_description">Notificações para o progresso do hash do vídeo</string>
<string name="hash_channel_name">Notificação de hash do vídeo</string>
<string name="hash_channel_description">Notificações sobre o progresso do hashing de vídeo</string>
<string name="hash_channel_name">Notificar hash de vídeo</string>
<string name="show_meta_info_summary">Desative para ocultar as caixas de informações de metadados com informações adicionais sobre o criador, conteúdo da transmissão ou uma solicitação de pesquisa</string>
<string name="show_meta_info_title">Mostrar informação de metadados</string>
<string name="recent">Recente</string>
@ -605,8 +605,8 @@
<string name="auto_device_theme_title">Automático (tema do dispositivo)</string>
<string name="night_theme_title">Tema noturno</string>
<string name="show_channel_details">Mostrar detalhes do canal</string>
<string name="disable_media_tunneling_summary">Desative o tunelamento de mídia se aparecer uma tela preta ou se tiver engasgos durante a reprodução do vídeo.</string>
<string name="disable_media_tunneling_title">Desativar tunelamento de mídia</string>
<string name="disable_media_tunneling_summary">Desative o túnel de mídia se aparecer uma tela preta ou se tiver travamento durante a reprodução do vídeo.</string>
<string name="disable_media_tunneling_title">Desativar túnel de mídia</string>
<string name="metadata_privacy_internal">Interno</string>
<string name="metadata_privacy_private">Privado</string>
<string name="metadata_privacy_unlisted">Não Listado</string>
@ -631,52 +631,52 @@
\nDeseja cancelar a inscrição neste canal\?</string>
<string name="feed_load_error_account_info">Não foi possível carregar o feed para \'%s\'.</string>
<string name="feed_load_error">Erro ao carregar o feed</string>
<string name="downloads_storage_use_saf_summary_api_29">O \'Storage Access Framework\' é compatível apenas com versões a partir do Android 10</string>
<string name="downloads_storage_use_saf_summary_api_29">A \"Estrutura de acesso ao armazenamento\" é compatível apenas com versões a partir do Android 10</string>
<string name="downloads_storage_ask_summary_no_saf_notice">Você será questionado onde salvar cada download</string>
<string name="no_dir_yet">Nenhuma pasta de download definida ainda, escolha a pasta de download padrão agora</string>
<string name="off">Desligado</string>
<string name="on">Ligado</string>
<string name="off">Desativado</string>
<string name="on">Ativado</string>
<string name="tablet_mode_title">Modo tablet</string>
<string name="dont_show">Não mostrar</string>
<string name="low_quality_smaller">Baixa qualidade (menor)</string>
<string name="high_quality_larger">Alta qualidade (maior)</string>
<string name="low_quality_smaller">Baixa qualidade (pior)</string>
<string name="high_quality_larger">Alta qualidade (melhor)</string>
<string name="seekbar_preview_thumbnail_title">Pré visualização da miniatura da barra de busca</string>
<string name="comments_are_disabled">Os comentários estão desabilitados</string>
<string name="mark_as_watched">Marcar como visto</string>
<string name="mark_as_watched">Marcar como assistido</string>
<string name="detail_heart_img_view_description">Curtido pelo criador</string>
<string name="show_image_indicators_summary">Exibir fitas coloridas no topo das imagens indicando sua fonte: vermelho para rede, azul para disco e verde para memória</string>
<plurals name="deleted_downloads_toast">
<item quantity="one">%1$s download apagado</item>
<item quantity="many">%1$s downloads apagados</item>
<item quantity="other">%1$s downloads apagados</item>
<item quantity="one">%1$s download excluído</item>
<item quantity="many">%1$s downloads excluídos</item>
<item quantity="other">%1$s downloads excluídos</item>
</plurals>
<plurals name="download_finished_notification">
<item quantity="one">%s download concluído</item>
<item quantity="many">%s downloads concluídos</item>
<item quantity="other">%s downloads concluídos</item>
</plurals>
<string name="show_image_indicators_title">Exibir indicadores com imagem</string>
<string name="show_image_indicators_title">Mostrar indicadores de imagem</string>
<string name="enqueued_next">Adicionado na próxima posição da fila</string>
<string name="enqueue_next_stream">Enfileira a próxima</string>
<string name="main_page_content_swipe_remove">Deslize items para remove-los</string>
<string name="start_main_player_fullscreen_summary">Não inicia os vídeos no reprodutor reduzido, mas muda direto para o modo de tela cheia, se a rotação automática estiver travada. Você ainda consegue acessar o reprodutor reduzido saindo da tela cheia</string>
<string name="start_main_player_fullscreen_title">Iniciar o reprodutor principal em tela cheia</string>
<string name="main_page_content_swipe_remove">Deslize os itens para remove-los</string>
<string name="start_main_player_fullscreen_summary">Não inicie os vídeos no mini player, mas vá diretamente para o modo de tela cheia, se a rotação automática estiver bloqueada. Você ainda pode acessar o mini player saindo da tela cheia</string>
<string name="start_main_player_fullscreen_title">Iniciar player principal em tela cheia</string>
<string name="remote_search_suggestions">Sugestões de busca remotas</string>
<string name="local_search_suggestions">Sugestões de busca locais</string>
<string name="processing_may_take_a_moment">Processando… Pode demorar um pouco</string>
<string name="check_for_updates">Procurar por atualizações</string>
<string name="manual_update_description">Procurar manualmente por novas versões</string>
<string name="checking_updates_toast">Procurando por atualizações…</string>
<string name="crash_the_player">Travar o reprodutor de vídeo</string>
<string name="show_crash_the_player_title">Mostrar \"Fechar o reprodutor\"</string>
<string name="show_crash_the_player_summary">Mostra uma opção de travamento ao usar o reprodutor</string>
<string name="check_for_updates">Buscar atualizações</string>
<string name="manual_update_description">Verificar manualmente se há novas versões</string>
<string name="checking_updates_toast">Buscando atualizações…</string>
<string name="crash_the_player">Travar reprodução</string>
<string name="show_crash_the_player_title">Mostrar \"Travar reprodução\"</string>
<string name="show_crash_the_player_summary">Mostra uma opção para travar a reprodução</string>
<string name="feed_new_items">Novos itens do feed</string>
<string name="error_report_channel_name">Notificação de relatório de erro</string>
<string name="error_report_channel_description">Notificações para reportar erros</string>
<string name="error_report_notification_title">O NewPipe encontrou um erro, toque para reportar</string>
<string name="error_report_notification_title">O NewPipe encontrou um erro, toque para relatar</string>
<string name="create_error_notification">Crie uma notificação de erro</string>
<string name="no_appropriate_file_manager_message_android_10">Nenhum gerenciador de arquivos apropriado foi encontrado para esta ação.
\nInstale um gerenciador de arquivos compatível com o Storage Access Framework</string>
\nInstale um gerenciador de arquivos compatível com a \"Estrutura de acesso ao armazenamento\"</string>
<string name="error_report_notification_toast">Ocorreu um erro, consulte a notificação</string>
<string name="show_error_snackbar">Mostrar um snackbar de erro</string>
<string name="no_appropriate_file_manager_message">Nenhum gerenciador de arquivos apropriado foi encontrado para esta ação.
@ -684,36 +684,36 @@
<string name="detail_pinned_comment_view_description">Comentário fixado</string>
<string name="leak_canary_not_available">O LeakCanary não está disponível</string>
<string name="progressive_load_interval_exoplayer_default">ExoPlayer padrão</string>
<string name="settings_category_player_notification_title">Notificação do reprodutor</string>
<string name="settings_category_player_notification_summary">Configurar a notificação da reprodução da transmissão atual</string>
<string name="settings_category_player_notification_title">Notificação de reprodução</string>
<string name="settings_category_player_notification_summary">Configurar notificação da reprodução do vídeo atual</string>
<string name="notifications">Notificações</string>
<string name="streams_notification_channel_name">Novas transmissões</string>
<string name="streams_notification_channel_description">Notificações sobre novas transmissões para inscrições</string>
<string name="enable_streams_notifications_title">Notificações de novas transmissões</string>
<string name="enable_streams_notifications_summary">Notificar sobre novas transmissões de inscrições</string>
<string name="streams_notification_channel_name">Novos vídeos</string>
<string name="streams_notification_channel_description">Notificações sobre novos vídeos de inscrições</string>
<string name="enable_streams_notifications_title">Notificações sobre novos vídeos</string>
<string name="enable_streams_notifications_summary">Notificar sobre novos vídeos de inscrições</string>
<string name="streams_notifications_interval_title">Frequência de verificação</string>
<string name="any_network">Nenhuma rede</string>
<string name="delete_downloaded_files_confirm">Excluir todos os arquivos baixados do disco\?</string>
<string name="delete_downloaded_files_confirm">Excluir todos os arquivos baixados?</string>
<string name="you_successfully_subscribed">Agora você se inscreveu neste canal</string>
<string name="toggle_all">Alternar tudo</string>
<string name="enumeration_comma">,</string>
<string name="loading_stream_details">Carregando detalhes da transmissão…</string>
<plurals name="new_streams">
<item quantity="one">%s nova transmissão</item>
<item quantity="many">%s novas transmissões</item>
<item quantity="other">%s novas transmissões</item>
<item quantity="one">%s novo vídeo</item>
<item quantity="many">%s novos vídeos</item>
<item quantity="other">%s novos vídeos</item>
</plurals>
<string name="check_new_streams">Verifica por novas transmissões</string>
<string name="check_new_streams">Buscar novos vídeos</string>
<string name="streams_notifications_network_title">Conexão de rede necessária</string>
<string name="notifications_disabled">As notificações estão desativadas</string>
<string name="get_notified">Seja notificado</string>
<string name="percent">Por cento</string>
<string name="semitone">Semitom</string>
<string name="selected_stream_external_player_not_supported">A transmissão selecionada não é compatível com reprodutores externos</string>
<string name="no_audio_streams_available_for_external_players">Nenhum transmissão de áudio está disponível para reprodutores externos</string>
<string name="streams_not_yet_supported_removed">Transmissões que ainda não são suportadas pelo baixador não são exibidos</string>
<string name="no_video_streams_available_for_external_players">Nenhum vídeo de transmissão está disponível para reprodutores externos</string>
<string name="select_quality_external_players">Selecione a qualidade para reprodutores externos</string>
<string name="selected_stream_external_player_not_supported">O vídeo selecionado não é compatível com players externos</string>
<string name="no_audio_streams_available_for_external_players">Nenhuma transmissão de áudio está disponível para players externos</string>
<string name="streams_not_yet_supported_removed">Os vídeos que ainda não são suportados pelo assistente de download não são exibidos</string>
<string name="no_video_streams_available_for_external_players">Nenhuma transmissão de vídeo está disponível para players externos</string>
<string name="select_quality_external_players">Selecione a qualidade para players externos</string>
<string name="unknown_format">Formato desconhecido</string>
<string name="unknown_quality">Qualidade desconhecida</string>
<string name="progressive_load_interval_title">Tamanho do intervalo de carregamento da reprodução</string>
@ -722,32 +722,32 @@
<string name="faq_title">Perguntas frequentes</string>
<string name="sort">Classificar</string>
<string name="fast_mode">Modo rápido</string>
<string name="import_subscriptions_hint">Importar ou exportar inscrições do menu de 3 pontos</string>
<string name="import_subscriptions_hint">Importar ou exportar inscrições no menu com 3 pontos</string>
<string name="app_update_available_notification_text">Toque para baixar %s</string>
<string name="app_update_unavailable_toast">Você está executando a versão mais recente do NewPipe</string>
<string name="app_update_unavailable_toast">Você já possui a atualização mais recente do NewPipe</string>
<string name="night_theme_available">Esta opção só está disponível se %s for selecionado para Tema</string>
<string name="unset_playlist_thumbnail">Desativar miniatura permanente</string>
<string name="card">Cartão</string>
<string name="msg_failed_to_copy">Falha ao copiar para a área de transferência</string>
<string name="playlist_add_stream_success_duplicate">Duplicata adicionada %d vez(es)</string>
<string name="duplicate_in_playlist">As listas de reprodução em cinza já contêm este item.</string>
<string name="duplicate_in_playlist">As playlists em cinza já contêm este item.</string>
<string name="ignore_hardware_media_buttons_title">Ignorar eventos de botão de mídia de hardware</string>
<string name="ignore_hardware_media_buttons_summary">Útil, por exemplo, se você estiver usando um fone de ouvido com botões físicos quebrados</string>
<string name="remove_duplicates">Remover duplicados</string>
<string name="remove_duplicates_title">Remover duplicados\?</string>
<string name="remove_duplicates_message">Deseja remover todos as transmissões duplicadas nesta lista de reprodução?</string>
<string name="feed_hide_streams_title">Mostrar as transmissões seguintes</string>
<string name="feed_show_hide_streams">Mostrar/ocultar transmissões</string>
<string name="remove_duplicates_message">Deseja remover todos os vídeos duplicados nesta playlist?</string>
<string name="feed_hide_streams_title">Mostrar próximos vídeos</string>
<string name="feed_show_hide_streams">Mostrar/ocultar vídeos</string>
<string name="feed_show_partially_watched">Parcialmente assistido</string>
<string name="feed_show_upcoming">Em breve</string>
<string name="feed_show_watched">Totalmente assistido</string>
<string name="left_gesture_control_summary">Escolha o gesto da mão esquerda da tela do reprodutor</string>
<string name="left_gesture_control_title">Ação do gesto esquerdo</string>
<string name="right_gesture_control_summary">Escolha o gesto da mão direita da tela do reprodutor</string>
<string name="left_gesture_control_summary">Escolha o gesto para a parte esquerda na tela de reprodução</string>
<string name="left_gesture_control_title">Ação para o gesto à esquerda</string>
<string name="right_gesture_control_summary">Escolha o gesto para a parte direita na tela de reprodução</string>
<string name="brightness">Brilho</string>
<string name="volume">Volume</string>
<string name="none">Nenhum</string>
<string name="right_gesture_control_title">Ação do gesto direito</string>
<string name="right_gesture_control_title">Ação para o gesto à direita</string>
<string name="progressive_load_interval_summary">Altere o tamanho do intervalo de carregamento (atualmente %s). Um valor menor pode acelerar o carregamento inicial do vídeo</string>
<string name="prefer_original_audio_title">Dar preferência ao áudio original</string>
<string name="prefer_original_audio_summary">Selecionar o áudio original e independentemente do idioma</string>
@ -755,69 +755,69 @@
<string name="prefer_descriptive_audio_summary">Selecionar um áudio com descrição para pessoas com dificuldades de visão, se disponível</string>
<string name="play_queue_audio_track">Áudio: %s</string>
<string name="audio_track">Faixa de áudio</string>
<string name="select_audio_track_external_players">Seleciona faixa de áudio para reprodutor externo</string>
<string name="select_audio_track_external_players">Selecione a faixa de áudio para players externo</string>
<string name="unknown_audio_track">Desconhecido</string>
<string name="settings_category_exoplayer_title">Configurações de ExoPlayer</string>
<string name="settings_category_exoplayer_summary">Gerenciar algumas configurações de ExoPlayer. É necessário reiniciar o reprodutor para aplicar as mudanças</string>
<string name="settings_category_exoplayer_title">Configurar ExoPlayer</string>
<string name="settings_category_exoplayer_summary">Gerenciar algumas configurações do ExoPlayer. É necessário reiniciar o player para aplicar as mudanças</string>
<string name="audio_track_name">%1$s %2$s</string>
<string name="audio_track_type_original">original</string>
<string name="audio_track_type_dubbed">dublado</string>
<string name="audio_track_type_descriptive">descritivo</string>
<string name="always_use_exoplayer_set_output_surface_workaround_summary">Esta solução alternativa libera os codificadores de vídeo quando ocorre uma alteração de superfície, no lugar de definir a superfície para o Codec diretamente. Já usado pelo ExoPlayer em alguns dispositivos com esse problema, essa configuração só tem efeito no Android 6 e superior
\n
\nAtivar esta opção pode evitar erros de reprodução ao alternar o reprodutor de vídeo atual ou alternar para tela cheia</string>
<string name="audio_track_present_in_video">Uma faixa de áudio já deve estar presente nesta transmissão</string>
<string name="use_exoplayer_decoder_fallback_title">Utilizar a contingência do decodificador do ExoPlayer</string>
<string name="always_use_exoplayer_set_output_surface_workaround_title">Sempre utilizar o configuração de saída de vídeo alternativa do ExoPlayer</string>
\nAtivar esta opção pode evitar erros de reprodução ao alternar o player de vídeo atual ou alternar para tela cheia</string>
<string name="audio_track_present_in_video">Uma faixa de áudio já deve estar presente neste vídeo</string>
<string name="use_exoplayer_decoder_fallback_title">Usar decodificador alternativo do ExoPlayer</string>
<string name="always_use_exoplayer_set_output_surface_workaround_title">Usar sempre a solução alternativa de configuração da superfície de saída de vídeo do ExoPlayer</string>
<string name="use_exoplayer_decoder_fallback_summary">Habilite essa opção se você tiver problemas de inicialização do decodificador, que retorna codificadores de baixa prioridade se o decodificador primário falhar. Isso pode resultar em pior desempenho de reprodução</string>
<string name="main_tabs_position_summary">Mova o seletor da aba principal para a parte inferior</string>
<string name="main_tabs_position_title">Posição das abas principais</string>
<string name="no_streams">Nenhuma transmissão</string>
<string name="main_tabs_position_summary">Mover o seletor da guia principal para a parte inferior</string>
<string name="main_tabs_position_title">Posição de guias principais</string>
<string name="no_streams">Nenhum conteúdo</string>
<string name="no_live_streams">Nenhuma transmissão ao vivo</string>
<string name="disable_media_tunneling_automatic_info">O tunelamento de mídia foi desabilitado por padrão em seu dispositivo porque seu modelo é conhecido por não suportá-lo.</string>
<string name="disable_media_tunneling_automatic_info">O túnel de mídia foi desabilitado por padrão em seu dispositivo porque seu modelo é conhecido por não suportá-lo.</string>
<string name="channel_tab_videos">Vídeos</string>
<string name="metadata_subscribers">Inscritos</string>
<string name="show_channel_tabs_summary">Quais guias são mostradas nas páginas do canal</string>
<string name="show_channel_tabs">Guias de canal</string>
<string name="show_channel_tabs_summary">Quais guias são mostradas na página do canal</string>
<string name="show_channel_tabs">Guias do canal</string>
<string name="channel_tab_shorts">Shorts</string>
<string name="loading_metadata_title">Carregando metadados…</string>
<string name="feed_fetch_channel_tabs">Buscar guias de canal</string>
<string name="channel_tab_about">Sobre</string>
<string name="channel_tab_albums">Álbuns</string>
<string name="feed_fetch_channel_tabs_summary">Guias a serem buscadas ao atualizar o feed. Esta opção não tem efeito se um canal for atualizado usando o modo rápido.</string>
<string name="channel_tab_playlists">Listas de reprodução</string>
<string name="channel_tab_playlists">Playlists</string>
<string name="channel_tab_tracks">Faixas</string>
<string name="channel_tab_channels">Canais</string>
<string name="channel_tab_livestreams">Ao vivo</string>
<string name="image_quality_title">Qualidade da imagem</string>
<string name="question_mark">\?</string>
<string name="share_playlist_with_list">Compartilhar lista URL</string>
<string name="share_playlist_with_titles">Compartilhar com Títulos</string>
<string name="share_playlist_with_list">Compartilhar URL</string>
<string name="share_playlist_with_titles">Compartilhar com título</string>
<string name="share_playlist_content_details">%1$s
\n%2$s</string>
<string name="toggle_screen_orientation">Alterna a orientação da tela</string>
<string name="toggle_screen_orientation">Alternar orientação da tela</string>
<string name="image_quality_low">Baixa qualidade</string>
<string name="toggle_fullscreen">Alternar tela cheia</string>
<string name="metadata_avatars">Avatares</string>
<string name="next_stream">Próxima transmissão</string>
<string name="metadata_subchannel_avatars">Avatares do subcanal</string>
<string name="open_play_queue">Abrir a fila de reprodução</string>
<string name="metadata_avatars">Fotos</string>
<string name="next_stream">Próxima vídeo</string>
<string name="metadata_subchannel_avatars">Fotos de perfil do subcanal</string>
<string name="open_play_queue">Abrir fila de reprodução</string>
<string name="image_quality_none">Não carregar imagens</string>
<string name="image_quality_high">Alta qualidade</string>
<string name="share_playlist">Compartilhar Lista de Reprodução</string>
<string name="share_playlist">Compartilhar playlist</string>
<string name="forward">Avançar</string>
<string name="rewind">Retroceder</string>
<string name="replay">Repete</string>
<string name="share_playlist_with_titles_message">Compartilhar lista de reprodução com detalhes como nome da lista de reprodução e títulos de vídeo ou como uma lista simples dos URL de vídeos</string>
<string name="replay">Repetir</string>
<string name="share_playlist_with_titles_message">Compartilhar playlist com detalhes como o nome da playlist e títulos de vídeo ou como uma lista simples dos URL de vídeos</string>
<string name="image_quality_medium">Qualidade média</string>
<string name="metadata_uploader_avatars">Avatares do carregador</string>
<string name="metadata_uploader_avatars">Fotos de perfil do autor</string>
<string name="video_details_list_item">- %1$s: %2$s</string>
<string name="image_quality_summary">Escolha a qualidade das imagens ou se deve carregá-las como estão, para reduzir o uso de dados e memória. Alterações limpam a memória e o cache de imagem no disco — %s</string>
<string name="image_quality_summary">Escolha a qualidade das imagens e se as imagens devem ser carregadas, para reduzir o uso de dados e memória. As alterações limpam o cache de imagens na memória e no disco - %s</string>
<string name="play">Reproduzir</string>
<string name="more_options">Mais opções</string>
<string name="metadata_thumbnails">Miniaturas</string>
<string name="duration">Duração</string>
<string name="previous_stream">Transmissão anterior</string>
<string name="previous_stream">Vídeo anterior</string>
<string name="metadata_banners">Banners</string>
<string name="show_more">Mostrar mais</string>
<string name="notification_actions_summary_android13">Edite cada ação de notificação abaixo tocando nela. As três primeiras ações (reproduzir/pausar, anterior e seguinte) são definidas pelo sistema e não podem ser personalizadas.</string>
@ -827,4 +827,15 @@
<item quantity="other">%s respostas</item>
</plurals>
<string name="show_less">Mostrar menos</string>
<string name="error_insufficient_storage">Não há espaço livre suficiente no dispositivo</string>
<string name="yes">Sim</string>
<string name="no">Não</string>
<string name="settings_category_backup_restore_title">Backup e restauração</string>
<string name="auto_update_check_description">O NewPipe pode verificar automaticamente se há novas versões de tempos em tempos e notificá-lo quando elas estiverem disponíveis.
\nDeseja ativar essa opção?</string>
<string name="reset_settings_title">Restaurar configurações</string>
<string name="reset_settings_summary">Restaurar todas as configurações para seus valores padrão</string>
<string name="reset_all_settings">A restauração de todas as configurações descartará todas as suas configurações preferidas e reiniciará o aplicativo.
\n
\nTem certeza de que deseja continuar?</string>
</resources>

View File

@ -827,4 +827,15 @@
<item quantity="other">%s respostas</item>
</plurals>
<string name="show_less">Mostrar menos</string>
<string name="auto_update_check_description">O NewPipe pode verificar automaticamente se há novas versões de tempos em tempos e notificá-lo quando elas estiverem disponíveis.
\nDeseja ativar essa opção?</string>
<string name="reset_settings_summary">Repor valores originais de todas as definições</string>
<string name="reset_all_settings">A restauração de todas as configurações descartará todas as suas configurações preferidas e reiniciará a app.
\n
\nTem certeza que deseja continuar?</string>
<string name="yes">Sim</string>
<string name="no">Não</string>
<string name="settings_category_backup_restore_title">Backup e restauro</string>
<string name="reset_settings_title">Repor definições</string>
<string name="error_insufficient_storage">Não há espaço suficiente no aparelho</string>
</resources>

View File

@ -827,4 +827,15 @@
</plurals>
<string name="show_less">Mostrar menos</string>
<string name="notification_actions_summary_android13">Edite cada ação de notificação abaixo a tocar nela. As três primeiras ações (reproduzir/pausa, anterior e seguinte) são definidas pelo sistema e não podem ser personalizadas.</string>
<string name="error_insufficient_storage">Não há espaço suficiente no dispositivo</string>
<string name="yes">Sim</string>
<string name="no">Não</string>
<string name="reset_settings_summary">Repor valores originais de todas as definições</string>
<string name="settings_category_backup_restore_title">Backup e restauro</string>
<string name="reset_settings_title">Repor definições</string>
<string name="reset_all_settings">A restauração de todas as configurações descartará todas as suas configurações preferidas e reiniciará a app.
\n
\nTem certeza que deseja continuar?</string>
<string name="auto_update_check_description">O NewPipe pode verificar automaticamente se há novas versões de tempos em tempos e notificá-lo quando elas estiverem disponíveis.
\nDeseja ativar essa opção?</string>
</resources>

View File

@ -765,15 +765,14 @@
<string name="toggle_fullscreen">Schimbați pe ecran complet</string>
<string name="feed_fetch_channel_tabs">Preluați filele canalului</string>
<string name="metadata_avatars">Avatare</string>
<string name="use_exoplayer_decoder_fallback_summary">Activați această opțiune dacă aveți probleme cu inițializarea decodorului care trece înapoi la decodoare cu prioritate mai scăzută dacă inițializarea decodoarelor principale eșuează. Asta poate duce la performanță de redare mai slabă decât atunci când se utilizează decodoarele principale.</string>
<string name="use_exoplayer_decoder_fallback_summary">Activați această opțiune dacă aveți probleme cu inițializarea decodorului care trece înapoi la decodoare cu prioritate mai scăzută dacă inițializarea decodoarelor principale eșuează. Asta poate duce la performanță de redare mai slabă decât atunci când se utilizează decodoarele principale</string>
<string name="right_gesture_control_title">Acțiunea gestului din dreapta</string>
<string name="audio_track_name">%1$s %2$s</string>
<string name="always_use_exoplayer_set_output_surface_workaround_title">Utilizați întotdeauna configurarația suprafeței de ieșire video din ExoPlayer ca soluție alternativă</string>
<string name="next_stream">Transmisia viitoare</string>
<string name="disable_media_tunneling_automatic_info">Tunelizarea media a fost dezactivată în mod implicit pe dispozitivul dumneavoastră deoarece se cunoaște despre acest model de dispozitiv că nu o suportă.</string>
<string name="metadata_subchannel_avatars">Avatarele subcanalelor</string>
<string name="always_use_exoplayer_set_output_surface_workaround_summary">Această soluție alternativă eliberează și reinstanțează codecurile video când se întamplă o schimbare a suprafeței, în loc de a seta suprafața pentru codec direct. Deja
\n folosită de ExoPlayer pe unele dispozitive cu această problemă, această setare are efect doar pe Android 6 sau mai mare
<string name="always_use_exoplayer_set_output_surface_workaround_summary">Această soluție alternativă eliberează și reinstanțează codecurile video când se întamplă o schimbare a suprafeței, în loc de a seta suprafața pentru codec direct. Deja folosită de ExoPlayer pe unele dispozitive cu această problemă, această setare are efect doar pe Android 6 sau mai mare
\n
\nActivarea acestei opțiuni poate preveni erorile de redare când se schimbă playerul video curent sau se trece pe ecran complet</string>
<string name="audio_track_present_in_video">O coloană sonoră ar trebui să fie deja prezentă în această transmisie</string>
@ -829,4 +828,14 @@
<string name="show_less">Arată mai puține</string>
<string name="channel_tab_tracks">Piste</string>
<string name="error_insufficient_storage">Nu este suficient spațiu liber pe dispozitiv</string>
<string name="settings_category_backup_restore_title">Backup și restabilire</string>
<string name="auto_update_check_description">NewPipe poate verifica automat pentru versiuni noi din când în când și te poate notifica când acestea sunt disponibile.
\nDoriți să activați acest lucru?</string>
<string name="reset_settings_summary">Resetează toate setările la valorile inițiale</string>
<string name="yes">Da</string>
<string name="no">Nu</string>
<string name="reset_settings_title">Resetează setări</string>
<string name="reset_all_settings">Resetarea tuturor setărilor va elimina toate setările tale preferate și va reporni aplicația.
\n
\nSigur doriți să continuați?</string>
</resources>

View File

@ -833,4 +833,11 @@
</plurals>
<string name="notification_actions_summary_android13">Отредактируйте каждое действие уведомления ниже, нажав на него. Первые три действия (воспроизведение/пауза, предыдущее и следующее) задаются системой и не подлежат настройке.</string>
<string name="error_insufficient_storage">Недостаточно свободного места на устройстве</string>
<string name="reset_settings_summary">Сбросить все настройки на их значения по умолчанию</string>
<string name="yes">Да</string>
<string name="no">Нет</string>
<string name="settings_category_backup_restore_title">Резервное копирование и восстановление</string>
<string name="reset_settings_title">Сбросить настройки</string>
<string name="auto_update_check_description">NewPipe может автоматически проверять наличие обновлений и уведомить вас, когда они будут доступны.
\nЖелаете включить эту функцию?</string>
</resources>

View File

@ -813,4 +813,15 @@
<string name="show_more">なーふぃんんーじゅん</string>
<string name="show_less">ひょうじいきらくすん</string>
<string name="notification_actions_summary_android13">いかぬちうちアクションタップしへんしゅうさびーん。さいしょぬみーちぬアクション (さいせい/いちじていし、めーんかい、ちぎんかい)ーシステムにゆってぃしっていさりてぃうぅい、カスタマイズすしぇーなやびらん。</string>
<string name="yes">はい</string>
<string name="auto_update_check_description">NewPipeーてぃんじちーがみーさるバージョンじちゃーてぃきんかいチェックしー、こうしんがのうないるとぅちうちさびーん。
\nゆうこうなさびーが</string>
<string name="error_insufficient_storage">デバイスぬあきゆういょうがふすくそーいびーん</string>
<string name="no">うぅーうぅー</string>
<string name="settings_category_backup_restore_title">バックアップとぅふくぎん</string>
<string name="reset_settings_title">しっていリセット</string>
<string name="reset_settings_summary">まじりぬしっていデフォルトじょうたいんかいリセットさびーん</string>
<string name="reset_all_settings">まじりぬしっていリセットしーねー、ゆーいるしんしっていぬまじりはちされい、アプリぬさいきちゃーさびーん。
\n
\nずっこうさびーが</string>
</resources>

View File

@ -539,7 +539,7 @@
<string name="clear_queue_confirmation_summary">Colende dae unu riproduidore a s\'àteru dias pòdere remplasare sa lista tua</string>
<string name="clear_queue_confirmation_title">Pedi una cunfirma in antis de iscantzellare una lista</string>
<string name="notification_action_shuffle">Òrdine casuale</string>
<string name="notification_actions_summary">Modìfica cada atzione de notìfica inoghe in suta incarchende·la. Ischerta·nde finas a tres de ammustrare in sa notìfica cumpata impreende sas casellas de controllu a destra</string>
<string name="notification_actions_summary">Modìfica cada atzione de notìfica inoghe in suta incarchende·la. Ischerta·nde finas a tres de ammustrare in sa notìfica cumpata impreende sas casellas de controllu a destra.</string>
<string name="notification_scale_to_square_image_summary">Sega sa miniadura ammustrada in sa notìfica dae su formadu in 16:9 a cussu 1:1</string>
<string name="notification_action_nothing">Nudda</string>
<string name="notification_action_buffering">Carrighende</string>
@ -806,4 +806,22 @@
<string name="channel_tab_channels">Canales</string>
<string name="previous_stream">Flussu antepostu</string>
<string name="channel_tab_livestreams">Diretas</string>
<string name="notification_actions_summary_android13">Modìfica cada atzione de notìfica inoghe in suta tochende·la. Sas primas tres atziones (riprodutzione/pàusa, antepostu e imbeniente) sunt impostadas dae su sistema e non si podent personalizare.</string>
<string name="error_insufficient_storage">Non b\'at ispàtziu lìberu bastante in su dispositivu</string>
<string name="show_less">Mustra de mancu</string>
<string name="auto_update_check_description">NewPipe podet chircare in automàticu versiones noas cada tantu e notificare·ti cando sunt a disponimentu.
\nLu boles abilitare?</string>
<string name="no">Nono</string>
<string name="settings_category_backup_restore_title">Còpia de seguresa e riprìstinu</string>
<plurals name="replies">
<item quantity="one">%s risposta</item>
<item quantity="other">%s rispostas</item>
</plurals>
<string name="show_more">Mustra de prus</string>
<string name="yes">Eja</string>
<string name="reset_settings_title">Reseta sas impostatziones</string>
<string name="reset_settings_summary">Reseta totu sas impostatziones a sos valores predefinidos issoro</string>
<string name="reset_all_settings">Resetende totu sas impostatziones as a iscartare totu sas impostatziones preferidas tuas e a torrare a allùghere s\'aplicatzione.
\n
\nSes seguru de bòlere sighire?</string>
</resources>

View File

@ -834,4 +834,8 @@
<string name="reset_all_settings">Ресетовање свих подешавања ће одбацити сва жељена подешавања и поново покренути апликацију.
\n
\nЖелите ли заиста да наставите?</string>
<string name="no">Не</string>
<string name="yes">Да</string>
<string name="auto_update_check_description">NewPipe може аутоматски да проверава да ли постоје нове верзије с времена на време и да вас обавести када буду доступне.
\nЖелите ли да омогућите ово?</string>
</resources>

View File

@ -814,4 +814,14 @@
<string name="show_less">Visa mindre</string>
<string name="notification_actions_summary_android13">Redigera varje aviseringsåtgärd nedan genom att trycka på den. De tre första åtgärderna (spela/pausa, föregående och nästa) är satta av systemet och kan inte ändras.</string>
<string name="error_insufficient_storage">Inte tillräckligt med ledigt utrymme på enheten</string>
<string name="no">Nej</string>
<string name="settings_category_backup_restore_title">Säkerhetskopiering och återställning</string>
<string name="yes">Ja</string>
<string name="auto_update_check_description">NewPipe kan automatiskt söka efter nya versioner då och då och meddela dig när de är tillgängliga.
\nVill du aktivera detta?</string>
<string name="reset_settings_title">Återställ inställningar</string>
<string name="reset_settings_summary">Återställ alla inställningar till deras standardvärden</string>
<string name="reset_all_settings">Om du återställer alla inställningar försvinner alla dina föredragna inställningar och appen startas om.
\n
\nÄr du säker på att du vill fortsätta?</string>
</resources>

View File

@ -833,4 +833,14 @@
</plurals>
<string name="show_less">Показати менше</string>
<string name="error_insufficient_storage">Недостатньо вільного простору на пристрої</string>
<string name="reset_settings_title">Скинути налаштування</string>
<string name="settings_category_backup_restore_title">Резервне копіювання і відновлення</string>
<string name="auto_update_check_description">NewPipe може час від часу автоматично перевіряти наявність нових версій і сповіщати вас про їх появу.
\nХочете увімкнути цю функцію?</string>
<string name="yes">Так</string>
<string name="no">Ні</string>
<string name="reset_settings_summary">Скинути всі налаштування до усталених значень</string>
<string name="reset_all_settings">Скидання всіх налаштувань призведе до скидання всіх вибраних вами налаштувань і перезапуску застосунку.
\n
\nВи впевнені, що хочете продовжити?</string>
</resources>

View File

@ -8,7 +8,7 @@
<string name="open_in_browser">Mở trong trình duyệt</string>
<string name="open_in_popup_mode">Mở trong chế độ bật lên</string>
<string name="share">Chia sẻ</string>
<string name="download">Tải về</string>
<string name="download">Tải xuống</string>
<string name="search">Tìm kiếm</string>
<string name="settings">Cài đặt</string>
<string name="did_you_mean">Ý bạn là \"%1$s\"\?</string>
@ -16,7 +16,7 @@
<string name="use_external_video_player_title">Sử dụng trình phát video bên ngoài</string>
<string name="use_external_video_player_summary">Loại bỏ âm thanh ở một số độ phân giải</string>
<string name="use_external_audio_player_title">Sử dụng trình phát âm thanh bên ngoài</string>
<string name="controls_popup_title">Trình phát nổi</string>
<string name="controls_popup_title">Bật lên</string>
<string name="download_path_title">Thư mục video tải về</string>
<string name="download_path_summary">Video đã tải về được lưu ở đây</string>
<string name="download_path_dialog_title">Chọn thư mục tải xuống cho các tệp video</string>
@ -43,7 +43,7 @@
<string name="popup_remember_size_pos_summary">Ghi nhớ kích thước và vị trí cuối cùng của cửa sổ bật lên</string>
<string name="show_search_suggestions_title">Đề xuất tìm kiếm</string>
<string name="show_search_suggestions_summary">Chọn các đề xuất để hiển thị khi tìm kiếm</string>
<string name="download_dialog_title">Tải về</string>
<string name="download_dialog_title">Tải xuống</string>
<string name="show_next_and_similar_title">Hiện các video \"Tiếp theo\" và \"Tương tự\"</string>
<string name="unsupported_url">URL không hỗ trợ</string>
<string name="settings_category_appearance_title">Vẻ ngoài</string>
@ -105,12 +105,12 @@
<string name="title_activity_about">Giới thiệu về NewPipe</string>
<string name="title_licenses">Giấy phép của bên thứ ba</string>
<string name="copyright" formatted="true">© %1$s bởi %2$s dưới %3$s</string>
<string name="tab_about">Thông tin &amp; FAQ</string>
<string name="tab_about">Giới thiệu &amp; Câu hỏi thường gặp</string>
<string name="tab_licenses">Giấy phép</string>
<string name="app_description">Phát trực tuyến nhẹ tự do trên Android.</string>
<string name="view_on_github">Xem trên GitHub</string>
<string name="app_license_title">Giấy phép của NewPipe</string>
<string name="contribution_encouragement">Sự đóng góp của bạn luôn được hoan nghênh kể cả khi bạn dịch, thay đổi giao diện, dọn code, thêm tính năng hay thay đổi những thứ khác, sự giúp đỡ của bạn vẫn đáng được trân trọng. Bạn càng làm nhiều, ứng dụng này sẽ càng tốt hơn bao giờ hết !</string>
<string name="contribution_encouragement">Cho dù bạn có ý tưởng về: dịch thuật, thay đổi thiết kế, dọn mã hoặc thay đổi mã thực sự nhiều— sự trợ giúp luôn được hoan nghênh. Làm càng nhiều thì càng tốt!</string>
<string name="read_full_license">Đọc giấy phép</string>
<string name="contribution_title">Đóng góp</string>
<string name="content_language_title">Ngôn ngữ nội dung ưu tiên</string>
@ -134,7 +134,7 @@
<string name="use_inexact_seek_summary">Tua ít chính xác cho phép trình phát giảm độ chính xác để tua tới vị trí nhanh hơn. Tua khoảng 5, 15 hoặc 25 giây không hoạt động với điều này</string>
<string name="thumbnail_cache_wipe_complete_notice">Đã xóa bộ nhớ cache hình ảnh</string>
<string name="metadata_cache_wipe_title">Xóa sạch siêu dữ liệu đã lưu đệm</string>
<string name="metadata_cache_wipe_summary">Xóa bỏ mọi dữ liệu trang web đã lưu đệm</string>
<string name="metadata_cache_wipe_summary">Xóa tất cả dữ liệu trang web được lưu trong bộ nhớ cache</string>
<string name="metadata_cache_wipe_complete_notice">Đã xóa bộ nhớ cache siêu dữ liệu</string>
<string name="auto_queue_title">Tự động xếp hàng luồng phát tiếp theo</string>
<string name="auto_queue_summary">Tiếp tục hàng đợi (không lặp lại) bằng cách thêm một luồng phát liên quan</string>
@ -212,9 +212,9 @@
<string name="settings_file_replacement_character_title">Ký tự thay thế</string>
<string name="charset_letters_and_digits">Chỉ chữ cái và chữ số</string>
<string name="charset_most_special_characters">Hầu hết các ký tự đặc biệt</string>
<string name="donation_title">Đóng góp</string>
<string name="donation_encouragement">NewPipe được phát triển bởi các tình nguyện viên dành thời gian và tâm huyết của mình để mang lại cho bạn trải nghiệm tốt nhất. Đóng góp một chút xiền để giúp chúng tôi làm NewPipe tốt hơn nữa (Nếu bạn muốn).</string>
<string name="give_back">Đôn Nét</string>
<string name="donation_title">Quyên tặng</string>
<string name="donation_encouragement">NewPipe được phát triển bởi các tình nguyện viên dành thời gian rảnh rỗi để mang lại cho bạn trải nghiệm người dùng tốt nhất. Hãy đền đáp để giúp các nhà phát triển làm cho NewPipe thậm chí còn tốt hơn nữa trong khi họ thưởng thức một tách cà phê.</string>
<string name="give_back">Đền đáp</string>
<string name="website_title">Trang web</string>
<string name="website_encouragement">Truy cập website chính thức của NewPipe để biết thêm thông tin và tin tức.</string>
<string name="privacy_policy_title">Chính sách bảo mật của NewPipe</string>
@ -283,7 +283,7 @@
<string name="import_from">Nhập từ</string>
<string name="export_to">Xuất sang</string>
<string name="import_ongoing">Đang nhập…</string>
<string name="export_ongoing">Đang xuất </string>
<string name="export_ongoing">Đang xuất…</string>
<string name="import_file_title">Nhập tệp</string>
<string name="previous_export">Xuất trước</string>
<string name="subscriptions_import_unsuccessful">Không thể nhập đăng ký</string>
@ -310,7 +310,7 @@
<string name="playback_tempo">Tốc độ</string>
<string name="playback_pitch">Độ cao</string>
<string name="unhook_checkbox">Bỏ gắn (có thể gây méo)</string>
<string name="skip_silence_checkbox">Tua nhanh trong im lặng</string>
<string name="skip_silence_checkbox">Chuyển nhanh qua khoảng lặng</string>
<string name="playback_step">Bước</string>
<string name="playback_reset">Đặt lại</string>
<string name="start_accept_privacy_policy">Để tuân thủ Quy định bảo vệ dữ liệu chung của châu Âu (GDPR), chúng tôi sẽ thu hút sự chú ý của bạn đến chính sách bảo mật của NewPipe. Vui lòng đọc kỹ.
@ -318,7 +318,7 @@
<string name="accept">Chấp nhận</string>
<string name="decline">Từ chối</string>
<string name="limit_data_usage_none_description">Không giới hạn</string>
<string name="limit_mobile_data_usage_title">Giới hạn độ phân giải khi sử dụng 3G, 4G</string>
<string name="limit_mobile_data_usage_title">Giới hạn độ phân giải khi sử dụng dữ liệu di động</string>
<string name="minimize_on_exit_title">Thu nhỏ khi chuyển qua ứng dụng khác</string>
<string name="minimize_on_exit_summary">Hành động khi chuyển sang ứng dụng khác từ trình phát video chính — %s</string>
<string name="minimize_on_exit_none_description">Không</string>
@ -353,7 +353,7 @@
<string name="post_processing">đang xử lý</string>
<string name="enqueue">Xếp hàng</string>
<string name="permission_denied">Thao tác bị từ chối bởi hệ thống</string>
<string name="download_failed">Tải về không thành công</string>
<string name="download_failed">Tải xuống thất bại</string>
<string name="generate_unique_name">Tạo tên riêng biệt</string>
<string name="overwrite">Ghi đè</string>
<string name="overwrite_finished_warning">Có một tệp đã tải về trùng tên</string>
@ -426,10 +426,10 @@
<item quantity="other">%d giây</item>
</plurals>
<string name="remove_watched_popup_yes_and_partially_watched_videos">Có, và video đã xem một phần</string>
<string name="remove_watched_popup_warning">Những video đã xem trước và sau khi thêm vào danh sách phát sẽ bị xóa.
<string name="remove_watched_popup_warning">Những video đã xem trước và sau khi thêm vào danh sách phát sẽ bị loại bỏ.
\nBạn có chắc không? Điều này không thể được hoàn tác!</string>
<string name="remove_watched_popup_title">Xóa video đã xem?</string>
<string name="remove_watched">Xóa đã xem</string>
<string name="remove_watched_popup_title">Xóa các video đã xem?</string>
<string name="remove_watched">Loại bỏ đã xem</string>
<string name="systems_language">Mặc định hệ thống</string>
<string name="app_language_title">Ngôn ngữ ứng dụng</string>
<string name="downloads_storage_use_saf_summary">\'Khung truy cập lưu trữ\' cho phép tải xuống một thẻ SD bên ngoài</string>
@ -563,7 +563,7 @@
<string name="comments_tab_description">Bình luận</string>
<string name="hash_channel_description">Thông báo cho quá trình băm video</string>
<string name="hash_channel_name">Thông báo băm video</string>
<string name="show_meta_info_summary">Tắt để ẩn các hộp thông tin meta có thông tin bổ sung về người tạo luồng, nội dung luồng hoặc yêu cầu tìm kiếm</string>
<string name="show_meta_info_summary">Tắt để ẩn các hộp siêu dữ liệu có thông tin bổ sung về người tạo luồng, nội dung luồng hoặc yêu cầu tìm kiếm</string>
<string name="show_meta_info_title">Hiển thị thông tin meta</string>
<string name="show_description_summary">Tắt để ẩn mô tả video và các thông tin bổ sung</string>
<string name="show_description_title">Hiện mô tả</string>
@ -624,7 +624,7 @@
<string name="comments_are_disabled">Bình luận đã bị tắt</string>
<string name="detail_heart_img_view_description">Đã được chủ kênh thả \"thính\"</string>
<string name="mark_as_watched">Đánh dấu là đã xem</string>
<string name="show_image_indicators_summary">Hiện ruy băng được tô màu Picasso ở trên cùng các hình ảnh và chỉ ra nguồn của chúng: đỏ đối với mạng, xanh lam đối với ổ đĩa và xanh lá đối với bộ nhớ</string>
<string name="show_image_indicators_summary">Hiển thị các dải băng màu Picasso trên đầu các hình ảnh cho biết nguồn của chúng: màu đỏ cho mạng, màu lam cho đĩa và màu lục cho bộ nhớ</string>
<string name="show_image_indicators_title">Hiện dấu chỉ hình ảnh</string>
<string name="remote_search_suggestions">Đề xuất tìm kiếm trên mạng</string>
<string name="local_search_suggestions">Đề xuất tìm kiếm cục bộ</string>
@ -634,7 +634,7 @@
<plurals name="download_finished_notification">
<item quantity="other">%s lượt tải xuống đã hoàn tất</item>
</plurals>
<string name="main_page_content_swipe_remove">Vuốt các mục để xóa chúng</string>
<string name="main_page_content_swipe_remove">Vuốt các mục để loại bỏ chúng</string>
<string name="start_main_player_fullscreen_summary">Không bắt đầu các video ở trình phát mini, mà chuyển trực tiếp thành chế độ toàn màn hình, nếu tự động xoay bị khóa. Bạn vẫn có thể truy cập trình phát mini bằng cách thoát khỏi toàn màn hình</string>
<string name="start_main_player_fullscreen_title">Khởi động trình phát chính ở toàn màn hình</string>
<string name="enqueued_next">Đã xếp kế tiếp vào hàng</string>
@ -683,7 +683,7 @@
<string name="percent">Phần trăm</string>
<string name="enumeration_comma">,</string>
<string name="semitone">Nửa cung</string>
<string name="streams_not_yet_supported_removed">Luồng băng hình mà không được trình tải xuống hỗ trợ sẽ không hiển thị</string>
<string name="streams_not_yet_supported_removed">Các luồng chưa được trình tải xuống hỗ trợ sẽ không được hiển thị</string>
<string name="no_video_streams_available_for_external_players">Không có luồng video nào khả dụng cho trình phát bên ngoài</string>
<string name="selected_stream_external_player_not_supported">Luồng phát đã chọn không được trình phát ngoài hỗ trợ</string>
<string name="no_audio_streams_available_for_external_players">Không có luồng âm thanh nào khả dụng cho máy phát bên ngoài</string>
@ -705,9 +705,9 @@
<string name="fast_mode">Chế độ tăng tốc</string>
<string name="duplicate_in_playlist">Danh sách phát màu xám thì đã chứa mục này.</string>
<string name="ignore_hardware_media_buttons_summary">Hữu ích trong trường hợp phím bấm âm lượng trên tai nghe hoặc thiết bị của bạn bị hỏng</string>
<string name="ignore_hardware_media_buttons_title">Không nhận phím điều khiển âm lượng vật lý</string>
<string name="remove_duplicates">Loại bỏ mục trùng lặp</string>
<string name="remove_duplicates_title">Loại bỏ mục trùng lặp\?</string>
<string name="ignore_hardware_media_buttons_title">Bỏ qua nhận nút phương tiện vật lý</string>
<string name="remove_duplicates">Loại bỏ các bản trùng lặp</string>
<string name="remove_duplicates_title">Loại bỏ các bản trùng lặp?</string>
<string name="remove_duplicates_message">Bạn có muốn loại bỏ mọi luồng trùng lặp trong danh sách phát này\?</string>
<string name="feed_show_hide_streams">Hiện/Ẩn luồng phát</string>
<string name="feed_hide_streams_title">Hiển thị các luồng phát sau</string>

View File

@ -800,4 +800,14 @@
<string name="show_more">拉開</string>
<string name="notification_actions_summary_android13">撳下面嘅掣去更改對應嘅通知動作。頭三個動作 (播放/暫停、上一個、下一個) 系統預設咗,冇得揀。</string>
<string name="error_insufficient_storage">部機冇晒位</string>
<string name="yes"></string>
<string name="auto_update_check_description">NewPipe 可以周不時自動睇過有冇新版本,一出咗就通知您。
\n您想唔想啟用呢個功能</string>
<string name="reset_settings_title">推翻所有設定</string>
<string name="reset_all_settings">推翻所有設定就會全盤抹走晒您喜好過嘅設定,然後重新開過個 app 個囉噃。
\n
\n您確定要不惜一切推倒重來</string>
<string name="settings_category_backup_restore_title">備份與還原</string>
<string name="no">唔使喇</string>
<string name="reset_settings_summary">顛覆所有設定,光復成預設值重新開始</string>
</resources>

View File

@ -856,4 +856,5 @@
</plurals>
<string name="show_more">Show more</string>
<string name="show_less">Show less</string>
<string name="import_settings_vulnerable_format">The settings in the export being imported use a vulnerable format that was deprecated since NewPipe 0.27.0. Make sure the export being imported is from a trusted source, and prefer using only exports obtained from NewPipe 0.27.0 or newer in the future. Support for importing settings in this vulnerable format will soon be removed completely, and then old versions of NewPipe will not be able to import settings of exports from new versions anymore.</string>
</resources>

View File

@ -0,0 +1,184 @@
package org.schabi.newpipe.settings
import android.content.SharedPreferences
import org.junit.Assert
import org.junit.Test
import org.mockito.Mockito
import org.schabi.newpipe.settings.export.BackupFileLocator
import org.schabi.newpipe.settings.export.ImportExportManager
import org.schabi.newpipe.streams.io.StoredFileHelper
import us.shandian.giga.io.FileStream
import java.io.File
import java.io.IOException
import java.nio.file.Files
class ImportAllCombinationsTest {
companion object {
private val classloader = ImportExportManager::class.java.classLoader!!
}
private enum class Ser(val id: String) {
YES("ser"),
VULNERABLE("vulnser"),
NO("noser");
}
private data class FailData(
val containsDb: Boolean,
val containsSer: Ser,
val containsJson: Boolean,
val filename: String,
val throwable: Throwable,
)
private fun testZipCombination(
containsDb: Boolean,
containsSer: Ser,
containsJson: Boolean,
filename: String,
runTest: (test: () -> Unit) -> Unit,
) {
val zipFile = File(classloader.getResource(filename)?.file!!)
val zip = Mockito.mock(StoredFileHelper::class.java, Mockito.withSettings().stubOnly())
Mockito.`when`(zip.stream).then { FileStream(zipFile) }
val fileLocator = Mockito.mock(
BackupFileLocator::class.java,
Mockito.withSettings().stubOnly()
)
val db = File.createTempFile("newpipe_", "")
val dbJournal = File.createTempFile("newpipe_", "")
val dbWal = File.createTempFile("newpipe_", "")
val dbShm = File.createTempFile("newpipe_", "")
Mockito.`when`(fileLocator.db).thenReturn(db)
Mockito.`when`(fileLocator.dbJournal).thenReturn(dbJournal)
Mockito.`when`(fileLocator.dbShm).thenReturn(dbShm)
Mockito.`when`(fileLocator.dbWal).thenReturn(dbWal)
if (containsDb) {
runTest {
Assert.assertTrue(ImportExportManager(fileLocator).extractDb(zip))
Assert.assertFalse(dbJournal.exists())
Assert.assertFalse(dbWal.exists())
Assert.assertFalse(dbShm.exists())
Assert.assertTrue("database file size is zero", Files.size(db.toPath()) > 0)
}
} else {
runTest {
Assert.assertFalse(ImportExportManager(fileLocator).extractDb(zip))
Assert.assertTrue(dbJournal.exists())
Assert.assertTrue(dbWal.exists())
Assert.assertTrue(dbShm.exists())
Assert.assertEquals(0, Files.size(db.toPath()))
}
}
val preferences = Mockito.mock(SharedPreferences::class.java, Mockito.withSettings().stubOnly())
var editor = Mockito.mock(SharedPreferences.Editor::class.java)
Mockito.`when`(preferences.edit()).thenReturn(editor)
Mockito.`when`(editor.commit()).thenReturn(true)
when (containsSer) {
Ser.YES -> runTest {
Assert.assertTrue(ImportExportManager(fileLocator).exportHasSerializedPrefs(zip))
ImportExportManager(fileLocator).loadSerializedPrefs(zip, preferences)
Mockito.verify(editor, Mockito.times(1)).clear()
Mockito.verify(editor, Mockito.times(1)).commit()
Mockito.verify(editor, Mockito.atLeastOnce())
.putBoolean(Mockito.anyString(), Mockito.anyBoolean())
Mockito.verify(editor, Mockito.atLeastOnce())
.putString(Mockito.anyString(), Mockito.anyString())
Mockito.verify(editor, Mockito.atLeastOnce())
.putInt(Mockito.anyString(), Mockito.anyInt())
}
Ser.VULNERABLE -> runTest {
Assert.assertTrue(ImportExportManager(fileLocator).exportHasSerializedPrefs(zip))
Assert.assertThrows(ClassNotFoundException::class.java) {
ImportExportManager(fileLocator).loadSerializedPrefs(zip, preferences)
}
Mockito.verify(editor, Mockito.never()).clear()
Mockito.verify(editor, Mockito.never()).commit()
}
Ser.NO -> runTest {
Assert.assertFalse(ImportExportManager(fileLocator).exportHasSerializedPrefs(zip))
Assert.assertThrows(IOException::class.java) {
ImportExportManager(fileLocator).loadSerializedPrefs(zip, preferences)
}
Mockito.verify(editor, Mockito.never()).clear()
Mockito.verify(editor, Mockito.never()).commit()
}
}
// recreate editor mock so verify() behaves correctly
editor = Mockito.mock(SharedPreferences.Editor::class.java)
Mockito.`when`(preferences.edit()).thenReturn(editor)
Mockito.`when`(editor.commit()).thenReturn(true)
if (containsJson) {
runTest {
Assert.assertTrue(ImportExportManager(fileLocator).exportHasJsonPrefs(zip))
ImportExportManager(fileLocator).loadJsonPrefs(zip, preferences)
Mockito.verify(editor, Mockito.times(1)).clear()
Mockito.verify(editor, Mockito.times(1)).commit()
Mockito.verify(editor, Mockito.atLeastOnce())
.putBoolean(Mockito.anyString(), Mockito.anyBoolean())
Mockito.verify(editor, Mockito.atLeastOnce())
.putString(Mockito.anyString(), Mockito.anyString())
Mockito.verify(editor, Mockito.atLeastOnce())
.putInt(Mockito.anyString(), Mockito.anyInt())
}
} else {
runTest {
Assert.assertFalse(ImportExportManager(fileLocator).exportHasJsonPrefs(zip))
Assert.assertThrows(IOException::class.java) {
ImportExportManager(fileLocator).loadJsonPrefs(zip, preferences)
}
Mockito.verify(editor, Mockito.never()).clear()
Mockito.verify(editor, Mockito.never()).commit()
}
}
}
@Test
fun `Importing all possible combinations of zip files`() {
val failedAssertions = mutableListOf<FailData>()
for (containsDb in listOf(true, false)) {
for (containsSer in Ser.entries) {
for (containsJson in listOf(true, false)) {
val filename = "settings/${if (containsDb) "db" else "nodb"}_${
containsSer.id}_${if (containsJson) "json" else "nojson"}.zip"
testZipCombination(containsDb, containsSer, containsJson, filename) { test ->
try {
test()
} catch (e: Throwable) {
failedAssertions.add(
FailData(
containsDb, containsSer, containsJson,
filename, e
)
)
}
}
}
}
}
if (failedAssertions.isNotEmpty()) {
for (a in failedAssertions) {
println(
"Assertion failed with containsDb=${a.containsDb}, containsSer=${
a.containsSer}, containsJson=${a.containsJson}, filename=${a.filename}:"
)
a.throwable.printStackTrace()
println()
}
Assert.fail("${failedAssertions.size} assertions failed")
}
}
}

View File

@ -1,8 +1,10 @@
package org.schabi.newpipe.settings
import android.content.SharedPreferences
import com.grack.nanojson.JsonParser
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Assume
import org.junit.Before
@ -17,6 +19,8 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.Mockito.withSettings
import org.mockito.junit.MockitoJUnitRunner
import org.schabi.newpipe.settings.export.BackupFileLocator
import org.schabi.newpipe.settings.export.ImportExportManager
import org.schabi.newpipe.streams.io.StoredFileHelper
import us.shandian.giga.io.FileStream
import java.io.File
@ -25,27 +29,25 @@ import java.nio.file.Files
import java.util.zip.ZipFile
@RunWith(MockitoJUnitRunner::class)
class ContentSettingsManagerTest {
class ImportExportManagerTest {
companion object {
private val classloader = ContentSettingsManager::class.java.classLoader!!
private val classloader = ImportExportManager::class.java.classLoader!!
}
private lateinit var fileLocator: NewPipeFileLocator
private lateinit var fileLocator: BackupFileLocator
private lateinit var storedFileHelper: StoredFileHelper
@Before
fun setupFileLocator() {
fileLocator = Mockito.mock(NewPipeFileLocator::class.java, withSettings().stubOnly())
fileLocator = Mockito.mock(BackupFileLocator::class.java, withSettings().stubOnly())
storedFileHelper = Mockito.mock(StoredFileHelper::class.java, withSettings().stubOnly())
}
@Test
fun `The settings must be exported successfully in the correct format`() {
val db = File(classloader.getResource("settings/newpipe.db")!!.file)
val newpipeSettings = File.createTempFile("newpipe_", "")
`when`(fileLocator.db).thenReturn(db)
`when`(fileLocator.settings).thenReturn(newpipeSettings)
val expectedPreferences = mapOf("such pref" to "much wow")
val sharedPreferences =
@ -54,11 +56,11 @@ class ContentSettingsManagerTest {
val output = File.createTempFile("newpipe_", "")
`when`(storedFileHelper.stream).thenReturn(FileStream(output))
ContentSettingsManager(fileLocator).exportDatabase(sharedPreferences, storedFileHelper)
ImportExportManager(fileLocator).exportDatabase(sharedPreferences, storedFileHelper)
val zipFile = ZipFile(output)
val entries = zipFile.entries().toList()
assertEquals(2, entries.size)
assertEquals(3, entries.size)
zipFile.getInputStream(entries.first { it.name == "newpipe.db" }).use { actual ->
db.inputStream().use { expected ->
@ -70,26 +72,11 @@ class ContentSettingsManagerTest {
val actualPreferences = ObjectInputStream(actual).readObject()
assertEquals(expectedPreferences, actualPreferences)
}
}
@Test
fun `Settings file must be deleted`() {
val settings = File.createTempFile("newpipe_", "")
`when`(fileLocator.settings).thenReturn(settings)
ContentSettingsManager(fileLocator).deleteSettingsFile()
assertFalse(settings.exists())
}
@Test
fun `Deleting settings file must do nothing if none exist`() {
val settings = File("non_existent")
`when`(fileLocator.settings).thenReturn(settings)
ContentSettingsManager(fileLocator).deleteSettingsFile()
assertFalse(settings.exists())
zipFile.getInputStream(entries.first { it.name == "preferences.json" }).use { actual ->
val actualPreferences = JsonParser.`object`().from(actual)
assertEquals(expectedPreferences, actualPreferences)
}
}
@Test
@ -98,7 +85,7 @@ class ContentSettingsManagerTest {
Assume.assumeTrue(dir.delete())
`when`(fileLocator.dbDir).thenReturn(dir)
ContentSettingsManager(fileLocator).ensureDbDirectoryExists()
ImportExportManager(fileLocator).ensureDbDirectoryExists()
assertTrue(dir.exists())
}
@ -107,7 +94,7 @@ class ContentSettingsManagerTest {
val dir = Files.createTempDirectory("newpipe_").toFile()
`when`(fileLocator.dbDir).thenReturn(dir)
ContentSettingsManager(fileLocator).ensureDbDirectoryExists()
ImportExportManager(fileLocator).ensureDbDirectoryExists()
assertTrue(dir.exists())
}
@ -122,9 +109,9 @@ class ContentSettingsManagerTest {
`when`(fileLocator.dbShm).thenReturn(dbShm)
`when`(fileLocator.dbWal).thenReturn(dbWal)
val zip = File(classloader.getResource("settings/newpipe.zip")?.file!!)
val zip = File(classloader.getResource("settings/db_ser_json.zip")?.file!!)
`when`(storedFileHelper.stream).thenReturn(FileStream(zip))
val success = ContentSettingsManager(fileLocator).extractDb(storedFileHelper)
val success = ImportExportManager(fileLocator).extractDb(storedFileHelper)
assertTrue(success)
assertFalse(dbJournal.exists())
@ -141,9 +128,9 @@ class ContentSettingsManagerTest {
val dbShm = File.createTempFile("newpipe_", "")
`when`(fileLocator.db).thenReturn(db)
val emptyZip = File(classloader.getResource("settings/empty.zip")?.file!!)
val emptyZip = File(classloader.getResource("settings/nodb_noser_nojson.zip")?.file!!)
`when`(storedFileHelper.stream).thenReturn(FileStream(emptyZip))
val success = ContentSettingsManager(fileLocator).extractDb(storedFileHelper)
val success = ImportExportManager(fileLocator).extractDb(storedFileHelper)
assertFalse(success)
assertTrue(dbJournal.exists())
@ -154,41 +141,44 @@ class ContentSettingsManagerTest {
@Test
fun `Contains setting must return true if a settings file exists in the zip`() {
val settings = File.createTempFile("newpipe_", "")
`when`(fileLocator.settings).thenReturn(settings)
val zip = File(classloader.getResource("settings/newpipe.zip")?.file!!)
val zip = File(classloader.getResource("settings/db_ser_json.zip")?.file!!)
`when`(storedFileHelper.stream).thenReturn(FileStream(zip))
val contains = ContentSettingsManager(fileLocator).extractSettings(storedFileHelper)
assertTrue(contains)
assertTrue(ImportExportManager(fileLocator).exportHasSerializedPrefs(storedFileHelper))
}
@Test
fun `Contains setting must return false if a no settings file exists in the zip`() {
val settings = File.createTempFile("newpipe_", "")
`when`(fileLocator.settings).thenReturn(settings)
val emptyZip = File(classloader.getResource("settings/empty.zip")?.file!!)
fun `Contains setting must return false if no settings file exists in the zip`() {
val emptyZip = File(classloader.getResource("settings/nodb_noser_nojson.zip")?.file!!)
`when`(storedFileHelper.stream).thenReturn(FileStream(emptyZip))
val contains = ContentSettingsManager(fileLocator).extractSettings(storedFileHelper)
assertFalse(contains)
assertFalse(ImportExportManager(fileLocator).exportHasSerializedPrefs(storedFileHelper))
}
@Test
fun `Preferences must be set from the settings file`() {
val settings = File(classloader.getResource("settings/newpipe.settings")!!.path)
`when`(fileLocator.settings).thenReturn(settings)
val zip = File(classloader.getResource("settings/db_ser_json.zip")?.file!!)
`when`(storedFileHelper.stream).thenReturn(FileStream(zip))
val preferences = Mockito.mock(SharedPreferences::class.java, withSettings().stubOnly())
val editor = Mockito.mock(SharedPreferences.Editor::class.java)
`when`(preferences.edit()).thenReturn(editor)
`when`(editor.commit()).thenReturn(true)
ContentSettingsManager(fileLocator).loadSharedPreferences(preferences)
ImportExportManager(fileLocator).loadSerializedPrefs(storedFileHelper, preferences)
verify(editor, atLeastOnce()).putBoolean(anyString(), anyBoolean())
verify(editor, atLeastOnce()).putString(anyString(), anyString())
verify(editor, atLeastOnce()).putInt(anyString(), anyInt())
}
@Test
fun `Importing preferences with a serialization injected class should fail`() {
val emptyZip = File(classloader.getResource("settings/db_vulnser_json.zip")?.file!!)
`when`(storedFileHelper.stream).thenReturn(FileStream(emptyZip))
val preferences = Mockito.mock(SharedPreferences::class.java, withSettings().stubOnly())
assertThrows(ClassNotFoundException::class.java) {
ImportExportManager(fileLocator).loadSerializedPrefs(storedFileHelper, preferences)
}
}
}

View File

@ -0,0 +1,4 @@
`*.zip` files in this folder are NewPipe database exports, in all possible configurations:
- `db` / `nodb` indicates if there is a `newpipe.db` database included or not
- `ser` / `vulnser` / `noser` indicates if there is a `newpipe.settings` Java-serialized preferences file included, if it is included and contains an injection attack, of if it is not included
- `json` / `nojson` indicates if there is a `preferences.json` JSON preferences file included or not

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -39,11 +39,13 @@
<module name="Translation"/>
<!-- Checks for Size Violations. -->
<!-- See https://checkstyle.org/config_sizes.html -->
<!-- See https://checkstyle.sourceforge.io/checks/sizes/index.html -->
<module name="FileLength"/>
<module name="LineLength">
<property name="max" value="100"/>
<property name="fileExtensions" value="java"/>
<!-- Also allow links in javadocs to be longer (the default would just cover imports) -->
<property name="ignorePattern" value="^((package|import) .*)|( *\* &lt;a href ?\= ?&quot;.*&quot;&gt;)$"/>
</module>
<!-- Checks for whitespace -->

View File

@ -0,0 +1,17 @@
جديد
• إضافة ردود التعليق
• السماح بإعادة ترتيب قوائم التشغيل
• عرض وصف قائمة التشغيل ومدتها
• السماح بإعادة ضبط الإعدادات
تحسين
• [Android 13+] استعادة إجراءات الإشعارات المخصصة
• طلب الموافقة للتحقق من التحديث
• السماح بتشغيل/إيقاف الإشعارات مؤقتًا أثناء التخزين المؤقت
• إعادة ترتيب بعض الإعدادات
مُثَبَّت
• [YouTube] إصلاح مشكلة عدم تحميل التعليقات، بالإضافة إلى إصلاحات وتحسينات أخرى
• حل مشكلة عدم الحصانة في إعدادات الاستيراد والتحويل إلى JSON
• إصلاحات التنزيل المختلفة
• تقليم نص البحث

View File

@ -0,0 +1,17 @@
Nové
• Odpovědi na komentáře
• Změna pořadí playlistů
• Zobrazení popisu a trvání playlistu
• Možnost resetu nastavení
Vylepšeno
• [Android 13+] Obnovení vlastních akcí oznámení
• Žádost o souhlas pro kontrolu aktualizací
• Povolení přehrání/pozastavení oznámení při načítání
• Změna pořadí některých nastavení
Opraveno
• [YouTube] Opraveno nenačítání komentářů a další opravy a vylepšení
• Oprava závislosti v importu nastavení a přechod na JSON
• Různé opravy stahování
• Trim vyhledávaného textu

View File

@ -11,3 +11,4 @@ Verbessert:
Behoben:
• Verschiedene Probleme mit Player-Benachrichtigung: veraltete/fehlende Medieninfos, verzerrte Miniaturansicht

View File

@ -0,0 +1,17 @@
Neu
• Antwort auf Kommentar
• Wiedergabelisten umordnen
• Wiedergabelisten-Beschreibung und -Dauer
• Rücksetzen der Einstellungen
Verbessert
• [Android 13+] Wiederherstellen benutzerdef. Benachrichtigungsaktionen
• Zustimmung zur Update-Prüfung
• Während Pufferung Abspielen/Pause über Benachrichtigung
• Neuordnung einiger Einstellungen
Behoben
• [YouTube] Kommentare wurden nicht geladen, weitere Korrekturen und Verbesserungen
• Sicherheitslücke beim Einstellungsimport und Umstellung auf JSON
• Verschiedene Download-Korrekturen
• Suchtext gekürzt

View File

@ -8,12 +8,12 @@ Mejorado
- Añadir una miniatura ficticia para listas de reproducción locales vacías
- Usar la extensión de archivos *.opus en lugar de *.webm y mostrar "opus" en etiqueta de formato en lugar de "WebM Opus" en menú desplegable de descargas
- Añadir un botón para eliminar archivos descargados o el historial de descargas en "Descargas"
- YouTube] Añadir soporte a los enlaces de canal /c/shortened_url
- [YouTube] Añadir soporte a los enlaces de canal /c/shortened_url
Corregidos
- Corregidos múltiples problemas al compartir un video a NewPipe y al descargar sus secuencias directamente
- Corregido el acceso al reproductor fuera de su hilo de creación
- Corregida la paginación de resultados de búsqueda
- YouTube] Corregido el cambio a nulo que causaba NPE
- YouTube] Corregida la visualización de comentarios al abrir una url de invidio.us
- SoundCloud] Actualizado client_id
- [YouTube] Corregido el cambio a nulo que causaba NPE
- [YouTube] Corregida la visualización de comentarios al abrir una url de invidio.us
- [SoundCloud] Actualizado client_id

View File

@ -8,5 +8,5 @@
- Se ha corregido la posibilidad de compartir vídeos desde el reproductor
- Corregida la vista web de ReCaptcha en blanco
- Corregido el fallo que se producía al eliminar un stream de una lista
- PeerTube] Corregidos los flujos relacionados
- YouTube] Corregida la búsqueda de música en YouTube
- [PeerTube] Corregidos los flujos relacionados
- [YouTube] Corregida la búsqueda de música en YouTube

View File

@ -1,5 +1,5 @@
• Añade botón de "reproducir siguiente" al menú presionado
• Añadido prefijo de ruta de Youtube shorts
• Añadido prefijo de ruta de YouTube Shorts
• Corregida importación de ajustes
• Intercambio entre barra y botones en pantalla de cola
• Correcciones relacionadas con MediasessionManager

View File

@ -0,0 +1,17 @@
Nuevo
• Añadir respuestas a comentarios
• Reordenar listas de reproducción
• Mostrar descripción y duración de listas de reproducción
• Restaurar ajustes
Mejorado
• [Android 13+] acciones de notificación personalizadas
• Permiso para comprobar actualizaciones
• Reproducir/pausar notificaciones al almacenar en búfer
• Algunos ajustes
Corregido
• [YouTube] Corregir comentarios que no se cargan y mejoras
• Fallo al importar de ajustes y JSON
• Corrección de varias descargas
• texto de búsqueda

View File

@ -0,0 +1,17 @@
नया
• टिप्पणियों के उत्तर जोड़ें
• प्लेलिस्ट को पुन: व्यवस्थित करने की अनुमति दें
• प्लेलिस्ट विवरण और अवधि दिखाएं
• सेटिंग्स रीसेट करने की अनुमति दें
सुधार
• [एंड्रॉइड 13+] कस्टम अधिसूचना क्रियाएं पुनर्स्थापित करें
• अपडेटस की जांच के लिए सहमति का अनुरोध करें
• बफ़रिंग के दौरान नोटीफिकेशन से चलाने/रोकने की अनुमति दें
• कुछ सेटिंग्स पुनः व्यवस्थित करें
ठीक किए
• [यूट्यूब] लोड न होने वाली टिप्पणियों को ठीक करें, साथ ही अन्य फिक्स और सुधार भी
• सेटिंग्स आयात में भेद्यता को हल करें और JSON पर स्विच करें
• विभिन्न डाउनलोड सुधार
• खोज पाठ को ट्रिम करें

View File

@ -0,0 +1,15 @@
Baru
• Tambah balasan komentar
• Izinkan susunan ulg playlist
• Tampilkan deskripsi & durasi daftar putar
• Izinkan setelan ulg
• [Android 13+] Pulihkan tindakan notifikasi khusus
• Minta persetujuan utk pemeriksaan update
• Izinkan pemutaran notifikasi sementara buffering
• Susun ulg bbrp setelan
Perbaikan
• [YouTube] Perbaiki komentar yg tdk dapat dimuat, ditambah perbaikan & peningkatan
• Atasi kerentanan pengimporan pengaturan & ubah ke JSON
• Perbaikan unduhan
• Pangkas teks pencarian

View File

@ -0,0 +1,17 @@
Novità
• Risposte ai commenti
• Riordinamento playlist
• Mostra descrizione e durata playlist
• Consenti ripristino impostazioni
Migliorie
• [Android 13+] Ripristina azioni di notifica personalizzate
• Richiedi consenso per ricerca aggiornamenti
• Notifiche avvio/pausa durante il buffer
• Riordinate alcune impostazioni
Correzioni
• [YouTube] I commenti non si caricavano, altre correzioni
• Vulnerabilità in importa impostazioni e passaggio a JSON
• Correzioni sui download
• Trim delle ricerche

View File

@ -0,0 +1 @@
SoundCloud ಸಮಸ್ಯೆಗಳನ್ನು ಸರಿಪಡಿಸಲು SoundCloud client_id ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ.

View File

@ -0,0 +1 @@
ಈ ಬಿಡುಗಡೆಯ ಯೂಟ್ಯೂಬ್ ವೆಬ್‌ಸೈಟ್ ಆವೃತ್ತಿಯನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ. ಹಳೆಯ ವೆಬ್‌ಸೈಟ್ ಆವೃತ್ತಿಯು ಮಾರ್ಚ್‌ನಲ್ಲಿ ಸ್ಥಗಿತಗೊಳ್ಳಲಿದೆ ಮತ್ತು ಆದ್ದರಿಂದ ನೀವು ನ್ಯೂಪೈಪ್ ಅನ್ನು ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.

View File

@ -0,0 +1 @@
ನ್ಯೂಪೈಪ್ ಯಾವುದೇ ಗೂಗಲ್ ಫ್ರೇಮ್‌ವರ್ಕ್ ಲೈಬ್ರರಿಗಳನ್ನು ಅಥವಾ ಯೂಟ್ಯೂಬ್‌ ಏಪಿಐ ಅನ್ನು ಬಳಸುವುದಿಲ್ಲ. ಇದು ಅಗತ್ಯವಿರುವ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು ವೆಬ್‌ಸೈಟ್ ಅನ್ನು ಮಾತ್ರ ಪಾರ್ಸ್ ಮಾಡುತ್ತದೆ. ಆದ್ದರಿಂದ ಈ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಗೂಗಲ್ ಸೇವೆಗಳನ್ನು ಸ್ಥಾಪಿಸದೆಯೇ ಸಾಧನಗಳಲ್ಲಿ ಬಳಸಬಹುದು. ಅಲ್ಲದೆ, ನ್ಯೂಪೈಪ್ ಅನ್ನು ಬಳಸಲು ನಿಮಗೆ ಯೂಟ್ಯೂಬ್ ಖಾತೆಯ ಅಗತ್ಯವಿಲ್ಲ ಮತ್ತು ಅದು FLOSS ಆಗಿದೆ.

View File

@ -0,0 +1 @@
ಆಂಡ್ರಾಯ್ಡ್‌ಗಾಗಿ ತಯಾರಿಸಿರುವ ಯೂಟ್ಯೂಬ್ ಆಧಾರಿತ ಉಚಿತ ಕಿರುತಂತ್ರಾಂಶ.

View File

@ -0,0 +1,17 @@
ਨਵਾਂ
• ਟਿੱਪਣੀਆਂ ਦੇ ਜਵਾਬ ਸ਼ਾਮਿਲ ਕਰੋ
• ਪਲੇਲਿਸਟਸ ਨੂੰ ਮੁੜ ਕ੍ਰਮਬੱਧ ਕਰਨ ਦਿਓ
• ਪਲੇਲਿਸਟ ਵਰਣਨ ਅਤੇ ਮਿਆਦ ਦਿਖਾਓ
• ਸੈਟਿੰਗਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨ ਦਿਓ
ਸੁਧਾਰ
• [ਐਂਡਰੌਇਡ 13+] ਕਸਟਮ ਨੋਟੀਫਿਕੇਸ਼ਨ ਕਿਰਿਆਵਾਂ ਨੂੰ ਮੁੜ ਲਾਗੂ ਕਰੋ
• ਅੱਪਡੇਟ ਜਾਂਚ ਲਈ ਸਹਿਮਤੀ ਦੀ ਬੇਨਤੀ ਕਰੋ
• ਬਫਰਿੰਗ ਦੌਰਾਨ ਨੋਟੀਫਿਕੇਸ਼ਨ ਤੋਂ ਚਲਾਉਣ/ਰੋਕਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ
• ਕੁਝ ਸੈਟਿੰਗਾਂ ਨੂੰ ਮੁੜ ਕ੍ਰਮਬੱਧ ਕਰੋ
ਠੀਕ ਕੀਤਾ
• [ਯੂਟਿਊਬ] ਲੋਡ ਨਾ ਹੋਣ ਵਾਲੀਆਂ ਟਿੱਪਣੀਆਂ ਨੂੰ ਠੀਕ ਕਰੋ, ਨਾਲ ਹੀ ਹੋਰ ਫਿਕਸ ਅਤੇ ਸੁਧਾਰ
• ਸੈਟਿੰਗਾਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਕਮਜ਼ੋਰੀ ਨੂੰ ਹੱਲ ਕਰੋ ਅਤੇ JSON 'ਤੇ ਸਵਿੱਚ ਕਰੋ
• ਕਈ ਡਾਊਨਲੋਡ ਫਿਕਸ
• ਖੋਜ ਟੈਕਸਟ ਨੂੰ ਟਰਿੱਮ ਕਰੋ

View File

@ -0,0 +1,17 @@
Nowe
• Odpowiadanie na komentarze
• Zmiana kolejności playlist
• Pokazyw. opisu i czasu trwania playlist
• Reset ustawień
Ulepszone
• [Android 13+] Przywrócono niestand. akcje powiadomień
• Prośba o zgodę na sprawdzanie aktualizacji
• Odtw./wstrzym. powiadomień podczas bufor.
• Zmiana kolejność niektórych ustawień
Naprawione
• [YouTube] Nieładujące się komentarze i inne poprawki i ulepszenia
• Luka w imporcie ustawień i przełączaniu na JSON
• Różne poprawki pobierania
• Przycięto wyszuk. tekst

View File

@ -0,0 +1,2 @@
Um NullPointerException foi corrigido ao abrir um canal / conferência em media.ccc.de.
O Grinch tentou estragar o nosso presente de Natal para si, mas corrigimo-lo.

View File

@ -0,0 +1,16 @@
Novo
• Adicionar respostas de comentários
• Permitir reordenar listas de reprodução
...
Melhorado
• [Android 13+] Restaurar ações de notificação personalizadas
• Solicitar consentimento para verificação de atualização
• Permitir reprodução/pausa de notificação durante o buffer
...
Fixado
• [Tube] Corrigir comentários que não carregam, além de outras correções e melhorias
• Resolver vulnerabilidade nas configurações importação e mudar para JSON
• Várias correções de descargas
...

View File

@ -0,0 +1,16 @@
Novo
• Adicionar respostas de comentários
• Permitir reordenar listas de reprodução
...
Melhorado
• [Android 13+] Restaurar ações de notificação personalizadas
• Solicitar consentimento para verificação de atualização
• Permitir reprodução/pausa de notificação durante o buffer
...
Fixado
• [Tube] Corrigir comentários que não carregam, além de outras correções e melhorias
• Resolver vulnerabilidade nas configurações importação e mudar para JSON
• Várias correções de descargas
...

View File

@ -0,0 +1,17 @@
Nové
• Pridané odpovede na komentáre
• Umožnená zmena poradia zoznamov skladieb
• Zobrazenie popisu a trvania playlistu
• Umožnené resetovanie nastavení
Vylepšené
• [Android 13+] Obnovenie vlastných akcií upozornenia
• Vyžiadanie súhlasu na kontrolu aktualizácie
• Povolenie oznámenia prehrávania/pozastavenia počas načítania
• Zmena poradia niektorých nastavení
Opravené
• [YouTube] Oprava nenačítania komentárov, ďalšie opravy a vylepšenia
• Vyriešenie zraniteľnosti pri importe nastavení a prepnutie na JSON
• Rôzne opravy sťahovania
• Orezanie textu vyhľadávania

View File

@ -0,0 +1,17 @@
Nytt
• La till kommentars svar
• Tillåt omordnande av spellistor
• Visa spellistors beskrivning och varaktighet
• Tillåt återställning av inställningar
Förbättrat
• [Android 13+] Återställ anpassade aviserings åtgärder
• Begär samtycke för uppdateringskontroll
• Tillåt spela/pausa från avisering under buffring
• Omordnade några inställningar
Fixat
• [YouTube] Fixade kommentarer som inte laddas
• Lös sårbarhet i inställnings import och byt till JSON
• Olika hämtnings fixar
• Trimma sök text

View File

@ -0,0 +1,17 @@
Нове
• Додано коментарі відповідей
• Дозвіл перевпор. плейлістів
• Показ опису й тривалості плейлістів
• Дозвіл скидати налаштування
Удосконалено
• [Android 13+] Відновлено власні дії сповіщень
• Запит згоди на пошук оновлень
• Дозвіл відтвор./паузи зі сповіщень під час буферизації
• Перевпор. деякі налаштування
Виправлено
• [YouTube] Усунуто незавантаж. коментарів та інші виправлення
• Усунуто вразливість імпорту налаштув. і переходу на JSON
• Виправлення завантажень
• Обрізання тексту пошуку

View File

@ -0,0 +1,25 @@
LƯU Ý: Phiên bản này có thể là một lỗi nghiêm trọng, giống như phiên bản trước. Tuy nhiên do đã tắt hoàn toàn kể từ ngày 17. một phiên bản bị hỏng còn tốt hơn là không có phiên bản nào. Phải không? ¯\_(ツ)_/¯
### Cải tiến
* bây giờ có thể mở các tệp đã tải xuống bằng một cú nhấp chuột #1879
* bỏ hỗ trợ cho android 4.1 - 4.3 #1884
* xóa trình phát cũ #1884
* xóa luồng khỏi hàng phát hiện tại bằng cách vuốt chúng sang phải #1915
* xóa luồng được xếp hàng tự động khi luồng mới được xếp hàng thủ công #1878
* Xử lý hậu kỳ để tải xuống và triển khai các tính năng còn thiếu #1759 của @kapodamy
* Cơ sở hạ tầng hậu xử lý
* Xử lý lỗi thích hợp "cơ sở hạ tầng" (dành cho người tải xuống)
* Xếp hàng thay vì tải xuống nhiều lần
* Di chuyển các lượt tải xuống đang chờ xử lý nối tiếp (tệp `.giga`) sang dữ liệu ứng dụng
* Triển khai thử tải xuống tối đa
* Tạm dừng tải xuống đa luồng thích hợp
* Dừng tải xuống khi chuyển sang mạng di động (không bao giờ hoạt động, xem điểm thứ 2)
* Lưu số lượng chủ đề cho lần tải tiếp theo
* Đã sửa rất nhiều lỗi không mạch lạc
### Đã sửa
* Khắc phục sự cố với độ phân giải mặc định được đặt thành độ phân giải dữ liệu di động tốt nhất và hạn chế #1835
* Đã sửa lỗi trình phát bật lên #1874
* NPE khi cố mở trình phát nền #1901
* Sửa lỗi chèn luồng mới khi bật xếp hàng tự động #1878
* Đã khắc phục sự cố tắt máy giải mã

View File

@ -0,0 +1 @@
Đã sửa lỗi YouTube không phát bất kỳ luồng nào

View File

@ -0,0 +1,17 @@
Mới
• Thêm câu trả lời nhận xét
• Cho phép sắp xếp lại danh sách phát
• Hiển thị mô tả và thời lượng danh sách phát
• Cho phép đặt lại cài đặt
Cải thiện
• [Android 13+] Khôi phục các tác vụ thông báo tùy chỉnh
• Yêu cầu sự đồng ý để kiểm tra cập nhật
• Cho phép phát/tạm dừng thông báo trong khi lưu vào bộ đệm
• Sắp xếp lại một số cài đặt
Đã sửa
• [YouTube] Khắc phục lỗi không tải được bình luận, cùng với các bản sửa lỗi và cải tiến khác
• Giải quyết lỗ hổng trong cài đặt nhập và chuyển sang JSON
• Nhiều bản sửa lỗi tải xuống khác nhau
• Cắt bớt văn bản tìm kiếm

View File

@ -0,0 +1,17 @@
新增
• 顯示留言回覆
• 允許重新排序播放清單
• 顯示播放清單描述與總時長
• 允許重設所有設定
改進
• [Android 13+] 還原自訂通知動作
• 更新檢查徵求同意
• 緩衝時允許自通知中播放/暫停
• 重新排序部分設定
修正
• [YouTube] 修正留言未能載入,以及其他修正與改進
• 解決設定匯入的漏洞並改用 JSON
• 若干下載修正
• 修剪搜尋文字

View File

@ -0,0 +1,17 @@
新嘢
• 留言睇埋回覆
• 播放清單有得執排位
• 騷埋播放清單描述同總片長
• 設定有得推倒重來
進步
• [Android 13+] 自訂通知動作回歸
• 徵得同意至睇過有冇更新
• 緩衝緊通知都照撳得播放/暫停
• 一啲設定執過位
修正
• [YouTube] 執返掂啲留言 lo 唔到,同埋其他執漏同進步
• 解決設定匯入漏洞兼轉會用 JSON
• 若干下載執漏
• 搵嘢飛起頭尾啲空格