Merged 'dev' branch

This commit is contained in:
Avently 2020-09-27 18:02:31 +03:00
commit 0370fa6c00
143 changed files with 4952 additions and 1792 deletions

View File

@ -33,7 +33,7 @@ android {
// suffix the app id and the app name with git branch name
def workingBranch = getGitWorkingBranch()
def normalizedWorkingBranch = workingBranch.replaceAll("[^A-Za-z]+", "").toLowerCase()
def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "")
if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
// default values when branch name could not be determined or is master or dev
applicationIdSuffix ".debug"

View File

@ -44,8 +44,9 @@
</receiver>
<service
android:name=".player.MainPlayer"
android:exported="false">
android:name=".player.MainPlayer"
android:exported="false"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>

View File

@ -39,6 +39,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
@ -50,6 +51,7 @@ import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.urlfinder.UrlFinder;
import org.schabi.newpipe.views.FocusOverlayView;
@ -159,27 +161,36 @@ public class RouterActivity extends AppCompatActivity {
if (result) {
onSuccess();
} else {
onError();
showUnsupportedUrlDialog(url);
}
}, this::handleError));
}, throwable -> handleError(throwable, url)));
}
private void handleError(final Throwable error) {
error.printStackTrace();
private void handleError(final Throwable throwable, final String url) {
throwable.printStackTrace();
if (error instanceof ExtractionException) {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
if (throwable instanceof ExtractionException) {
showUnsupportedUrlDialog(url);
} else {
ExtractorHelper.handleGeneralException(this, -1, null, error,
ExtractorHelper.handleGeneralException(this, -1, url, throwable,
UserAction.SOMETHING_ELSE, null);
finish();
}
finish();
}
private void onError() {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
finish();
private void showUnsupportedUrlDialog(final String url) {
final Context context = getThemeWrapperContext();
new AlertDialog.Builder(context)
.setTitle(R.string.unsupported_url)
.setMessage(R.string.unsupported_url_dialog_message)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_share))
.setPositiveButton(R.string.open_in_browser,
(dialog, which) -> ShareUtils.openUrlInBrowser(this, url))
.setNegativeButton(R.string.share,
(dialog, which) -> ShareUtils.shareUrl(this, "", url)) // no subject
.setNeutralButton(R.string.cancel, null)
.setOnDismissListener(dialog -> finish())
.show();
}
protected void onSuccess() {
@ -258,7 +269,7 @@ public class RouterActivity extends AppCompatActivity {
final LayoutInflater inflater = LayoutInflater.from(themeWrapperContext);
final LinearLayout rootLayout = (LinearLayout) inflater.inflate(
R.layout.preferred_player_dialog_view, null, false);
R.layout.single_choice_dialog_view, null, false);
final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list);
final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> {
@ -268,6 +279,7 @@ public class RouterActivity extends AppCompatActivity {
handleChoice(choice.key);
// open future streams always like this one, because "always" button was used by user
if (which == DialogInterface.BUTTON_POSITIVE) {
preferences.edit()
.putString(getString(R.string.preferred_open_action_key), choice.key)
@ -367,23 +379,50 @@ public class RouterActivity extends AppCompatActivity {
final boolean isExtAudioEnabled = preferences.getBoolean(
getString(R.string.use_external_audio_player_key), false);
returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key),
getString(R.string.show_info),
resolveResourceIdFromAttr(context, R.attr.ic_info_outline)));
final AdapterChoiceItem videoPlayer = new AdapterChoiceItem(
getString(R.string.video_player_key), getString(R.string.video_player),
resolveResourceIdFromAttr(context, R.attr.ic_play_arrow));
final AdapterChoiceItem showInfo = new AdapterChoiceItem(
getString(R.string.show_info_key), getString(R.string.show_info),
resolveResourceIdFromAttr(context, R.attr.ic_info_outline));
final AdapterChoiceItem popupPlayer = new AdapterChoiceItem(
getString(R.string.popup_player_key), getString(R.string.popup_player),
resolveResourceIdFromAttr(context, R.attr.ic_popup));
final AdapterChoiceItem backgroundPlayer = new AdapterChoiceItem(
getString(R.string.background_player_key), getString(R.string.background_player),
resolveResourceIdFromAttr(context, R.attr.ic_headset));
if (capabilities.contains(VIDEO) && !(isExtVideoEnabled && linkType != LinkType.STREAM)) {
returnList.add(new AdapterChoiceItem(getString(R.string.video_player_key),
getString(R.string.video_player),
resolveResourceIdFromAttr(context, R.attr.ic_play_arrow)));
returnList.add(new AdapterChoiceItem(getString(R.string.popup_player_key),
getString(R.string.popup_player),
resolveResourceIdFromAttr(context, R.attr.ic_popup)));
}
if (linkType == LinkType.STREAM) {
if (isExtVideoEnabled) {
// show both "show info" and "video player", they are two different activities
returnList.add(showInfo);
returnList.add(videoPlayer);
} else if (capabilities.contains(VIDEO)
&& PlayerHelper.isAutoplayAllowedByUser(context)) {
// show only "video player" since the details activity will be opened and the video
// will be autoplayed there and "show info" would do the exact same thing
returnList.add(videoPlayer);
} else {
// show only "show info" if video player is not applicable or autoplay is disabled
returnList.add(showInfo);
}
if (capabilities.contains(AUDIO) && !(isExtAudioEnabled && linkType != LinkType.STREAM)) {
returnList.add(new AdapterChoiceItem(getString(R.string.background_player_key),
getString(R.string.background_player),
resolveResourceIdFromAttr(context, R.attr.ic_headset)));
if (capabilities.contains(VIDEO)) {
returnList.add(popupPlayer);
}
if (capabilities.contains(AUDIO)) {
returnList.add(backgroundPlayer);
}
} else {
returnList.add(showInfo);
if (capabilities.contains(VIDEO) && !isExtVideoEnabled) {
returnList.add(videoPlayer);
returnList.add(popupPlayer);
}
if (capabilities.contains(AUDIO) && !isExtAudioEnabled) {
returnList.add(backgroundPlayer);
}
}
returnList.add(new AdapterChoiceItem(getString(R.string.download_key),
@ -459,7 +498,7 @@ public class RouterActivity extends AppCompatActivity {
startActivity(intent);
finish();
}, this::handleError)
}, throwable -> handleError(throwable, currentUrl))
);
return;
}
@ -493,7 +532,9 @@ public class RouterActivity extends AppCompatActivity {
downloadDialog.show(fm, "downloadDialog");
fm.executePendingTransactions();
downloadDialog.getDialog().setOnDismissListener(dialog -> finish());
}, (@NonNull Throwable throwable) -> onError());
}, (@NonNull Throwable throwable) -> {
showUnsupportedUrlDialog(currentUrl);
});
}
@Override

View File

@ -122,6 +122,7 @@ import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
@ -327,7 +328,7 @@ public class VideoDetailFragment
settingsContentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(final boolean selfChange) {
if (activity != null && !PlayerHelper.globalScreenOrientationLocked(activity)) {
if (activity != null && !globalScreenOrientationLocked(activity)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
@ -853,6 +854,9 @@ public class VideoDetailFragment
return;
}
setInitialData(sid, videoUrl, title, queue);
if (player != null) {
player.disablePreloadingOfCurrentTrack();
}
startLoading(false, true);
}
@ -1143,7 +1147,7 @@ public class VideoDetailFragment
}
private boolean isExternalPlayerEnabled() {
return PreferenceManager.getDefaultSharedPreferences(getContext())
return PreferenceManager.getDefaultSharedPreferences(requireContext())
.getBoolean(getString(R.string.use_external_video_player_key), false);
}
@ -1154,23 +1158,7 @@ public class VideoDetailFragment
&& !isExternalPlayerEnabled()
&& (player == null || player.videoPlayerSelected())
&& bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
&& isAutoplayAllowedByUser();
}
private boolean isAutoplayAllowedByUser() {
if (activity == null) {
return false;
}
switch (PlayerHelper.getAutoplayType(activity)) {
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
return false;
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
return !ListHelper.isMeteredNetwork(activity);
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
default:
return true;
}
&& PlayerHelper.isAutoplayAllowedByUser(requireContext());
}
private void addVideoPlayerView() {
@ -1759,9 +1747,6 @@ public class VideoDetailFragment
setOverlayPlayPauseImage();
switch (state) {
case BasePlayer.STATE_COMPLETED:
restoreDefaultOrientation();
break;
case BasePlayer.STATE_PLAYING:
if (positionView.getAlpha() != 1.0f
&& player.getPlayQueue() != null
@ -1865,7 +1850,13 @@ public class VideoDetailFragment
}
scrollToTop();
addVideoPlayerView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
addVideoPlayerView();
} else {
// KitKat needs a delay before addVideoPlayerView call or it reports wrong height in
// activity.getWindow().getDecorView().getHeight()
new Handler().post(this::addVideoPlayerView);
}
}
@Override
@ -1873,13 +1864,15 @@ public class VideoDetailFragment
// In tablet user experience will be better if screen will not be rotated
// from landscape to portrait every time.
// Just turn on fullscreen mode in landscape orientation
if (isLandscape() && DeviceUtils.isTablet(activity)) {
// or portrait & unlocked global orientation
if (DeviceUtils.isTablet(activity)
&& (!globalScreenOrientationLocked(activity) || isLandscape())) {
player.toggleFullscreen();
return;
}
final int newOrientation = isLandscape()
? ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
activity.setRequestedOrientation(newOrientation);
@ -2022,9 +2015,8 @@ public class VideoDetailFragment
}
player.checkLandscape();
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
// Let's give a user time to look at video information page if video is not playing
if (orientationLocked && !player.isPlaying()) {
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
player.onPlay();
}
}

View File

@ -52,6 +52,7 @@ import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExceptionUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ServiceHelper;
@ -78,7 +79,7 @@ import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovement
import static java.util.Arrays.asList;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage>
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
implements BackPressable {
/*//////////////////////////////////////////////////////////////////////////
// Search
@ -133,7 +134,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
private Map<Integer, String> menuItemToFilterName;
private StreamingService service;
private Page nextPage;
private String contentCountry;
private boolean isSuggestionsEnabled = true;
private Disposable searchDisposable;
@ -154,6 +154,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
private TextView correctSuggestion;
private View suggestionsPanel;
private boolean suggestionsPanelVisible = false;
private RecyclerView suggestionsRecyclerView;
/*////////////////////////////////////////////////////////////////////////*/
@ -204,8 +205,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
= PreferenceManager.getDefaultSharedPreferences(activity);
isSuggestionsEnabled = preferences
.getBoolean(getString(R.string.show_search_suggestions_key), true);
contentCountry = preferences.getString(getString(R.string.content_country_key),
getString(R.string.default_localization_key));
}
@Override
@ -233,9 +232,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
if (suggestionDisposable != null) {
suggestionDisposable.dispose();
}
if (disposables != null) {
disposables.clear();
}
disposables.clear();
hideKeyboardSearch();
}
@ -249,8 +246,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
try {
service = NewPipe.getService(serviceId);
} catch (final Exception e) {
ErrorActivity.reportError(getActivity(), e, getActivity().getClass(),
getActivity().findViewById(android.R.id.content),
ErrorActivity.reportError(getActivity(), e, requireActivity().getClass(),
requireActivity().findViewById(android.R.id.content),
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"",
"", R.string.general_error));
@ -303,26 +300,20 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
if (suggestionDisposable != null) {
suggestionDisposable.dispose();
}
if (disposables != null) {
disposables.clear();
}
disposables.clear();
}
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case ReCaptchaActivity.RECAPTCHA_REQUEST:
if (resultCode == Activity.RESULT_OK
&& !TextUtils.isEmpty(searchString)) {
search(searchString, contentFilter, sortFilter);
} else {
Log.e(TAG, "ReCaptcha failed");
}
break;
default:
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
break;
if (requestCode == ReCaptchaActivity.RECAPTCHA_REQUEST) {
if (resultCode == Activity.RESULT_OK
&& !TextUtils.isEmpty(searchString)) {
search(searchString, contentFilter, sortFilter);
} else {
Log.e(TAG, "ReCaptcha failed");
}
} else {
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
}
}
@ -340,7 +331,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
@Override
public int getMovementFlags(@NonNull final RecyclerView recyclerView,
@NonNull final RecyclerView.ViewHolder viewHolder) {
return getSuggestionMovementFlags(recyclerView, viewHolder);
return getSuggestionMovementFlags(viewHolder);
}
@Override
@ -352,7 +343,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
@Override
public void onSwiped(@NonNull final RecyclerView.ViewHolder viewHolder, final int i) {
onSuggestionItemSwiped(viewHolder, i);
onSuggestionItemSwiped(viewHolder);
}
}).attachToRecyclerView(suggestionsRecyclerView);
@ -627,6 +618,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
if (DEBUG) {
Log.d(TAG, "showSuggestionsPanel() called");
}
suggestionsPanelVisible = true;
animateView(suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, true, 200);
}
@ -634,6 +626,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
if (DEBUG) {
Log.d(TAG, "hideSuggestionsPanel() called");
}
suggestionsPanelVisible = false;
animateView(suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, false, 200);
}
@ -669,8 +662,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
private void showDeleteSuggestionDialog(final SuggestionItem item) {
if (activity == null || historyRecordManager == null || suggestionPublisher == null
|| searchEditText == null || disposables == null) {
if (activity == null || historyRecordManager == null || searchEditText == null) {
return;
}
final String query = item.query;
@ -695,7 +687,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
@Override
public boolean onBackPressed() {
if (suggestionsPanel.getVisibility() == View.VISIBLE
if (suggestionsPanelVisible
&& infoListAdapter.getItemsList().size() > 0
&& !isLoading.get()) {
hideSuggestionsPanel();
@ -742,6 +734,13 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
final Observable<List<SuggestionItem>> network = ExtractorHelper
.suggestionsFor(serviceId, query)
.onErrorReturn(throwable -> {
if (!ExceptionUtils.isNetworkRelated(throwable)) {
showSnackBarError(throwable, UserAction.GET_SUGGESTIONS,
NewPipe.getNameOfService(serviceId), searchString, 0);
}
return new ArrayList<>();
})
.toObservable()
.map(strings -> {
final List<SuggestionItem> result = new ArrayList<>();
@ -791,28 +790,30 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
// no-op
}
private void search(final String ss, final String[] cf, final String sf) {
private void search(final String theSearchString,
final String[] theContentFilter,
final String theSortFilter) {
if (DEBUG) {
Log.d(TAG, "search() called with: query = [" + ss + "]");
Log.d(TAG, "search() called with: query = [" + theSearchString + "]");
}
if (ss.isEmpty()) {
if (theSearchString.isEmpty()) {
return;
}
try {
final StreamingService streamingService = NewPipe.getServiceByUrl(ss);
final StreamingService streamingService = NewPipe.getServiceByUrl(theSearchString);
if (streamingService != null) {
showLoading();
disposables.add(Observable
.fromCallable(() ->
NavigationHelper.getIntentByLink(activity, streamingService, ss))
.fromCallable(() -> NavigationHelper.getIntentByLink(activity,
streamingService, theSearchString))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(intent -> {
getFM().popBackStackImmediate();
activity.startActivity(intent);
}, throwable ->
showError(getString(R.string.url_not_supported_toast), false)));
showError(getString(R.string.unsupported_url), false)));
return;
}
} catch (final Exception ignored) {
@ -820,29 +821,27 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
lastSearchedString = this.searchString;
this.searchString = ss;
this.searchString = theSearchString;
infoListAdapter.clearStreamItemList();
hideSuggestionsPanel();
hideKeyboardSearch();
historyRecordManager.onSearched(serviceId, ss)
disposables.add(historyRecordManager.onSearched(serviceId, theSearchString)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> {
},
error -> showSnackBarError(error, UserAction.SEARCHED,
NewPipe.getNameOfService(serviceId), ss, 0)
);
suggestionPublisher.onNext(ss);
NewPipe.getNameOfService(serviceId), theSearchString, 0)
));
suggestionPublisher.onNext(theSearchString);
startLoading(false);
}
@Override
public void startLoading(final boolean forceLoad) {
super.startLoading(forceLoad);
if (disposables != null) {
disposables.clear();
}
disposables.clear();
if (searchDisposable != null) {
searchDisposable.dispose();
}
@ -881,8 +880,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
@Override
protected boolean hasMoreItems() {
// TODO: No way to tell if search has more items in the moment
return true;
return Page.isValid(nextPage);
}
@Override
@ -895,22 +893,25 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void changeContentFilter(final MenuItem item, final List<String> cf) {
this.filterItemCheckedId = item.getItemId();
private void changeContentFilter(final MenuItem item, final List<String> theContentFilter) {
filterItemCheckedId = item.getItemId();
item.setChecked(true);
this.contentFilter = new String[]{cf.get(0)};
contentFilter = new String[]{theContentFilter.get(0)};
if (!TextUtils.isEmpty(searchString)) {
search(searchString, this.contentFilter, sortFilter);
search(searchString, contentFilter, sortFilter);
}
}
private void setQuery(final int sid, final String ss, final String[] cf, final String sf) {
this.serviceId = sid;
this.searchString = searchString;
this.contentFilter = cf;
this.sortFilter = sf;
private void setQuery(final int theServiceId,
final String theSearchString,
final String[] theContentFilter,
final String theSortFilter) {
serviceId = theServiceId;
searchString = theSearchString;
contentFilter = theContentFilter;
sortFilter = theSortFilter;
}
/*//////////////////////////////////////////////////////////////////////////
@ -924,7 +925,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
suggestionsRecyclerView.smoothScrollToPosition(0);
suggestionsRecyclerView.post(() -> suggestionListAdapter.setItems(suggestions));
if (errorPanelRoot.getVisibility() == View.VISIBLE) {
if (suggestionsPanelVisible && errorPanelRoot.getVisibility() == View.VISIBLE) {
hideLoading();
}
}
@ -1027,7 +1028,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
@Override
public void handleNextItems(final ListExtractor.InfoItemsPage result) {
public void handleNextItems(final ListExtractor.InfoItemsPage<?> result) {
showListFooter(false);
infoListAdapter.addInfoItemList(result.getItems());
nextPage = result.getNextPage();
@ -1066,8 +1067,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
// Suggestion item touch helper
//////////////////////////////////////////////////////////////////////////*/
public int getSuggestionMovementFlags(@NonNull final RecyclerView recyclerView,
@NonNull final RecyclerView.ViewHolder viewHolder) {
public int getSuggestionMovementFlags(@NonNull final RecyclerView.ViewHolder viewHolder) {
final int position = viewHolder.getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
return 0;
@ -1078,8 +1078,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) : 0;
}
public void onSuggestionItemSwiped(@NonNull final RecyclerView.ViewHolder viewHolder,
final int i) {
public void onSuggestionItemSwiped(@NonNull final RecyclerView.ViewHolder viewHolder) {
final int position = viewHolder.getAdapterPosition();
final String query = suggestionListAdapter.getItem(position).query;
final Disposable onDelete = historyRecordManager.deleteSearchHistory(query)

View File

@ -180,6 +180,8 @@ public abstract class BasePlayer implements
@NonNull
protected final HistoryRecordManager recordManager;
@NonNull
protected final SharedPreferences sharedPreferences;
@NonNull
protected final CustomTrackSelector trackSelector;
@NonNull
protected final PlayerDataSource dataSource;
@ -211,6 +213,7 @@ public abstract class BasePlayer implements
setupBroadcastReceiver(intentFilter);
this.recordManager = new HistoryRecordManager(context);
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
this.progressUpdateReactor = new SerialDisposable();
this.databaseUpdateReactor = new CompositeDisposable();
@ -1246,7 +1249,15 @@ public abstract class BasePlayer implements
Log.d(TAG, "seekBy() called with: position = [" + positionMillis + "]");
}
if (simpleExoPlayer != null) {
simpleExoPlayer.seekTo(positionMillis);
// prevent invalid positions when fast-forwarding/-rewinding
long normalizedPositionMillis = positionMillis;
if (normalizedPositionMillis < 0) {
normalizedPositionMillis = 0;
} else if (normalizedPositionMillis > simpleExoPlayer.getDuration()) {
normalizedPositionMillis = simpleExoPlayer.getDuration();
}
simpleExoPlayer.seekTo(normalizedPositionMillis);
}
}
@ -1417,6 +1428,11 @@ public abstract class BasePlayer implements
return currentMetadata;
}
@NonNull
public LoadController getLoadController() {
return (LoadController) loadControl;
}
@NonNull
public String getVideoUrl() {
return currentMetadata == null

View File

@ -19,35 +19,18 @@
package org.schabi.newpipe.player;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import androidx.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.google.android.exoplayer2.Player;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.BitmapUtils;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
@ -64,7 +47,6 @@ public final class MainPlayer extends Service {
private VideoPlayerImpl playerImpl;
private WindowManager windowManager;
private SharedPreferences sharedPreferences;
private final IBinder mBinder = new MainPlayer.LocalBinder();
@ -78,30 +60,26 @@ public final class MainPlayer extends Service {
// Notification
//////////////////////////////////////////////////////////////////////////*/
static final int NOTIFICATION_ID = 123789;
private NotificationManager notificationManager;
private NotificationCompat.Builder notBuilder;
private RemoteViews notRemoteView;
private RemoteViews bigNotRemoteView;
static final String ACTION_CLOSE =
"org.schabi.newpipe.player.MainPlayer.CLOSE";
static final String ACTION_PLAY_PAUSE =
"org.schabi.newpipe.player.MainPlayer.PLAY_PAUSE";
static final String ACTION_OPEN_CONTROLS =
"org.schabi.newpipe.player.MainPlayer.OPEN_CONTROLS";
static final String ACTION_REPEAT =
"org.schabi.newpipe.player.MainPlayer.REPEAT";
static final String ACTION_PLAY_NEXT =
"org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT";
static final String ACTION_PLAY_PREVIOUS =
"org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS";
static final String ACTION_FAST_REWIND =
"org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND";
static final String ACTION_FAST_FORWARD =
"org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD";
private static final String SET_IMAGE_RESOURCE_METHOD = "setImageResource";
static final String ACTION_CLOSE
= "org.schabi.newpipe.player.MainPlayer.CLOSE";
static final String ACTION_PLAY_PAUSE
= "org.schabi.newpipe.player.MainPlayer.PLAY_PAUSE";
static final String ACTION_OPEN_CONTROLS
= "org.schabi.newpipe.player.MainPlayer.OPEN_CONTROLS";
static final String ACTION_REPEAT
= "org.schabi.newpipe.player.MainPlayer.REPEAT";
static final String ACTION_PLAY_NEXT
= "org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT";
static final String ACTION_PLAY_PREVIOUS
= "org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS";
static final String ACTION_FAST_REWIND
= "org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND";
static final String ACTION_FAST_FORWARD
= "org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD";
static final String ACTION_SHUFFLE
= "org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE";
public static final String ACTION_RECREATE_NOTIFICATION
= "org.schabi.newpipe.player.MainPlayer.ACTION_RECREATE_NOTIFICATION";
/*//////////////////////////////////////////////////////////////////////////
// Service's LifeCycle
@ -113,9 +91,7 @@ public final class MainPlayer extends Service {
Log.d(TAG, "onCreate() called");
}
assureCorrectAppLanguage(this);
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
ThemeHelper.setTheme(this);
createView();
@ -143,7 +119,7 @@ public final class MainPlayer extends Service {
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
|| intent.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY) != null) {
showNotificationAndStartForeground();
NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this);
}
playerImpl.handleIntent(intent);
@ -177,7 +153,7 @@ public final class MainPlayer extends Service {
// So we should hide the notification at all.
// When autoplay enabled such notification flashing is annoying so skip this case
if (!autoplayEnabled) {
stopForeground(true);
NotificationUtil.getInstance().cancelNotificationAndStopForeground(this);
}
}
}
@ -232,11 +208,8 @@ public final class MainPlayer extends Service {
playerImpl.removePopupFromView();
playerImpl.destroy();
}
if (notificationManager != null) {
notificationManager.cancel(NOTIFICATION_ID);
}
stopForeground(true);
NotificationUtil.getInstance().cancelNotificationAndStopForeground(this);
stopSelf();
}
@ -275,206 +248,6 @@ public final class MainPlayer extends Service {
}
}
private void showNotificationAndStartForeground() {
resetNotification();
if (getBigNotRemoteView() != null) {
getBigNotRemoteView().setProgressBar(R.id.notificationProgressBar, 100, 0, false);
}
if (getNotRemoteView() != null) {
getNotRemoteView().setProgressBar(R.id.notificationProgressBar, 100, 0, false);
}
startForeground(NOTIFICATION_ID, getNotBuilder().build());
}
/*//////////////////////////////////////////////////////////////////////////
// Notification
//////////////////////////////////////////////////////////////////////////*/
void resetNotification() {
notBuilder = createNotification();
playerImpl.timesNotificationUpdated = 0;
}
private NotificationCompat.Builder createNotification() {
notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
R.layout.player_notification);
bigNotRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
R.layout.player_notification_expanded);
setupNotification(notRemoteView);
setupNotification(bigNotRemoteView);
final NotificationCompat.Builder builder = new NotificationCompat
.Builder(this, getString(R.string.notification_channel_id))
.setOngoing(true)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCustomContentView(notRemoteView)
.setCustomBigContentView(bigNotRemoteView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setLockScreenThumbnail(builder);
}
builder.setPriority(NotificationCompat.PRIORITY_MAX);
return builder;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void setLockScreenThumbnail(final NotificationCompat.Builder builder) {
final boolean isLockScreenThumbnailEnabled = sharedPreferences.getBoolean(
getString(R.string.enable_lock_screen_video_thumbnail_key), true);
if (isLockScreenThumbnailEnabled) {
playerImpl.mediaSessionManager.setLockScreenArt(
builder,
getCenteredThumbnailBitmap()
);
} else {
playerImpl.mediaSessionManager.clearLockScreenArt(builder);
}
}
@Nullable
private Bitmap getCenteredThumbnailBitmap() {
final int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
final int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
return BitmapUtils.centerCrop(playerImpl.getThumbnail(), screenWidth, screenHeight);
}
private void setupNotification(final RemoteViews remoteViews) {
// Don't show anything until player is playing
if (playerImpl == null) {
return;
}
remoteViews.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle());
remoteViews.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName());
remoteViews.setImageViewBitmap(R.id.notificationCover, playerImpl.getThumbnail());
remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationStop,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
// Starts VideoDetailFragment or opens BackgroundPlayerActivity.
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getActivity(this, NOTIFICATION_ID,
getIntentForNotification(), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
if (playerImpl.playQueue != null && playerImpl.playQueue.size() > 1) {
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD,
R.drawable.exo_controls_previous);
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD,
R.drawable.exo_controls_next);
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_PLAY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_PLAY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT));
} else {
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD,
R.drawable.exo_controls_rewind);
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD,
R.drawable.exo_controls_fastforward);
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_FAST_REWIND), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
new Intent(ACTION_FAST_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT));
}
setRepeatModeIcon(remoteViews, playerImpl.getRepeatMode());
}
/**
* Updates the notification, and the play/pause button in it.
* Used for changes on the remoteView
*
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
*/
synchronized void updateNotification(final int drawableId) {
/*if (DEBUG) {
Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
}*/
if (notBuilder == null) {
return;
}
if (drawableId != -1) {
if (notRemoteView != null) {
notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
}
if (bigNotRemoteView != null) {
bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
}
}
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
playerImpl.timesNotificationUpdated++;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMode) {
if (remoteViews == null) {
return;
}
switch (repeatMode) {
case Player.REPEAT_MODE_OFF:
remoteViews.setInt(R.id.notificationRepeat,
SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_repeat_off);
break;
case Player.REPEAT_MODE_ONE:
remoteViews.setInt(R.id.notificationRepeat,
SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_repeat_one);
break;
case Player.REPEAT_MODE_ALL:
remoteViews.setInt(R.id.notificationRepeat,
SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_repeat_all);
break;
}
}
private Intent getIntentForNotification() {
final Intent intent;
if (playerImpl.audioPlayerSelected() || playerImpl.popupPlayerSelected()) {
// Means we play in popup or audio only. Let's show BackgroundPlayerActivity
intent = NavigationHelper.getBackgroundPlayerActivityIntent(getApplicationContext());
} else {
// We are playing in fragment. Don't open another activity just show fragment. That's it
intent = NavigationHelper.getPlayerIntent(this, MainActivity.class, null, true);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
}
return intent;
}
/*//////////////////////////////////////////////////////////////////////////
// Getters
//////////////////////////////////////////////////////////////////////////*/
NotificationCompat.Builder getNotBuilder() {
return notBuilder;
}
RemoteViews getBigNotRemoteView() {
return bigNotRemoteView;
}
RemoteViews getNotRemoteView() {
return notRemoteView;
}
public class LocalBinder extends Binder {

View File

@ -0,0 +1,165 @@
package org.schabi.newpipe.player;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.DrawableRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.Localization;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public final class NotificationConstants {
private NotificationConstants() { }
public static final int NOTHING = 0;
public static final int PREVIOUS = 1;
public static final int NEXT = 2;
public static final int REWIND = 3;
public static final int FORWARD = 4;
public static final int SMART_REWIND_PREVIOUS = 5;
public static final int SMART_FORWARD_NEXT = 6;
public static final int PLAY_PAUSE = 7;
public static final int PLAY_PAUSE_BUFFERING = 8;
public static final int REPEAT = 9;
public static final int SHUFFLE = 10;
public static final int CLOSE = 11;
@Retention(RetentionPolicy.SOURCE)
@IntDef({NOTHING, PREVIOUS, NEXT, REWIND, FORWARD, SMART_REWIND_PREVIOUS, SMART_FORWARD_NEXT,
PLAY_PAUSE, PLAY_PAUSE_BUFFERING, REPEAT, SHUFFLE, CLOSE})
public @interface Action { }
@DrawableRes
public static final int[] ACTION_ICONS = {
0,
R.drawable.exo_icon_previous,
R.drawable.exo_icon_next,
R.drawable.exo_icon_rewind,
R.drawable.exo_icon_fastforward,
R.drawable.exo_icon_previous,
R.drawable.exo_icon_next,
R.drawable.ic_pause_white_24dp,
R.drawable.ic_hourglass_top_white_24dp,
R.drawable.exo_icon_repeat_all,
R.drawable.exo_icon_shuffle_on,
R.drawable.ic_close_white_24dp,
};
@Action
public static final int[] SLOT_DEFAULTS = {
SMART_REWIND_PREVIOUS,
PLAY_PAUSE_BUFFERING,
SMART_FORWARD_NEXT,
REPEAT,
CLOSE,
};
@Action
public static final int[][] SLOT_ALLOWED_ACTIONS = {
new int[] {PREVIOUS, REWIND, SMART_REWIND_PREVIOUS},
new int[] {REWIND, PLAY_PAUSE, PLAY_PAUSE_BUFFERING},
new int[] {NEXT, FORWARD, SMART_FORWARD_NEXT, PLAY_PAUSE, PLAY_PAUSE_BUFFERING},
new int[] {NOTHING, PREVIOUS, NEXT, REWIND, FORWARD, SMART_REWIND_PREVIOUS,
SMART_FORWARD_NEXT, REPEAT, SHUFFLE, CLOSE},
new int[] {NOTHING, NEXT, FORWARD, SMART_FORWARD_NEXT, REPEAT, SHUFFLE, CLOSE},
};
public static final int[] SLOT_PREF_KEYS = {
R.string.notification_slot_0_key,
R.string.notification_slot_1_key,
R.string.notification_slot_2_key,
R.string.notification_slot_3_key,
R.string.notification_slot_4_key,
};
public static final Integer[] SLOT_COMPACT_DEFAULTS = {0, 1, 2};
public static final int[] SLOT_COMPACT_PREF_KEYS = {
R.string.notification_slot_compact_0_key,
R.string.notification_slot_compact_1_key,
R.string.notification_slot_compact_2_key,
};
public static String getActionName(@NonNull final Context context, @Action final int action) {
switch (action) {
case PREVIOUS:
return context.getString(R.string.exo_controls_previous_description);
case NEXT:
return context.getString(R.string.exo_controls_next_description);
case REWIND:
return context.getString(R.string.exo_controls_rewind_description);
case FORWARD:
return context.getString(R.string.exo_controls_fastforward_description);
case SMART_REWIND_PREVIOUS:
return Localization.concatenateStrings(
context.getString(R.string.exo_controls_rewind_description),
context.getString(R.string.exo_controls_previous_description));
case SMART_FORWARD_NEXT:
return Localization.concatenateStrings(
context.getString(R.string.exo_controls_fastforward_description),
context.getString(R.string.exo_controls_next_description));
case PLAY_PAUSE:
return Localization.concatenateStrings(
context.getString(R.string.exo_controls_play_description),
context.getString(R.string.exo_controls_pause_description));
case PLAY_PAUSE_BUFFERING:
return Localization.concatenateStrings(
context.getString(R.string.exo_controls_play_description),
context.getString(R.string.exo_controls_pause_description),
context.getString(R.string.notification_action_buffering));
case REPEAT:
return context.getString(R.string.notification_action_repeat);
case SHUFFLE:
return context.getString(R.string.notification_action_shuffle);
case CLOSE:
return context.getString(R.string.close);
case NOTHING: default:
return context.getString(R.string.notification_action_nothing);
}
}
/**
* @param context the context to use
* @param sharedPreferences the shared preferences to query values from
* @param slotCount remove indices >= than this value (set to {@code 5} to do nothing, or make
* it lower if there are slots with empty actions)
* @return a sorted list of the indices of the slots to use as compact slots
*/
public static List<Integer> getCompactSlotsFromPreferences(
@NonNull final Context context,
final SharedPreferences sharedPreferences,
final int slotCount) {
final SortedSet<Integer> compactSlots = new TreeSet<>();
for (int i = 0; i < 3; i++) {
final int compactSlot = sharedPreferences.getInt(
context.getString(SLOT_COMPACT_PREF_KEYS[i]), Integer.MAX_VALUE);
if (compactSlot == Integer.MAX_VALUE) {
// settings not yet populated, return default values
return new ArrayList<>(Arrays.asList(SLOT_COMPACT_DEFAULTS));
}
// a negative value (-1) is set when the user does not want a particular compact slot
if (compactSlot >= 0 && compactSlot < slotCount) {
compactSlots.add(compactSlot);
}
}
return new ArrayList<>(compactSlots);
}
}

View File

@ -0,0 +1,371 @@
package org.schabi.newpipe.player;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.os.Build;
import android.util.Log;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.List;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE;
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD;
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND;
import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT;
import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PAUSE;
import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS;
import static org.schabi.newpipe.player.MainPlayer.ACTION_REPEAT;
import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE;
/**
* This is a utility class for player notifications.
*
* @author cool-student
*/
public final class NotificationUtil {
private static final String TAG = NotificationUtil.class.getSimpleName();
private static final boolean DEBUG = BasePlayer.DEBUG;
private static final int NOTIFICATION_ID = 123789;
@Nullable private static NotificationUtil instance = null;
@NotificationConstants.Action
private int[] notificationSlots = NotificationConstants.SLOT_DEFAULTS.clone();
private NotificationManagerCompat notificationManager;
private NotificationCompat.Builder notificationBuilder;
private NotificationUtil() {
}
public static NotificationUtil getInstance() {
if (instance == null) {
instance = new NotificationUtil();
}
return instance;
}
/////////////////////////////////////////////////////
// NOTIFICATION
/////////////////////////////////////////////////////
/**
* Creates the notification if it does not exist already and recreates it if forceRecreate is
* true. Updates the notification with the data in the player.
* @param player the player currently open, to take data from
* @param forceRecreate whether to force the recreation of the notification even if it already
* exists
*/
synchronized void createNotificationIfNeededAndUpdate(final VideoPlayerImpl player,
final boolean forceRecreate) {
if (forceRecreate || notificationBuilder == null) {
notificationBuilder = createNotification(player);
}
updateNotification(player);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
private synchronized NotificationCompat.Builder createNotification(
final VideoPlayerImpl player) {
if (DEBUG) {
Log.d(TAG, "createNotification()");
}
notificationManager = NotificationManagerCompat.from(player.context);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(player.context,
player.context.getString(R.string.notification_channel_id));
initializeNotificationSlots(player);
// count the number of real slots, to make sure compact slots indices are not out of bound
int nonNothingSlotCount = 5;
if (notificationSlots[3] == NotificationConstants.NOTHING) {
--nonNothingSlotCount;
}
if (notificationSlots[4] == NotificationConstants.NOTHING) {
--nonNothingSlotCount;
}
// build the compact slot indices array (need code to convert from Integer... because Java)
final List<Integer> compactSlotList = NotificationConstants.getCompactSlotsFromPreferences(
player.context, player.sharedPreferences, nonNothingSlotCount);
final int[] compactSlots = new int[compactSlotList.size()];
for (int i = 0; i < compactSlotList.size(); i++) {
compactSlots[i] = compactSlotList.get(i);
}
builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(player.mediaSessionManager.getSessionToken())
.setShowActionsInCompactView(compactSlots))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setColor(ContextCompat.getColor(player.context, R.color.gray))
.setCategory(NotificationCompat.CATEGORY_TRANSPORT)
.setDeleteIntent(PendingIntent.getBroadcast(player.context, NOTIFICATION_ID,
new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT));
return builder;
}
/**
* Updates the notification builder and the button icons depending on the playback state.
* @param player the player currently open, to take data from
*/
private synchronized void updateNotification(final VideoPlayerImpl player) {
if (DEBUG) {
Log.d(TAG, "updateNotification()");
}
// also update content intent, in case the user switched players
notificationBuilder.setContentIntent(PendingIntent.getActivity(player.context,
NOTIFICATION_ID, getIntentForNotification(player), FLAG_UPDATE_CURRENT));
notificationBuilder.setContentTitle(player.getVideoTitle());
notificationBuilder.setContentText(player.getUploaderName());
notificationBuilder.setTicker(player.getVideoTitle());
updateActions(notificationBuilder, player);
setLargeIcon(notificationBuilder, player);
}
@SuppressLint("RestrictedApi")
boolean shouldUpdateBufferingSlot() {
if (notificationBuilder.mActions.size() < 3) {
// this should never happen, but let's make sure notification actions are populated
return true;
}
// only second and third slot could contain PLAY_PAUSE_BUFFERING, update them only if they
// are not already in the buffering state (the only one with a null action intent)
return (notificationSlots[1] == NotificationConstants.PLAY_PAUSE_BUFFERING
&& notificationBuilder.mActions.get(1).actionIntent != null)
|| (notificationSlots[2] == NotificationConstants.PLAY_PAUSE_BUFFERING
&& notificationBuilder.mActions.get(2).actionIntent != null);
}
void createNotificationAndStartForeground(final VideoPlayerImpl player, final Service service) {
if (notificationBuilder == null) {
notificationBuilder = createNotification(player);
}
updateNotification(player);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
service.startForeground(NOTIFICATION_ID, notificationBuilder.build(),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
} else {
service.startForeground(NOTIFICATION_ID, notificationBuilder.build());
}
}
void cancelNotificationAndStopForeground(final Service service) {
service.stopForeground(true);
if (notificationManager != null) {
notificationManager.cancel(NOTIFICATION_ID);
}
notificationManager = null;
notificationBuilder = null;
}
/////////////////////////////////////////////////////
// ACTIONS
/////////////////////////////////////////////////////
private void initializeNotificationSlots(final VideoPlayerImpl player) {
for (int i = 0; i < 5; ++i) {
notificationSlots[i] = player.sharedPreferences.getInt(
player.context.getString(NotificationConstants.SLOT_PREF_KEYS[i]),
NotificationConstants.SLOT_DEFAULTS[i]);
}
}
@SuppressLint("RestrictedApi")
private void updateActions(final NotificationCompat.Builder builder,
final VideoPlayerImpl player) {
builder.mActions.clear();
for (int i = 0; i < 5; ++i) {
addAction(builder, player, notificationSlots[i]);
}
}
private void addAction(final NotificationCompat.Builder builder,
final VideoPlayerImpl player,
@NotificationConstants.Action final int slot) {
final NotificationCompat.Action action = getAction(player, slot);
if (action != null) {
builder.addAction(action);
}
}
@Nullable
private NotificationCompat.Action getAction(
final VideoPlayerImpl player,
@NotificationConstants.Action final int selectedAction) {
final int baseActionIcon = NotificationConstants.ACTION_ICONS[selectedAction];
switch (selectedAction) {
case NotificationConstants.PREVIOUS:
return getAction(player, baseActionIcon,
R.string.exo_controls_previous_description, ACTION_PLAY_PREVIOUS);
case NotificationConstants.NEXT:
return getAction(player, baseActionIcon,
R.string.exo_controls_next_description, ACTION_PLAY_NEXT);
case NotificationConstants.REWIND:
return getAction(player, baseActionIcon,
R.string.exo_controls_rewind_description, ACTION_FAST_REWIND);
case NotificationConstants.FORWARD:
return getAction(player, baseActionIcon,
R.string.exo_controls_fastforward_description, ACTION_FAST_FORWARD);
case NotificationConstants.SMART_REWIND_PREVIOUS:
if (player.playQueue != null && player.playQueue.size() > 1) {
return getAction(player, R.drawable.exo_notification_previous,
R.string.exo_controls_previous_description, ACTION_PLAY_PREVIOUS);
} else {
return getAction(player, R.drawable.exo_controls_rewind,
R.string.exo_controls_rewind_description, ACTION_FAST_REWIND);
}
case NotificationConstants.SMART_FORWARD_NEXT:
if (player.playQueue != null && player.playQueue.size() > 1) {
return getAction(player, R.drawable.exo_notification_next,
R.string.exo_controls_next_description, ACTION_PLAY_NEXT);
} else {
return getAction(player, R.drawable.exo_controls_fastforward,
R.string.exo_controls_fastforward_description, ACTION_FAST_FORWARD);
}
case NotificationConstants.PLAY_PAUSE_BUFFERING:
if (player.getCurrentState() == BasePlayer.STATE_PREFLIGHT
|| player.getCurrentState() == BasePlayer.STATE_BLOCKED
|| player.getCurrentState() == BasePlayer.STATE_BUFFERING) {
// null intent -> show hourglass icon that does nothing when clicked
return new NotificationCompat.Action(R.drawable.ic_hourglass_top_white_24dp_png,
player.context.getString(R.string.notification_action_buffering),
null);
}
case NotificationConstants.PLAY_PAUSE:
if (player.getCurrentState() == BasePlayer.STATE_COMPLETED) {
return getAction(player, R.drawable.ic_replay_white_24dp_png,
R.string.exo_controls_pause_description, ACTION_PLAY_PAUSE);
} else if (player.isPlaying()
|| player.getCurrentState() == BasePlayer.STATE_PREFLIGHT
|| player.getCurrentState() == BasePlayer.STATE_BLOCKED
|| player.getCurrentState() == BasePlayer.STATE_BUFFERING) {
return getAction(player, R.drawable.exo_notification_pause,
R.string.exo_controls_pause_description, ACTION_PLAY_PAUSE);
} else {
return getAction(player, R.drawable.exo_notification_play,
R.string.exo_controls_play_description, ACTION_PLAY_PAUSE);
}
case NotificationConstants.REPEAT:
if (player.getRepeatMode() == REPEAT_MODE_ALL) {
return getAction(player, R.drawable.exo_media_action_repeat_all,
R.string.exo_controls_repeat_all_description, ACTION_REPEAT);
} else if (player.getRepeatMode() == REPEAT_MODE_ONE) {
return getAction(player, R.drawable.exo_media_action_repeat_one,
R.string.exo_controls_repeat_one_description, ACTION_REPEAT);
} else /* player.getRepeatMode() == REPEAT_MODE_OFF */ {
return getAction(player, R.drawable.exo_media_action_repeat_off,
R.string.exo_controls_repeat_off_description, ACTION_REPEAT);
}
case NotificationConstants.SHUFFLE:
if (player.playQueue != null && player.playQueue.isShuffled()) {
return getAction(player, R.drawable.exo_controls_shuffle_on,
R.string.exo_controls_shuffle_on_description, ACTION_SHUFFLE);
} else {
return getAction(player, R.drawable.exo_controls_shuffle_off,
R.string.exo_controls_shuffle_off_description, ACTION_SHUFFLE);
}
case NotificationConstants.CLOSE:
return getAction(player, R.drawable.ic_close_white_24dp_png,
R.string.close, ACTION_CLOSE);
case NotificationConstants.NOTHING:
default:
// do nothing
return null;
}
}
private NotificationCompat.Action getAction(final VideoPlayerImpl player,
@DrawableRes final int drawable,
@StringRes final int title,
final String intentAction) {
return new NotificationCompat.Action(drawable, player.context.getString(title),
PendingIntent.getBroadcast(player.context, NOTIFICATION_ID,
new Intent(intentAction), FLAG_UPDATE_CURRENT));
}
private Intent getIntentForNotification(final VideoPlayerImpl player) {
if (player.audioPlayerSelected() || player.popupPlayerSelected()) {
// Means we play in popup or audio only. Let's show the play queue
return NavigationHelper.getPlayQueueActivityIntent(player.context);
} else {
// We are playing in fragment. Don't open another activity just show fragment. That's it
final Intent intent = NavigationHelper.getPlayerIntent(
player.context, MainActivity.class, null, true);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return intent;
}
}
/////////////////////////////////////////////////////
// BITMAP
/////////////////////////////////////////////////////
private void setLargeIcon(final NotificationCompat.Builder builder,
final VideoPlayerImpl player) {
final boolean scaleImageToSquareAspectRatio = player.sharedPreferences.getBoolean(
player.context.getString(R.string.scale_to_square_image_in_notifications_key),
false);
if (scaleImageToSquareAspectRatio) {
builder.setLargeIcon(getBitmapWithSquareAspectRatio(player.getThumbnail()));
} else {
builder.setLargeIcon(player.getThumbnail());
}
}
private Bitmap getBitmapWithSquareAspectRatio(final Bitmap bitmap) {
return getResizedBitmap(bitmap, bitmap.getWidth(), bitmap.getWidth());
}
private Bitmap getResizedBitmap(final Bitmap bitmap, final int newWidth, final int newHeight) {
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
final float scaleWidth = ((float) newWidth) / width;
final float scaleHeight = ((float) newHeight) / height;
final Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
}
}

View File

@ -360,11 +360,11 @@ public abstract class VideoPlayer extends BasePlayer
return true;
});
// apply caption language from previous user preference
if (userPreferredLanguage != null && (captionLanguage.equals(userPreferredLanguage)
|| searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage)
|| userPreferredLanguage.contains("(") && captionLanguage.startsWith(
userPreferredLanguage
.substring(0, userPreferredLanguage.indexOf('('))))) {
if (userPreferredLanguage != null
&& (captionLanguage.equals(userPreferredLanguage)
|| (searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage))
|| (userPreferredLanguage.contains("(") && captionLanguage.startsWith(
userPreferredLanguage.substring(0, userPreferredLanguage.indexOf('(')))))) {
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
if (textRendererIndex != RENDERER_UNAVAILABLE) {
trackSelector.setPreferredTextLanguage(captionLanguage);

View File

@ -55,6 +55,7 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@ -64,6 +65,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
@ -108,10 +110,11 @@ import static org.schabi.newpipe.player.MainPlayer.ACTION_OPEN_CONTROLS;
import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT;
import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PAUSE;
import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS;
import static org.schabi.newpipe.player.MainPlayer.ACTION_RECREATE_NOTIFICATION;
import static org.schabi.newpipe.player.MainPlayer.ACTION_REPEAT;
import static org.schabi.newpipe.player.MainPlayer.NOTIFICATION_ID;
import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.util.AnimationUtils.Type.SLIDE_AND_ALPHA;
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
@ -134,14 +137,12 @@ public class VideoPlayerImpl extends VideoPlayer
static final String POPUP_SAVED_WIDTH = "popup_saved_width";
static final String POPUP_SAVED_X = "popup_saved_x";
static final String POPUP_SAVED_Y = "popup_saved_y";
private static final int MINIMUM_SHOW_EXTRA_WIDTH_DP = 300;
private static final int IDLE_WINDOW_FLAGS = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
private static final int ONGOING_PLAYBACK_WINDOW_FLAGS = IDLE_WINDOW_FLAGS
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
private static final float MAX_GESTURE_LENGTH = 0.75f;
private static final int NOTIFICATION_UPDATES_BEFORE_RESET = 60;
private TextView titleTextView;
private TextView channelTextView;
@ -187,7 +188,6 @@ public class VideoPlayerImpl extends VideoPlayer
private boolean isVerticalVideo = false;
private boolean fragmentIsVisible = false;
boolean shouldUpdateOnProgress;
int timesNotificationUpdated;
private final MainPlayer service;
private PlayerServiceEventListener fragmentListener;
@ -198,9 +198,6 @@ public class VideoPlayerImpl extends VideoPlayer
@NonNull
private final AudioPlaybackResolver resolver;
private int cachedDuration;
private String cachedDurationString;
// Popup
private WindowManager.LayoutParams popupLayoutParams;
public WindowManager windowManager;
@ -312,6 +309,9 @@ public class VideoPlayerImpl extends VideoPlayer
titleTextView.setSelected(true);
channelTextView.setSelected(true);
// Prevent hiding of bottom sheet via swipe inside queue
this.itemsList.setNestedScrollingEnabled(false);
}
@Override
@ -578,29 +578,32 @@ public class VideoPlayerImpl extends VideoPlayer
setupScreenRotationButton();
}
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/
void onShuffleOrRepeatModeChanged() {
updatePlaybackButtons();
updatePlayback();
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
public void onRepeatModeChanged(final int i) {
super.onRepeatModeChanged(i);
updatePlaybackButtons();
updatePlayback();
service.resetNotification();
service.updateNotification(-1);
onShuffleOrRepeatModeChanged();
}
@Override
public void onShuffleClicked() {
super.onShuffleClicked();
updatePlaybackButtons();
updatePlayback();
onShuffleOrRepeatModeChanged();
}
/*//////////////////////////////////////////////////////////////////////////
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////////////////
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onPlayerError(final ExoPlaybackException error) {
@ -611,6 +614,13 @@ public class VideoPlayerImpl extends VideoPlayer
}
}
@Override
public void onTimelineChanged(final Timeline timeline, final int reason) {
super.onTimelineChanged(timeline, reason);
// force recreate notification to ensure seek bar is shown when preparation finishes
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, true);
}
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
super.onMetadataChanged(tag);
@ -619,8 +629,7 @@ public class VideoPlayerImpl extends VideoPlayer
titleTextView.setText(tag.getMetadata().getName());
channelTextView.setText(tag.getMetadata().getUploaderName());
service.resetNotification();
service.updateNotification(-1);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
updateMetadata();
}
@ -643,35 +652,17 @@ public class VideoPlayerImpl extends VideoPlayer
public void onUpdateProgress(final int currentProgress,
final int duration, final int bufferPercent) {
super.onUpdateProgress(currentProgress, duration, bufferPercent);
updateProgress(currentProgress, duration, bufferPercent);
if (!shouldUpdateOnProgress || getCurrentState() == BasePlayer.STATE_COMPLETED
|| getCurrentState() == BasePlayer.STATE_PAUSED || getPlayQueue() == null) {
return;
}
// setMetadata only updates the metadata when any of the metadata keys are null
mediaSessionManager.setMetadata(getVideoTitle(), getUploaderName(), getThumbnail(),
duration);
}
if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) {
service.resetNotification();
}
if (service.getBigNotRemoteView() != null) {
if (cachedDuration != duration) {
cachedDuration = duration;
cachedDurationString = getTimeString(duration);
}
service.getBigNotRemoteView()
.setProgressBar(R.id.notificationProgressBar,
duration, currentProgress, false);
service.getBigNotRemoteView()
.setTextViewText(R.id.notificationTime,
getTimeString(currentProgress) + " / " + cachedDurationString);
}
if (service.getNotRemoteView() != null) {
service.getNotRemoteView()
.setProgressBar(R.id.notificationProgressBar, duration, currentProgress, false);
}
service.updateNotification(-1);
@Override
public void onPlayQueueEdited() {
updatePlayback();
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
@ -709,62 +700,33 @@ public class VideoPlayerImpl extends VideoPlayer
}
/*//////////////////////////////////////////////////////////////////////////
// Player Overrides
//////////////////////////////////////////////////////////////////////////*/
// Player Overrides
//////////////////////////////////////////////////////////////////////////*/
@Override
public void toggleFullscreen() {
if (DEBUG) {
Log.d(TAG, "toggleFullscreen() called");
}
if (simpleExoPlayer == null || getCurrentMetadata() == null) {
if (popupPlayerSelected()
|| simpleExoPlayer == null
|| getCurrentMetadata() == null
|| fragmentListener == null) {
return;
}
if (popupPlayerSelected()) {
setRecovery();
service.removeViewFromParent();
final Intent intent = NavigationHelper.getPlayerIntent(
service,
MainActivity.class,
this.getPlayQueue(),
this.getRepeatMode(),
this.getPlaybackSpeed(),
this.getPlaybackPitch(),
this.getPlaybackSkipSilence(),
null,
true,
!isPlaying(),
isMuted()
);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Constants.KEY_SERVICE_ID,
getCurrentMetadata().getMetadata().getServiceId());
intent.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM);
intent.putExtra(Constants.KEY_URL, getVideoUrl());
intent.putExtra(Constants.KEY_TITLE, getVideoTitle());
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
service.onDestroy();
context.startActivity(intent);
return;
isFullscreen = !isFullscreen;
if (!isFullscreen) {
// Apply window insets because Android will not do it when orientation changes
// from landscape to portrait (open vertical video to reproduce)
getControlsRoot().setPadding(0, 0, 0, 0);
} else {
if (fragmentListener == null) {
return;
}
isFullscreen = !isFullscreen;
if (!isFullscreen) {
// Apply window insets because Android will not do it when orientation changes
// from landscape to portrait (open vertical video to reproduce)
getControlsRoot().setPadding(0, 0, 0, 0);
} else {
// Android needs tens milliseconds to send new insets but a user is able to see
// how controls changes it's position from `0` to `nav bar height` padding.
// So just hide the controls to hide this visual inconsistency
hideControls(0, 0);
}
fragmentListener.onFullscreenStateChanged(isFullscreen());
// Android needs tens milliseconds to send new insets but a user is able to see
// how controls changes it's position from `0` to `nav bar height` padding.
// So just hide the controls to hide this visual inconsistency
hideControls(0, 0);
}
fragmentListener.onFullscreenStateChanged(isFullscreen());
if (!isFullscreen()) {
titleTextView.setVisibility(View.GONE);
@ -778,6 +740,40 @@ public class VideoPlayerImpl extends VideoPlayer
setupScreenRotationButton();
}
public void switchFromPopupToMain() {
if (DEBUG) {
Log.d(TAG, "switchFromPopupToMain() called");
}
if (!popupPlayerSelected() || simpleExoPlayer == null || getCurrentMetadata() == null) {
return;
}
setRecovery();
service.removeViewFromParent();
final Intent intent = NavigationHelper.getPlayerIntent(
service,
MainActivity.class,
this.getPlayQueue(),
this.getRepeatMode(),
this.getPlaybackSpeed(),
this.getPlaybackPitch(),
this.getPlaybackSkipSilence(),
null,
true,
!isPlaying(),
isMuted()
);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Constants.KEY_SERVICE_ID,
getCurrentMetadata().getMetadata().getServiceId());
intent.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM);
intent.putExtra(Constants.KEY_URL, getVideoUrl());
intent.putExtra(Constants.KEY_TITLE, getVideoTitle());
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
service.onDestroy();
context.startActivity(intent);
}
@Override
public void onClick(final View v) {
super.onClick(v);
@ -805,9 +801,12 @@ public class VideoPlayerImpl extends VideoPlayer
} else if (v.getId() == openInBrowser.getId()) {
onOpenInBrowserClicked();
} else if (v.getId() == fullscreenButton.getId()) {
toggleFullscreen();
switchFromPopupToMain();
} else if (v.getId() == screenRotationButton.getId()) {
if (!isVerticalVideo) {
// Only if it's not a vertical video or vertical video but in landscape with locked
// orientation a screen orientation can be changed automatically
if (!isVerticalVideo
|| (service.isLandscape() && globalScreenOrientationLocked(service))) {
fragmentListener.onScreenRotationButtonClicked();
} else {
toggleFullscreen();
@ -823,7 +822,9 @@ public class VideoPlayerImpl extends VideoPlayer
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
if (v.getId() == playPauseButton.getId()) {
if (v.getId() == playPauseButton.getId()
// Hide controls in fullscreen immediately
|| (v.getId() == screenRotationButton.getId() && isFullscreen)) {
hideControls(0, 0);
} else {
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
@ -942,9 +943,8 @@ public class VideoPlayerImpl extends VideoPlayer
private void setupScreenRotationButton() {
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
final boolean tabletInLandscape = DeviceUtils.isTablet(service) && service.isLandscape();
final boolean showButton = videoPlayerSelected()
&& (orientationLocked || isVerticalVideo || tabletInLandscape);
&& (orientationLocked || isVerticalVideo || DeviceUtils.isTablet(service));
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service, isFullscreen()
? R.drawable.ic_fullscreen_exit_white_24dp
@ -956,6 +956,8 @@ public class VideoPlayerImpl extends VideoPlayer
if (orientationLocked
&& isFullscreen()
&& service.isLandscape() == isVerticalVideo
&& !DeviceUtils.isTv(service)
&& !DeviceUtils.isTablet(service)
&& fragmentListener != null) {
fragmentListener.onScreenRotationButtonClicked();
}
@ -986,6 +988,7 @@ public class VideoPlayerImpl extends VideoPlayer
super.onDismiss(menu);
if (isPlaying()) {
hideControls(DEFAULT_CONTROLS_DURATION, 0);
hideSystemUIIfNeeded();
}
}
@ -1010,15 +1013,6 @@ public class VideoPlayerImpl extends VideoPlayer
setInitialGestureValues();
queueLayout.getLayoutParams().height = height - queueLayout.getTop();
if (popupPlayerSelected()) {
final float widthDp = Math.abs(r - l) / service.getResources()
.getDisplayMetrics().density;
final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP
? View.VISIBLE
: View.GONE;
secondaryControls.setVisibility(visibility);
}
}
}
@ -1101,8 +1095,7 @@ public class VideoPlayerImpl extends VideoPlayer
animatePlayButtons(false, 100);
getRootView().setKeepScreenOn(false);
service.resetNotification();
service.updateNotification(R.drawable.exo_controls_play);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
@ -1110,8 +1103,9 @@ public class VideoPlayerImpl extends VideoPlayer
super.onBuffering();
getRootView().setKeepScreenOn(true);
service.resetNotification();
service.updateNotification(R.drawable.exo_controls_play);
if (NotificationUtil.getInstance().shouldUpdateBufferingSlot()) {
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
}
@Override
@ -1129,10 +1123,7 @@ public class VideoPlayerImpl extends VideoPlayer
checkLandscape();
getRootView().setKeepScreenOn(true);
service.resetNotification();
service.updateNotification(R.drawable.exo_controls_pause);
service.startForeground(NOTIFICATION_ID, service.getNotBuilder().build());
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
@ -1148,13 +1139,12 @@ public class VideoPlayerImpl extends VideoPlayer
updateWindowFlags(IDLE_WINDOW_FLAGS);
service.resetNotification();
service.updateNotification(R.drawable.exo_controls_play);
// Remove running notification when user don't want music (or video in popup)
// to be played in background
if (!minimizeOnPopupEnabled() && !backgroundPlaybackEnabled() && videoPlayerSelected()) {
service.stopForeground(true);
NotificationUtil.getInstance().cancelNotificationAndStopForeground(service);
} else {
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
getRootView().setKeepScreenOn(false);
@ -1166,8 +1156,7 @@ public class VideoPlayerImpl extends VideoPlayer
animatePlayButtons(false, 100);
getRootView().setKeepScreenOn(true);
service.resetNotification();
service.updateNotification(R.drawable.exo_controls_play);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@ -1177,20 +1166,20 @@ public class VideoPlayerImpl extends VideoPlayer
playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp);
animatePlayButtons(true, DEFAULT_CONTROLS_DURATION);
});
getRootView().setKeepScreenOn(false);
getRootView().setKeepScreenOn(false);
updateWindowFlags(IDLE_WINDOW_FLAGS);
service.resetNotification();
service.updateNotification(R.drawable.ic_replay_white_24dp);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
if (isFullscreen) {
toggleFullscreen();
}
super.onCompleted();
}
@Override
public void destroy() {
super.destroy();
service.getContentResolver().unregisterContentObserver(settingsContentObserver);
}
@ -1214,6 +1203,8 @@ public class VideoPlayerImpl extends VideoPlayer
intentFilter.addAction(ACTION_PLAY_NEXT);
intentFilter.addAction(ACTION_FAST_REWIND);
intentFilter.addAction(ACTION_FAST_FORWARD);
intentFilter.addAction(ACTION_SHUFFLE);
intentFilter.addAction(ACTION_RECREATE_NOTIFICATION);
intentFilter.addAction(VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED);
intentFilter.addAction(VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED);
@ -1263,6 +1254,17 @@ public class VideoPlayerImpl extends VideoPlayer
case ACTION_REPEAT:
onRepeatClicked();
break;
case ACTION_SHUFFLE:
onShuffleClicked();
break;
case ACTION_RECREATE_NOTIFICATION:
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, true);
break;
case Intent.ACTION_HEADSET_PLUG: //FIXME
/*notificationManager.cancel(NOTIFICATION_ID);
mediaSessionManager.dispose();
mediaSessionManager.enable(getBaseContext(), basePlayerImpl.simpleExoPlayer);*/
break;
case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED:
fragmentIsVisible = true;
useVideoSource(true);
@ -1302,7 +1304,6 @@ public class VideoPlayerImpl extends VideoPlayer
}
break;
}
service.resetNotification();
}
/*//////////////////////////////////////////////////////////////////////////
@ -1314,10 +1315,7 @@ public class VideoPlayerImpl extends VideoPlayer
final View view,
final Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
// rebuild notification here since remote view does not release bitmaps,
// causing memory leaks
service.resetNotification();
service.updateNotification(-1);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
@ -1325,20 +1323,18 @@ public class VideoPlayerImpl extends VideoPlayer
final View view,
final FailReason failReason) {
super.onLoadingFailed(imageUri, view, failReason);
service.resetNotification();
service.updateNotification(-1);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
@Override
public void onLoadingCancelled(final String imageUri, final View view) {
super.onLoadingCancelled(imageUri, view);
service.resetNotification();
service.updateNotification(-1);
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void setInitialGestureValues() {
if (getAudioReactor() != null) {
@ -1492,6 +1488,10 @@ public class VideoPlayerImpl extends VideoPlayer
}
}
public void disablePreloadingOfCurrentTrack() {
getLoadController().disablePreloadingOfCurrentTrack();
}
protected void setMuteButton(final ImageButton button, final boolean isMuted) {
button.setImageDrawable(AppCompatResources.getDrawable(service, isMuted
? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_up_white_24dp));

View File

@ -13,6 +13,7 @@ public class LoadController implements LoadControl {
private final long initialPlaybackBufferUs;
private final LoadControl internalLoadControl;
private boolean preloadingEnabled = true;
/*//////////////////////////////////////////////////////////////////////////
// Default Load Control
@ -41,6 +42,7 @@ public class LoadController implements LoadControl {
@Override
public void onPrepared() {
preloadingEnabled = true;
internalLoadControl.onPrepared();
}
@ -52,11 +54,13 @@ public class LoadController implements LoadControl {
@Override
public void onStopped() {
preloadingEnabled = true;
internalLoadControl.onStopped();
}
@Override
public void onReleased() {
preloadingEnabled = true;
internalLoadControl.onReleased();
}
@ -78,6 +82,9 @@ public class LoadController implements LoadControl {
@Override
public boolean shouldContinueLoading(final long bufferedDurationUs,
final float playbackSpeed) {
if (!preloadingEnabled) {
return false;
}
return internalLoadControl.shouldContinueLoading(bufferedDurationUs, playbackSpeed);
}
@ -90,4 +97,8 @@ public class LoadController implements LoadControl {
.shouldStartPlayback(bufferedDurationUs, playbackSpeed, rebuffering);
return isInitialPlaybackBufferFilled || isInternalStartingPlayback;
}
public void disablePreloadingOfCurrentTrack() {
preloadingEnabled = false;
}
}

View File

@ -3,44 +3,58 @@ package org.schabi.newpipe.player.helper;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.MediaMetadata;
import android.os.Build;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.media.app.NotificationCompat.MediaStyle;
import androidx.media.session.MediaButtonReceiver;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
import org.schabi.newpipe.player.mediasession.PlayQueueNavigator;
import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController;
public class MediaSessionManager {
private static final String TAG = "MediaSessionManager";
private static final String TAG = MediaSessionManager.class.getSimpleName();
public static final boolean DEBUG = MainActivity.DEBUG;
@NonNull
private final MediaSessionCompat mediaSession;
@NonNull
private final MediaSessionConnector sessionConnector;
private int lastAlbumArtHashCode;
public MediaSessionManager(@NonNull final Context context,
@NonNull final Player player,
@NonNull final MediaSessionCallback callback) {
this.mediaSession = new MediaSessionCompat(context, TAG);
this.mediaSession.setActive(true);
mediaSession = new MediaSessionCompat(context, TAG);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
| MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setActive(true);
this.sessionConnector = new MediaSessionConnector(mediaSession);
this.sessionConnector.setControlDispatcher(new PlayQueuePlaybackController(callback));
this.sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback));
this.sessionConnector.setPlayer(player);
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_NONE, -1, 1)
.setActions(PlaybackStateCompat.ACTION_SEEK_TO
| PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_PAUSE // was play and pause now play/pause
| PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
| PlaybackStateCompat.ACTION_SET_REPEAT_MODE
| PlaybackStateCompat.ACTION_STOP)
.build());
sessionConnector = new MediaSessionConnector(mediaSession);
sessionConnector.setControlDispatcher(new PlayQueuePlaybackController(callback));
sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback));
sessionConnector.setPlayer(player);
}
@Nullable
@ -49,46 +63,78 @@ public class MediaSessionManager {
return MediaButtonReceiver.handleIntent(mediaSession, intent);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void setLockScreenArt(final NotificationCompat.Builder builder,
@Nullable final Bitmap thumbnailBitmap) {
if (thumbnailBitmap == null || !mediaSession.isActive()) {
public MediaSessionCompat.Token getSessionToken() {
return mediaSession.getSessionToken();
}
public void setMetadata(final String title,
final String artist,
final Bitmap albumArt,
final long duration) {
if (albumArt == null || !mediaSession.isActive()) {
return;
}
mediaSession.setMetadata(
new MediaMetadataCompat.Builder()
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, thumbnailBitmap)
.build()
);
if (DEBUG) {
if (getMetadataAlbumArt() == null) {
Log.d(TAG, "N_getMetadataAlbumArt: thumb == null");
}
if (getMetadataTitle() == null) {
Log.d(TAG, "N_getMetadataTitle: title == null");
}
if (getMetadataArtist() == null) {
Log.d(TAG, "N_getMetadataArtist: artist == null");
}
if (getMetadataDuration() <= 1) {
Log.d(TAG, "N_getMetadataDuration: duration <= 1; " + getMetadataDuration());
}
}
final MediaStyle mediaStyle = new MediaStyle()
.setMediaSession(mediaSession.getSessionToken());
if (getMetadataAlbumArt() == null || getMetadataTitle() == null
|| getMetadataArtist() == null || getMetadataDuration() <= 1
|| albumArt.hashCode() != lastAlbumArtHashCode) {
if (DEBUG) {
Log.d(TAG, "setMetadata: N_Metadata update: t: " + title + " a: " + artist
+ " thumb: " + albumArt.hashCode() + " d: " + duration);
}
builder.setStyle(mediaStyle);
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt)
.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, albumArt)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration).build());
lastAlbumArtHashCode = albumArt.hashCode();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void clearLockScreenArt(final NotificationCompat.Builder builder) {
mediaSession.setMetadata(
new MediaMetadataCompat.Builder()
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null)
.build()
);
private Bitmap getMetadataAlbumArt() {
return mediaSession.getController().getMetadata()
.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
}
final MediaStyle mediaStyle = new MediaStyle()
.setMediaSession(mediaSession.getSessionToken());
private String getMetadataTitle() {
return mediaSession.getController().getMetadata()
.getString(MediaMetadataCompat.METADATA_KEY_TITLE);
}
builder.setStyle(mediaStyle);
private String getMetadataArtist() {
return mediaSession.getController().getMetadata()
.getString(MediaMetadataCompat.METADATA_KEY_ARTIST);
}
private long getMetadataDuration() {
return mediaSession.getController().getMetadata()
.getLong(MediaMetadataCompat.METADATA_KEY_DURATION);
}
/**
* Should be called on player destruction to prevent leakage.
*/
public void dispose() {
this.sessionConnector.setPlayer(null);
this.sessionConnector.setQueueNavigator(null);
this.mediaSession.setActive(false);
this.mediaSession.release();
sessionConnector.setPlayer(null);
sessionConnector.setQueueNavigator(null);
mediaSession.setActive(false);
mediaSession.release();
}
}

View File

@ -28,6 +28,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.ListHelper;
import java.lang.annotation.Retention;
import java.text.DecimalFormat;
@ -248,6 +249,18 @@ public final class PlayerHelper {
}
}
public static boolean isAutoplayAllowedByUser(@NonNull final Context context) {
switch (PlayerHelper.getAutoplayType(context)) {
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
return false;
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
return !ListHelper.isMeteredNetwork(context);
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
default:
return true;
}
}
@NonNull
public static SeekParameters getSeekParameters(@NonNull final Context context) {
return isUsingInexactSeek(context) ? SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;

View File

@ -255,21 +255,21 @@ public class MediaSourceManager {
// Loading and Syncing
switch (event.type()) {
case INIT:
case REORDER:
case ERROR:
case SELECT:
case INIT: case REORDER: case ERROR: case SELECT:
loadImmediate(); // low frequency, critical events
break;
case APPEND:
case REMOVE:
case MOVE:
case RECOVERY:
case APPEND: case REMOVE: case MOVE: case RECOVERY:
default:
loadDebounced(); // high frequency or noncritical events
break;
}
// update ui and notification
switch (event.type()) {
case APPEND: case REMOVE: case MOVE: case REORDER:
playbackListener.onPlayQueueEdited();
}
if (!isPlayQueueReady()) {
maybeBlock();
playQueue.fetch();

View File

@ -69,7 +69,7 @@ public interface PlaybackListener {
MediaSource sourceOf(PlayQueueItem item, StreamInfo info);
/**
* Called when the play queue can no longer to played or used.
* Called when the play queue can no longer be played or used.
* Currently, this means the play queue is empty and complete.
* Signals to the listener that it should shutdown.
* <p>
@ -77,4 +77,13 @@ public interface PlaybackListener {
* </p>
*/
void onPlaybackShutdown();
/**
* Called whenever the play queue was edited (items were added, deleted or moved),
* use this to e.g. update notification buttons or fragment ui.
* <p>
* May be called at any time.
* </p>
*/
void onPlayQueueEdited();
}

View File

@ -20,7 +20,8 @@ public enum UserAction {
DELETE_FROM_HISTORY("delete from history"),
PLAY_STREAM("Play stream"),
DOWNLOAD_POSTPROCESSING("download post-processing"),
DOWNLOAD_FAILED("download failed");
DOWNLOAD_FAILED("download failed"),
PREFERENCES_MIGRATION("migration of preferences");
private final String message;

View File

@ -5,12 +5,12 @@ import android.os.Bundle;
import androidx.preference.PreferenceManager;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceFragmentCompat;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.util.ThemeHelper;
public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
@ -25,24 +25,16 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
}
@Override
public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
public void onViewCreated(@NonNull final View rootView,
@Nullable final Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
setDivider(null);
updateTitle();
ThemeHelper.setTitleToAppCompatActivity(getActivity(), getPreferenceScreen().getTitle());
}
@Override
public void onResume() {
super.onResume();
updateTitle();
}
private void updateTitle() {
if (getActivity() instanceof AppCompatActivity) {
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(getPreferenceScreen().getTitle());
}
}
ThemeHelper.setTitleToAppCompatActivity(getActivity(), getPreferenceScreen().getTitle());
}
}

View File

@ -10,6 +10,7 @@ import androidx.preference.PreferenceManager;
import org.schabi.newpipe.R;
import java.io.File;
import java.util.Set;
/*
* Created by k3b on 07.01.2016.
@ -38,6 +39,22 @@ public final class NewPipeSettings {
private NewPipeSettings() { }
public static void initSettings(final Context context) {
// check if there are entries in the prefs to determine whether this is the first app run
Boolean isFirstRun = null;
final Set<String> prefsKeys = PreferenceManager.getDefaultSharedPreferences(context)
.getAll().keySet();
for (final String key: prefsKeys) {
// ACRA stores some info in the prefs during app initialization
// which happens before this method is called. Therefore ignore ACRA-related keys.
if (!key.toLowerCase().startsWith("acra")) {
isFirstRun = false;
break;
}
}
if (isFirstRun == null) {
isFirstRun = true;
}
PreferenceManager.setDefaultValues(context, R.xml.appearance_settings, true);
PreferenceManager.setDefaultValues(context, R.xml.content_settings, true);
PreferenceManager.setDefaultValues(context, R.xml.download_settings, true);
@ -48,6 +65,8 @@ public final class NewPipeSettings {
getVideoDownloadFolder(context);
getAudioDownloadFolder(context);
SettingMigrations.initMigrations(context, isFirstRun);
}
private static void getVideoDownloadFolder(final Context context) {

View File

@ -0,0 +1,270 @@
package org.schabi.newpipe.settings;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.fragment.app.Fragment;
import org.schabi.newpipe.R;
import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.NotificationConstants;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.FocusOverlayView;
import java.util.List;
public class NotificationSettingsFragment extends Fragment {
private Switch scaleSwitch;
private NotificationSlot[] notificationSlots;
private SharedPreferences pref;
private List<Integer> compactSlots;
private String scaleKey;
////////////////////////////////////////////////////////////////////////////
// Lifecycle
////////////////////////////////////////////////////////////////////////////
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pref = PreferenceManager.getDefaultSharedPreferences(requireContext());
scaleKey = getString(R.string.scale_to_square_image_in_notifications_key);
}
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
return inflater.inflate(R.layout.settings_notification, container, false);
}
@Override
public void onViewCreated(@NonNull final View rootView,
@Nullable final Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
setupScaleSwitch(rootView);
setupActions(rootView);
}
@Override
public void onResume() {
super.onResume();
ThemeHelper.setTitleToAppCompatActivity(getActivity(),
getString(R.string.settings_category_notification_title));
}
@Override
public void onPause() {
super.onPause();
saveChanges();
requireContext().sendBroadcast(new Intent(MainPlayer.ACTION_RECREATE_NOTIFICATION));
}
////////////////////////////////////////////////////////////////////////////
// Setup
////////////////////////////////////////////////////////////////////////////
private void setupScaleSwitch(@NonNull final View view) {
scaleSwitch = view.findViewById(R.id.notificationScaleSwitch);
scaleSwitch.setChecked(pref.getBoolean(scaleKey, false));
view.findViewById(R.id.notificationScaleSwitchClickableArea)
.setOnClickListener(v -> scaleSwitch.toggle());
}
private void setupActions(@NonNull final View view) {
compactSlots =
NotificationConstants.getCompactSlotsFromPreferences(requireContext(), pref, 5);
notificationSlots = new NotificationSlot[5];
for (int i = 0; i < 5; i++) {
notificationSlots[i] = new NotificationSlot(i, view);
}
}
////////////////////////////////////////////////////////////////////////////
// Saving
////////////////////////////////////////////////////////////////////////////
private void saveChanges() {
final SharedPreferences.Editor editor = pref.edit();
editor.putBoolean(scaleKey, scaleSwitch.isChecked());
for (int i = 0; i < 3; i++) {
editor.putInt(getString(NotificationConstants.SLOT_COMPACT_PREF_KEYS[i]),
(i < compactSlots.size() ? compactSlots.get(i) : -1));
}
for (int i = 0; i < 5; i++) {
editor.putInt(getString(NotificationConstants.SLOT_PREF_KEYS[i]),
notificationSlots[i].selectedAction);
}
editor.apply();
}
////////////////////////////////////////////////////////////////////////////
// Notification action
////////////////////////////////////////////////////////////////////////////
private static final int[] SLOT_ITEMS = {
R.id.notificationAction0,
R.id.notificationAction1,
R.id.notificationAction2,
R.id.notificationAction3,
R.id.notificationAction4,
};
private static final int[] SLOT_TITLES = {
R.string.notification_action_0_title,
R.string.notification_action_1_title,
R.string.notification_action_2_title,
R.string.notification_action_3_title,
R.string.notification_action_4_title,
};
private class NotificationSlot {
final int i;
@NotificationConstants.Action int selectedAction;
ImageView icon;
TextView summary;
NotificationSlot(final int actionIndex, final View parentView) {
this.i = actionIndex;
final View view = parentView.findViewById(SLOT_ITEMS[i]);
setupSelectedAction(view);
setupTitle(view);
setupCheckbox(view);
}
void setupTitle(final View view) {
((TextView) view.findViewById(R.id.notificationActionTitle))
.setText(SLOT_TITLES[i]);
view.findViewById(R.id.notificationActionClickableArea).setOnClickListener(
v -> openActionChooserDialog());
}
void setupCheckbox(final View view) {
final CheckBox compactSlotCheckBox = view.findViewById(R.id.notificationActionCheckBox);
compactSlotCheckBox.setChecked(compactSlots.contains(i));
view.findViewById(R.id.notificationActionCheckBoxClickableArea).setOnClickListener(
v -> {
if (compactSlotCheckBox.isChecked()) {
compactSlots.remove((Integer) i);
} else if (compactSlots.size() < 3) {
compactSlots.add(i);
} else {
Toast.makeText(requireContext(),
R.string.notification_actions_at_most_three,
Toast.LENGTH_SHORT).show();
return;
}
compactSlotCheckBox.toggle();
});
}
void setupSelectedAction(final View view) {
icon = view.findViewById(R.id.notificationActionIcon);
summary = view.findViewById(R.id.notificationActionSummary);
selectedAction = pref.getInt(getString(NotificationConstants.SLOT_PREF_KEYS[i]),
NotificationConstants.SLOT_DEFAULTS[i]);
updateInfo();
}
void updateInfo() {
if (NotificationConstants.ACTION_ICONS[selectedAction] == 0) {
icon.setImageDrawable(null);
} else {
icon.setImageDrawable(AppCompatResources.getDrawable(requireContext(),
NotificationConstants.ACTION_ICONS[selectedAction]));
}
summary.setText(NotificationConstants.getActionName(requireContext(), selectedAction));
}
void openActionChooserDialog() {
final LayoutInflater inflater = LayoutInflater.from(requireContext());
final LinearLayout rootLayout = (LinearLayout) inflater.inflate(
R.layout.single_choice_dialog_view, null, false);
final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list);
final AlertDialog alertDialog = new AlertDialog.Builder(requireContext())
.setTitle(SLOT_TITLES[i])
.setView(radioGroup)
.setCancelable(true)
.create();
final View.OnClickListener radioButtonsClickListener = v -> {
selectedAction = NotificationConstants.SLOT_ALLOWED_ACTIONS[i][v.getId()];
updateInfo();
alertDialog.dismiss();
};
for (int id = 0; id < NotificationConstants.SLOT_ALLOWED_ACTIONS[i].length; ++id) {
final int action = NotificationConstants.SLOT_ALLOWED_ACTIONS[i][id];
final RadioButton radioButton
= (RadioButton) inflater.inflate(R.layout.list_radio_icon_item, null);
// if present set action icon with correct color
if (NotificationConstants.ACTION_ICONS[action] != 0) {
final Drawable drawable = AppCompatResources.getDrawable(requireContext(),
NotificationConstants.ACTION_ICONS[action]);
if (drawable != null) {
final int color = ThemeHelper.resolveColorFromAttr(requireContext(),
android.R.attr.textColorPrimary);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTint(color);
} else {
drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
radioButton.setCompoundDrawablesWithIntrinsicBounds(
null, null, drawable, null);
}
}
radioButton.setText(NotificationConstants.getActionName(requireContext(), action));
radioButton.setChecked(action == selectedAction);
radioButton.setId(id);
radioButton.setLayoutParams(new RadioGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
radioButton.setOnClickListener(radioButtonsClickListener);
radioGroup.addView(radioButton);
}
alertDialog.show();
if (DeviceUtils.isTv(requireContext())) {
FocusOverlayView.setupFocusObserver(alertDialog);
}
}
}
}

View File

@ -22,9 +22,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.fragment.app.Fragment;
@ -117,7 +115,8 @@ public class PeertubeInstanceListFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
updateTitle();
ThemeHelper.setTitleToAppCompatActivity(getActivity(),
getString(R.string.peertube_instance_url_title));
}
@Override
@ -176,15 +175,6 @@ public class PeertubeInstanceListFragment extends Fragment {
sharedPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply();
}
private void updateTitle() {
if (getActivity() instanceof AppCompatActivity) {
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.peertube_instance_url_title);
}
}
}
private void saveChanges() {
final JsonStringWriter jsonWriter = JsonWriter.string().object().array("instances");
for (final PeertubeInstance instance : instanceList) {

View File

@ -0,0 +1,140 @@
package org.schabi.newpipe.settings;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import androidx.preference.PreferenceManager;
import org.schabi.newpipe.R;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorActivity.ErrorInfo;
import org.schabi.newpipe.report.UserAction;
import static org.schabi.newpipe.MainActivity.DEBUG;
public final class SettingMigrations {
private static final String TAG = SettingMigrations.class.toString();
/**
* Version number for preferences. Must be incremented every time a migration is necessary.
*/
public static final int VERSION = 2;
private static SharedPreferences sp;
public static final Migration MIGRATION_0_1 = new Migration(0, 1) {
@Override
public void migrate(final Context context) {
// We changed the content of the dialog which opens when sharing a link to NewPipe
// by removing the "open detail page" option.
// Therefore, show the dialog once again to ensure users need to choose again and are
// aware of the changed dialog.
final SharedPreferences.Editor editor = sp.edit();
editor.putString(context.getString(R.string.preferred_open_action_key),
context.getString(R.string.always_ask_open_action_key));
editor.apply();
}
};
public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
protected void migrate(final Context context) {
// The new application workflow introduced in #2907 allows minimizing videos
// while playing to do other stuff within the app.
// For an even better workflow, we minimize a stream when switching the app to play in
// background.
// Therefore, set default value to background, if it has not been changed yet.
final String minimizeOnExitKey = context.getString(R.string.minimize_on_exit_key);
if (sp.getString(minimizeOnExitKey, "")
.equals(context.getString(R.string.minimize_on_exit_none_key))) {
final SharedPreferences.Editor editor = sp.edit();
editor.putString(minimizeOnExitKey,
context.getString(R.string.minimize_on_exit_background_key));
editor.apply();
}
}
};
/**
* List of all implemented migrations.
* <p>
* <b>Append new migrations to the end of the list</b> to keep it sorted ascending.
* If not sorted correctly, migrations which depend on each other, may fail.
*/
private static final Migration[] SETTING_MIGRATIONS = {
MIGRATION_0_1,
MIGRATION_1_2
};
public static void initMigrations(final Context context, final boolean isFirstRun) {
// setup migrations and check if there is something to do
sp = PreferenceManager.getDefaultSharedPreferences(context);
final String lastPrefVersionKey = context.getString(R.string.last_used_preferences_version);
final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0);
// no migration to run, already up to date
if (isFirstRun) {
sp.edit().putInt(lastPrefVersionKey, VERSION).apply();
return;
} else if (lastPrefVersion == VERSION) {
return;
}
// run migrations
int currentVersion = lastPrefVersion;
for (final Migration currentMigration : SETTING_MIGRATIONS) {
try {
if (currentMigration.shouldMigrate(currentVersion)) {
if (DEBUG) {
Log.d(TAG, "Migrating preferences from version "
+ currentVersion + " to " + currentMigration.newVersion);
}
currentMigration.migrate(context);
currentVersion = currentMigration.newVersion;
}
} catch (final Exception e) {
// save the version with the last successful migration and report the error
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
final ErrorInfo errorInfo = ErrorInfo.make(
UserAction.PREFERENCES_MIGRATION,
"none",
"Migrating preferences from version " + lastPrefVersion + " to "
+ VERSION + ". "
+ "Error at " + currentVersion + " => " + ++currentVersion,
0
);
ErrorActivity.reportError(context, e, SettingMigrations.class, null, errorInfo);
return;
}
}
// store the current preferences version
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
}
private SettingMigrations() { }
abstract static class Migration {
public final int oldVersion;
public final int newVersion;
protected Migration(final int oldVersion, final int newVersion) {
this.oldVersion = oldVersion;
this.newVersion = newVersion;
}
/**
* @param currentVersion current settings version
* @return Returns whether this migration should be run.
* A migration is necessary if the old version of this migration is lower than or equal to
* the current settings version.
*/
private boolean shouldMigrate(final int currentVersion) {
return oldVersion >= currentVersion;
}
protected abstract void migrate(Context context);
}
}

View File

@ -16,9 +16,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.fragment.app.Fragment;
@ -92,7 +90,8 @@ public class ChooseTabsFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
updateTitle();
ThemeHelper.setTitleToAppCompatActivity(getActivity(),
getString(R.string.main_page_content));
}
@Override
@ -137,15 +136,6 @@ public class ChooseTabsFragment extends Fragment {
tabList.addAll(tabsManager.getTabs());
}
private void updateTitle() {
if (getActivity() instanceof AppCompatActivity) {
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.main_page_content);
}
}
}
private void saveChanges() {
tabsManager.saveTabs(tabList);
}

View File

@ -57,7 +57,7 @@ import org.schabi.newpipe.settings.SettingsActivity;
import java.util.ArrayList;
@SuppressWarnings({"unused", "WeakerAccess"})
@SuppressWarnings({"unused"})
public final class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
public static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
@ -69,16 +69,18 @@ public final class NavigationHelper {
//////////////////////////////////////////////////////////////////////////*/
@NonNull
public static Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class targetClazz,
@NonNull final PlayQueue playQueue,
@Nullable final String quality,
final boolean resumePlayback) {
public static <T> Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class<T> targetClazz,
@Nullable final PlayQueue playQueue,
@Nullable final String quality,
final boolean resumePlayback) {
final Intent intent = new Intent(context, targetClazz);
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
if (cacheKey != null) {
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
if (playQueue != null) {
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
if (cacheKey != null) {
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
}
}
if (quality != null) {
intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
@ -90,53 +92,51 @@ public final class NavigationHelper {
}
@NonNull
public static Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class targetClazz,
@NonNull final PlayQueue playQueue,
final boolean resumePlayback) {
public static <T> Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class<T> targetClazz,
@Nullable final PlayQueue playQueue,
final boolean resumePlayback) {
return getPlayerIntent(context, targetClazz, playQueue, null, resumePlayback);
}
@NonNull
public static Intent getPlayerEnqueueIntent(@NonNull final Context context,
@NonNull final Class targetClazz,
@NonNull final PlayQueue playQueue,
final boolean selectOnAppend,
final boolean resumePlayback) {
public static <T> Intent getPlayerEnqueueIntent(@NonNull final Context context,
@NonNull final Class<T> targetClazz,
@Nullable final PlayQueue playQueue,
final boolean selectOnAppend,
final boolean resumePlayback) {
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
.putExtra(BasePlayer.APPEND_ONLY, true)
.putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend);
}
@NonNull
public static Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class targetClazz,
@NonNull final PlayQueue playQueue,
final int repeatMode,
final float playbackSpeed,
final float playbackPitch,
final boolean playbackSkipSilence,
@Nullable final String playbackQuality,
final boolean resumePlayback,
final boolean startPaused,
final boolean isMuted) {
public static <T> Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class<T> targetClazz,
@Nullable final PlayQueue playQueue,
final int repeatMode,
final float playbackSpeed,
final float playbackPitch,
final boolean playbackSkipSilence,
@Nullable final String playbackQuality,
final boolean resumePlayback,
final boolean startPaused,
final boolean isMuted) {
return getPlayerIntent(context, targetClazz, playQueue, playbackQuality, resumePlayback)
.putExtra(BasePlayer.REPEAT_MODE, repeatMode)
.putExtra(BasePlayer.START_PAUSED, startPaused)
.putExtra(BasePlayer.IS_MUTED, isMuted);
}
public static void playOnMainPlayer(
final AppCompatActivity activity,
final PlayQueue queue,
final boolean autoPlay) {
public static void playOnMainPlayer(final AppCompatActivity activity,
final PlayQueue queue,
final boolean autoPlay) {
playOnMainPlayer(activity.getSupportFragmentManager(), queue, autoPlay);
}
public static void playOnMainPlayer(
final FragmentManager fragmentManager,
final PlayQueue queue,
final boolean autoPlay) {
public static void playOnMainPlayer(final FragmentManager fragmentManager,
final PlayQueue queue,
final boolean autoPlay) {
final PlayQueueItem currentStream = queue.getItem();
openVideoDetailFragment(
fragmentManager,
@ -148,7 +148,7 @@ public final class NavigationHelper {
}
public static void playOnMainPlayer(@NonNull final Context context,
@NonNull final PlayQueue queue,
@Nullable final PlayQueue queue,
@NonNull final StreamingService.LinkType linkType,
@NonNull final String url,
@NonNull final String title,
@ -553,18 +553,14 @@ public final class NavigationHelper {
return true;
}
public static Intent getBackgroundPlayerActivityIntent(final Context context) {
return getServicePlayerActivityIntent(context, BackgroundPlayerActivity.class);
}
private static Intent getServicePlayerActivityIntent(final Context context,
final Class activityClass) {
final Intent intent = new Intent(context, activityClass);
public static Intent getPlayQueueActivityIntent(final Context context) {
final Intent intent = new Intent(context, BackgroundPlayerActivity.class);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
return intent;
}
/*//////////////////////////////////////////////////////////////////////////
// Link handling
//////////////////////////////////////////////////////////////////////////*/

View File

@ -19,6 +19,7 @@
package org.schabi.newpipe.util;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.preference.PreferenceManager;
@ -26,7 +27,10 @@ import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import androidx.annotation.AttrRes;
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import org.schabi.newpipe.R;
@ -231,4 +235,20 @@ public final class ThemeHelper {
return PreferenceManager.getDefaultSharedPreferences(context)
.getString(themeKey, defaultTheme);
}
/**
* Sets the title to the activity, if the activity is an {@link AppCompatActivity} and has an
* action bar.
* @param activity the activity to set the title of
* @param title the title to set to the activity
*/
public static void setTitleToAppCompatActivity(@Nullable final Activity activity,
final CharSequence title) {
if (activity instanceof AppCompatActivity) {
final ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(title);
}
}
}
}

View File

@ -5,6 +5,7 @@ import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.google.android.material.appbar.CollapsingToolbarLayout;
public class CustomCollapsingToolbarLayout extends CollapsingToolbarLayout {
@ -27,8 +28,10 @@ public class CustomCollapsingToolbarLayout extends CollapsingToolbarLayout {
}
/**
* CollapsingToolbarLayout overrides our logic with fitsSystemWindows and ruins the layout.
* Override Google's method
* CollapsingToolbarLayout sets it's own setOnApplyInsetsListener which consumes
* system insets {@link CollapsingToolbarLayout#onWindowInsetChanged(WindowInsetsCompat)}
* so we will not receive them in subviews with fitsSystemWindows = true.
* Override Google's behavior
* */
public void overrideListener() {
ViewCompat.setOnApplyWindowInsetsListener(this, (v, insets) -> insets);

View File

@ -1,14 +1,17 @@
package org.schabi.newpipe.views;
import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.view.SurfaceView;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
public class ExpandableSurfaceView extends SurfaceView {
private int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
private int resizeMode = RESIZE_MODE_FIT;
private int baseHeight = 0;
private int maxHeight = 0;
private float videoAspectRatio = 0.0f;
@ -30,7 +33,7 @@ public class ExpandableSurfaceView extends SurfaceView {
final boolean verticalVideo = videoAspectRatio < 1;
// Use maxHeight only on non-fit resize mode and in vertical videos
int height = maxHeight != 0
&& resizeMode != AspectRatioFrameLayout.RESIZE_MODE_FIT
&& resizeMode != RESIZE_MODE_FIT
&& verticalVideo ? maxHeight : baseHeight;
if (height == 0) {
@ -42,26 +45,22 @@ public class ExpandableSurfaceView extends SurfaceView {
scaleX = 1.0f;
scaleY = 1.0f;
switch (resizeMode) {
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
if (aspectDeformation > 0) {
height = (int) (width / videoAspectRatio);
} else {
width = (int) (height * videoAspectRatio);
}
break;
case RESIZE_MODE_ZOOM:
if (aspectDeformation < 0) {
scaleY = viewAspectRatio / videoAspectRatio;
} else {
scaleX = videoAspectRatio / viewAspectRatio;
}
break;
default:
break;
if (resizeMode == RESIZE_MODE_FIT
// KitKat doesn't work well when a view has a scale like needed for ZOOM
|| (resizeMode == RESIZE_MODE_ZOOM && VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)) {
if (aspectDeformation > 0) {
height = (int) (width / videoAspectRatio);
} else {
width = (int) (height * videoAspectRatio);
}
} else if (resizeMode == RESIZE_MODE_ZOOM) {
if (aspectDeformation < 0) {
scaleY = viewAspectRatio / videoAspectRatio;
} else {
scaleX = videoAspectRatio / viewAspectRatio;
}
}
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 908 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M6,2l0.01,6L10,12l-3.99,4.01L6,22h12v-6l-4,-4l4,-3.99V2H6zM16,16.5V20H8v-3.5l4,-4L16,16.5z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,5V1L7,6l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6 -6,-2.69 -6,-6H4c0,4.42 3.58,8 8,8s8,-3.58 8,-8 -3.58,-8 -8,-8z"/>
</vector>

View File

@ -232,29 +232,29 @@
tools:ignore="HardcodedText,RtlHardcoded"
tools:text="FIT"/>
<Button
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
android:lines="1"
android:ellipsize="end"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textAllCaps="false"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
tools:text="English"/>
<Space
android:id="@+id/spaceBeforeButton"
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="3"/>
android:layout_height="wrap_content"
android:layout_weight="3">
<TextView
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
android:lines="1"
android:ellipsize="end"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
tools:text="English"/>
</FrameLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playWithKodi"
@ -311,25 +311,24 @@
android:contentDescription="@string/mute"
tools:ignore="RtlHardcoded" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="@dimen/player_main_buttons_padding"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"
tools:visibility="visible"/>
<LinearLayout
android:id="@+id/bottomControls"
android:layout_width="match_parent"
@ -469,21 +468,20 @@
android:layout_height="60dp"
android:id="@+id/playQueueControl">
<ImageButton
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playQueueClose"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="40dp"
android:padding="10dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:tint="?attr/colorAccent"
android:src="@drawable/ic_close_white_24dp"
android:background="?android:selectableItemBackground"
tools:ignore="ContentDescription"/>
android:clickable="true"
android:contentDescription="@string/close"
android:focusable="true"
android:padding="10dp"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_close_white_24dp" />
<ImageButton
android:id="@+id/repeatButton"

View File

@ -12,6 +12,6 @@
android:inputType="text"
android:maxLines="1"
android:layout_margin="10dp"
android:hint="@string/playlist_name_input"/>
android:hint="@string/name"/>
</LinearLayout>

View File

@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center_vertical"
android:hint="@string/feed_group_dialog_name_input"
android:hint="@string/name"
android:paddingTop="6dp"
android:paddingBottom="6dp"
app:errorEnabled="true"

View File

@ -16,6 +16,6 @@
android:layout_marginRight="10dp"
android:saveEnabled="true"
android:inputType="text"
android:hint="@string/playlist_name_input"
android:hint="@string/name"
android:maxLines="1"/>
</RelativeLayout>

View File

@ -10,10 +10,8 @@
android:maxLines="2"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingEnd="?attr/listPreferredItemPaddingRight"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:paddingStart="?attr/listPreferredItemPaddingLeft"
android:background="?attr/checked_selector"
android:textColor="?attr/textColorAlertDialogListItem"
tools:drawableLeft="?attr/ic_play"
tools:drawableLeft="?attr/ic_play_arrow"
tools:text="Lorem ipsum dolor sit amet" />

View File

@ -81,254 +81,253 @@
android:paddingEnd="@dimen/player_main_controls_padding"
android:baselineAligned="false">
<LinearLayout
android:id="@+id/primaryControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="45dp"
android:baselineAligned="false"
android:gravity="top"
tools:ignore="RtlHardcoded">
<ImageButton
android:id="@+id/playerCloseButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:src="?attr/ic_close"
android:background="?attr/selectableItemBackgroundBorderless"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone" />
<LinearLayout
android:id="@+id/metadataView"
android:layout_width="0dp"
android:id="@+id/primaryControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="45dp"
android:baselineAligned="false"
android:gravity="top"
android:orientation="vertical"
android:layout_marginTop="6dp"
android:layout_marginRight="8dp"
tools:ignore="RtlHardcoded"
android:layout_weight="1">
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="15sp"
android:textStyle="bold"
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playerCloseButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="?attr/ic_close"
android:background="?attr/selectableItemBackgroundBorderless"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone" />
<LinearLayout
android:id="@+id/metadataView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="top"
android:orientation="vertical"
android:layout_marginTop="6dp"
android:layout_marginRight="8dp"
tools:ignore="RtlHardcoded"
tools:text="The Video Title LONG very LONG"/>
android:layout_weight="1">
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="15sp"
android:textStyle="bold"
android:clickable="true"
android:focusable="true"
tools:ignore="RtlHardcoded"
tools:text="The Video Title LONG very LONG"/>
<TextView
android:id="@+id/channelTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="12sp"
android:clickable="true"
android:focusable="true"
tools:text="The Video Artist LONG very LONG very Long"/>
</LinearLayout>
<TextView
android:id="@+id/channelTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:minWidth="0dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:text="720p"
android:textColor="@android:color/white"
android:textSize="12sp"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
android:visibility="visible"
tools:ignore="HardcodedText,RtlHardcoded"/>
<TextView
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="0dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RtlHardcoded,RtlSymmetry"
tools:text="1x"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/queueButton"
android:layout_width="35dp"
android:layout_height="35dp"
android:paddingTop="5dp"
android:paddingStart="3dp"
android:paddingEnd="3dp"
android:paddingBottom="3dp"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
tools:text="The Video Artist LONG very LONG very Long"/>
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_list_white_24dp"
android:background="?attr/selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_expand_more_white_24dp"
android:background="?attr/selectableItemBackgroundBorderless"
tools:ignore="ContentDescription,RtlHardcoded"/>
</LinearLayout>
<TextView
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:minWidth="0dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:text="720p"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
android:visibility="visible"
tools:ignore="HardcodedText,RtlHardcoded"/>
<LinearLayout
android:id="@+id/secondaryControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
<TextView
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="0dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RtlHardcoded,RtlSymmetry"
tools:text="1x"/>
<TextView
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded"
tools:text="FIT"/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3">
<TextView
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
android:lines="1"
android:ellipsize="end"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
tools:text="English"/>
</FrameLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playWithKodi"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_cast_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/play_with_kodi_title"
tools:ignore="RtlHardcoded"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/openInBrowser"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_language_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/open_in_browser"
tools:ignore="RtlHardcoded"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_share_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/share"
tools:ignore="RtlHardcoded"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/switchMute"
android:layout_width="wrap_content"
android:layout_height="37dp"
android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_volume_off_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/mute"
tools:ignore="RtlHardcoded" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/queueButton"
android:layout_width="35dp"
android:layout_height="35dp"
android:paddingTop="5dp"
android:paddingStart="3dp"
android:paddingEnd="3dp"
android:paddingBottom="3dp"
android:layout_marginEnd="8dp"
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="@dimen/player_main_buttons_padding"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_list_white_24dp"
android:background="?attr/selectableItemBackground"
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_expand_more_white_24dp"
android:background="?attr/selectableItemBackgroundBorderless"
tools:ignore="ContentDescription,RtlHardcoded"/>
</LinearLayout>
<LinearLayout
android:id="@+id/secondaryControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
<TextView
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded"
tools:text="FIT"/>
<TextView
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
android:maxWidth="100dp"
android:lines="1"
android:ellipsize="end"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
tools:text="English"/>
<Space
android:id="@+id/spaceBeforeButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="3"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playWithKodi"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_cast_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/play_with_kodi_title"
tools:ignore="RtlHardcoded"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/openInBrowser"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_language_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/open_in_browser"
tools:ignore="RtlHardcoded"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_share_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/share"
tools:ignore="RtlHardcoded"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/switchMute"
android:layout_width="wrap_content"
android:layout_height="37dp"
android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_volume_off_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/mute"
tools:ignore="RtlHardcoded" />
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="@dimen/player_main_buttons_padding"
android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"
android:visibility="gone"
tools:visibility="visible"/>
<LinearLayout
android:id="@+id/bottomControls"
android:layout_width="match_parent"
@ -411,42 +410,42 @@
android:orientation="horizontal"
android:weightSum="5.5">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playPreviousButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:layout_marginEnd="10dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_previous_white_24dp"
tools:ignore="ContentDescription"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playPreviousButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:layout_marginEnd="10dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_previous_white_24dp"
tools:ignore="ContentDescription"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playPauseButton"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_pause_white_24dp"
tools:ignore="ContentDescription"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playPauseButton"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_pause_white_24dp"
tools:ignore="ContentDescription"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playNextButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:layout_marginStart="10dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_next_white_24dp"
tools:ignore="ContentDescription"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playNextButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:layout_marginStart="10dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_next_white_24dp"
tools:ignore="ContentDescription"/>
</LinearLayout>
@ -465,21 +464,20 @@
android:layout_height="60dp"
android:id="@+id/playQueueControl">
<ImageButton
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playQueueClose"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="40dp"
android:padding="10dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:tint="?attr/colorAccent"
android:src="@drawable/ic_close_white_24dp"
android:background="?android:selectableItemBackground"
tools:ignore="ContentDescription"/>
android:clickable="true"
android:contentDescription="@string/close"
android:focusable="true"
android:padding="10dp"
android:scaleType="fitXY"
app:srcCompat="@drawable/ic_close_white_24dp" />
<ImageButton
android:id="@+id/repeatButton"

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="64dp"
xmlns:tools="http://schemas.android.com/tools">
android:layout_height="64dp"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:id="@+id/notificationContent"
@ -107,8 +107,8 @@
android:focusable="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_close_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"/>
app:srcCompat="@drawable/ic_close_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded" />
</LinearLayout>
<ProgressBar
@ -121,4 +121,4 @@
android:progressDrawable="@drawable/custom_progress_bar"
tools:ignore="RtlHardcoded"
tools:progress="52"/>
</FrameLayout>
</FrameLayout>

View File

@ -29,8 +29,8 @@
android:focusable="true"
android:padding="8dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_close_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"/>
app:srcCompat="@drawable/ic_close_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded" />
<LinearLayout
@ -162,4 +162,4 @@
android:src="@drawable/exo_controls_next"
tools:ignore="ContentDescription"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -11,8 +10,8 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="24dp"
app:srcCompat="@drawable/ic_close_white_24dp"
app:backgroundTint="@color/light_youtube_primary_color"
app:borderWidth="0dp"
app:fabSize="normal"/>
</FrameLayout>
app:fabSize="normal"
app:srcCompat="@drawable/ic_close_white_24dp" />
</FrameLayout>

View File

@ -12,7 +12,7 @@
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_alignBaseline="@+id/autoplay_switch"
android:text="@string/next_video_title"
android:text="@string/exo_controls_next_description"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="12sp"
tools:ignore="RtlHardcoded" />
@ -27,6 +27,6 @@
android:switchPadding="5dp"
android:textSize="12sp"
android:textColor="@android:color/tab_indicator_text"
android:text="@string/autoplay_title" />
android:text="@string/auto_queue_toggle" />
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<Switch
android:id="@+id/notificationScaleSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:clickable="false"
android:focusable="false"
app:layout_constraintBottom_toBottomOf="@+id/textView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/textView" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:maxLines="1"
android:text="@string/notification_scale_to_square_image_title"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="14sp"
app:layout_constraintEnd_toStartOf="@+id/notificationScaleSwitch"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/notification_scale_to_square_image_summary"
app:layout_constraintEnd_toStartOf="@+id/notificationScaleSwitch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<View
android:id="@+id/notificationScaleSwitchClickableArea"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toTopOf="@+id/divider"
app:layout_constraintTop_toTopOf="parent"
android:background="?android:selectableItemBackground" />
<View
android:id="@+id/divider"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:background="?android:attr/listDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
<TextView
android:id="@+id/textView4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:clickable="false"
android:focusable="false"
android:gravity="center"
android:lines="4"
android:text="@string/notification_actions_summary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider" />
<include
android:id="@+id/notificationAction0"
layout="@layout/settings_notification_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
<include
android:id="@+id/notificationAction1"
layout="@layout/settings_notification_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/notificationAction0" />
<include
android:id="@+id/notificationAction2"
layout="@layout/settings_notification_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/notificationAction1" />
<include
android:id="@+id/notificationAction3"
layout="@layout/settings_notification_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/notificationAction2" />
<include
android:id="@+id/notificationAction4"
layout="@layout/settings_notification_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/notificationAction3" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/notificationActionIcon"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:tint="?android:textColorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_previous_white_24dp" />
<TextView
android:id="@+id/notificationActionTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="14sp"
app:layout_constraintBottom_toTopOf="@+id/notificationActionSummary"
app:layout_constraintEnd_toEndOf="@id/notificationActionClickableArea"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/notificationActionIcon"
app:layout_constraintTop_toTopOf="@+id/notificationActionIcon"
app:layout_constraintVertical_chainStyle="packed"
tools:text="@string/notification_action_1_title" />
<TextView
android:id="@+id/notificationActionSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="@+id/notificationActionIcon"
app:layout_constraintEnd_toEndOf="@+id/notificationActionClickableArea"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/notificationActionTitle"
app:layout_constraintTop_toBottomOf="@+id/notificationActionTitle"
tools:text="@string/notification_action_play_pause_buffering_value" />
<View
android:id="@+id/notificationActionClickableArea"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?android:selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/notificationActionCheckBoxClickableArea"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/notificationActionCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
app:layout_constraintBottom_toBottomOf="@+id/notificationActionCheckBoxClickableArea"
app:layout_constraintEnd_toEndOf="@+id/notificationActionCheckBoxClickableArea"
app:layout_constraintStart_toStartOf="@+id/notificationActionCheckBoxClickableArea"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/notificationActionCheckBoxClickableArea"
android:layout_width="0dp"
android:layout_height="0dp"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -47,7 +47,7 @@
android:contentDescription="@string/search"
android:scaleType="fitCenter"
app:srcCompat="?attr/ic_close"
tools:ignore="RtlHardcoded"/>
tools:ignore="RtlHardcoded" />
</FrameLayout>
</FrameLayout>
</FrameLayout>

View File

@ -1,2 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="no_player_found">Geen stream-speler gevind nie. Installeer VLC\?</string>
<string name="main_bg_subtitle">Tik op \"Soek\" om aan die gang te kom</string>
</resources>

View File

@ -46,7 +46,7 @@
<string name="show_play_with_kodi_title">عرض خيار التشغيل بواسطة كودي</string>
<string name="theme_title">السمة</string>
<string name="upload_date_text">تم النشر بتاريخ %1$s</string>
<string name="url_not_supported_toast">رابط URL غير معتمد</string>
<string name="unsupported_url">رابط URL غير معتمد</string>
<string name="use_external_audio_player_title">استخدام مشغل صوت خارجي</string>
<string name="use_external_video_player_title">استخدام مشغل فيديو خارجي</string>
<string name="use_tor_summary">(إختبارية) إجراء التنزيلات من خلال استخدام بروكسي Tor لزيادة الخصوصية ( تشغيل الفيديو المباشر غير مدعوم حتى الأن ).</string>
@ -143,7 +143,7 @@
<string name="error_snackbar_action">أبلِغ</string>
<string name="what_device_headline">معلومات:</string>
<string name="what_happened_headline">ماذا حدث:</string>
<string name="info_labels">ماذا:\\nطلب:\\nيحتوى اللغة:\\nSالخدمات:\\nتوقيت غرينتش:\\nحزمة:\\nالإصدار:\\nOS إصدار نظام التشغيل:</string>
<string name="info_labels">ماذا:\\nطلب:\\nلغة المحتوى:\\nبلد المحتوى:\\nلغة التطبيق:\\nالخدمات:\\nتوقيت غرينتش:\\nالحزمة:\\nالإصدار:\\nOS الإصدار:</string>
<string name="your_comment">تعليقك (باللغة الإنجليزية):</string>
<string name="error_details_headline">التفاصيل:</string>
<string name="report_error">الإبلاغ عن خطأ</string>
@ -155,15 +155,15 @@
<string name="storage_permission_denied">ترخيص الوصول إلى التخزين أوّلا</string>
<string name="short_thousand">ألف</string>
<string name="short_million">مليون</string>
<string name="short_billion">B</string>
<string name="short_billion">بليون</string>
<string name="no_subscribers">ليس هناك مشترِكون</string>
<plurals name="subscribers">
<item quantity="zero">%s لا يوجد مشترك</item>
<item quantity="one">%s مشترك</item>
<item quantity="two">%s المشتركين</item>
<item quantity="few">%s المشتركين</item>
<item quantity="many">%s المشتركين</item>
<item quantity="other">%s المشتركين</item>
<item quantity="zero">%s لا مشتركين</item>
<item quantity="one">%s مشترِك</item>
<item quantity="two">مشتركين</item>
<item quantity="few">%s مشتركين</item>
<item quantity="many">%s مشتركين</item>
<item quantity="other">%s الاشتراكات</item>
</plurals>
<string name="no_views">دون مشاهدات</string>
<string name="no_videos">لاتوجد فيديوهات</string>
@ -235,12 +235,12 @@
<string name="title_activity_recaptcha">تحدي الكابتشا</string>
<string name="hold_to_append">ضغط مطول للإدراج الى قائمة الانتظار</string>
<plurals name="views">
<item quantity="zero">%s بدون مشهادة</item>
<item quantity="zero">%s بدون مشاهد</item>
<item quantity="one">%s مشاهدة</item>
<item quantity="two">%s مشاهدة</item>
<item quantity="few">%s مشاهدة</item>
<item quantity="many">%s مشاهدة</item>
<item quantity="other">%s مشاهدة</item>
<item quantity="two">%s مشاهدات</item>
<item quantity="few">%s مشاهدات</item>
<item quantity="many">%s مشاهدات</item>
<item quantity="other">%s مشاهدات</item>
</plurals>
<plurals name="videos">
<item quantity="zero">%s فيديو</item>
@ -272,7 +272,7 @@
<string name="no_player_found_toast">لم يتم العثور على مشغل دفق (يمكنك تثبيت VLC لتشغيله).</string>
<string name="import_data_title">استيراد قاعدة البيانات</string>
<string name="export_data_title">تصدير قاعدة البيانات</string>
<string name="import_data_summary">"الكتابة فوق سجل التاريخ والاشتراكات الحالية "</string>
<string name="import_data_summary">يتجاوز السجل والاشتراكات الحالية</string>
<string name="export_data_summary">تصدير السجل، الإشتراكات وقوائم التشغيل</string>
<string name="show_info">عرض المعلومات</string>
<string name="controls_add_to_playlist_title">إضافة إلى</string>
@ -295,8 +295,8 @@
<string name="preferred_player_fetcher_notification_message">تحميل المحتوى المطلوب</string>
<string name="create_playlist">إنشاء قائمة تشغيل جديدة</string>
<string name="delete_playlist">حذف قائمة التشغيل</string>
<string name="rename_playlist">"إعادة تسمية قائمة التشغيل "</string>
<string name="playlist_name_input">التسمية</string>
<string name="rename_playlist">إعادة تسمية</string>
<string name="name">التسمية</string>
<string name="append_playlist">إضافة إلى قائمة تشغيل</string>
<string name="delete_playlist_prompt">هل تريد حذف قائمة التشغيل هذه ؟</string>
<string name="playlist_creation_success">تم إنشاء قائمة التشغيل</string>
@ -325,7 +325,7 @@
<string name="import_ongoing">عملية الإستعادة جارية …</string>
<string name="export_ongoing">عملية التصدير جارية …</string>
<string name="import_file_title">إستيراد ملف</string>
<string name="import_soundcloud_instructions_hint">"معرفك , soundcloud.com/ الخاص بك "</string>
<string name="import_soundcloud_instructions_hint">معرفك, soundcloud.com/هويتك</string>
<string name="download_thumbnail_summary">عند إيقاف تحميل أي صور مصغرة ، وتوفير البيانات واستخدام الذاكرة. تعمل التغييرات على محو ذاكرة التخزين المؤقت للصورة الموجودة على الذاكرة أو على القرص.</string>
<string name="metadata_cache_wipe_title">امسح البيانات الوصفية المخزنة مؤقتًا</string>
<string name="metadata_cache_wipe_summary">إزالة جميع بيانات صفحات الويب المخزنة مؤقتًا</string>
@ -338,7 +338,6 @@
<string name="caption_none">بدون تسميات توضيحية</string>
<string name="caption_setting_title">تسميات توضيحية</string>
<string name="caption_setting_description">تعديل مشغل نص التسمية التوضيحية وأنماط الخلفية. يتطلب إعادة تشغيل التطبيق لتصبح التغييرات سارية المفعول.</string>
<string name="enable_leak_canary_title">تمكين تسرب الكناري</string>
<string name="enable_leak_canary_summary">قد تتسبب مراقبة تسرب الذاكرة في عدم استجابة التطبيق عند تفريغ السجلات</string>
<string name="enable_disposed_exceptions_title">تقرير الأخطاء خارج دورة الحياة</string>
<string name="enable_disposed_exceptions_summary">فرض الإبلاغ عن استثناءات Rx غير القابلة للتسليم خارج دورة حياة الجزء أو النشاط بعد التخلص منها</string>
@ -363,7 +362,7 @@
<string name="title_most_played">الأكثر تشغيلا</string>
<string name="override_current_data">هذا سوف يُزيل إعداداتك الحالية.</string>
<string name="preferred_open_action_settings_title">طريقة \'التشغيل\' المفضلة</string>
<string name="preferred_open_action_settings_summary">"الإجراء الافتراضي عند فتح المحتوى — %s"</string>
<string name="preferred_open_action_settings_summary">الإجراء الافتراضي عند فتح المحتوى — %s</string>
<string name="background_player">مشغل الخلفية</string>
<string name="popup_player">المشغل المنبثق</string>
<string name="previous_export">نسخة احتياطية</string>
@ -388,7 +387,7 @@
<string name="playback_pitch">تردد الصوت</string>
<string name="unhook_checkbox">حل (قد يسبب تشويه)</string>
<string name="import_settings">هل تريد أيضا استيراد الإعدادات؟</string>
<string name="privacy_policy_title">"سياسة الخصوصية في NewPipe "</string>
<string name="privacy_policy_title">سياسة خصوصية NewPipe</string>
<string name="privacy_policy_encouragement">يأخذ مشروع NewPipe خصوصيتك على محمل الجد. لذلك ، لا يجمع التطبيق أي بيانات دون موافقتك.
\nتوضح سياسة خصوصية NewPipe بالتفصيل البيانات التي يتم إرسالها وتخزينها عند إرسال تقرير الأعطال.</string>
<string name="read_privacy_policy">الإطلاع على سياسة الخصوصية</string>
@ -423,7 +422,7 @@
<string name="events">الأحداث</string>
<string name="app_update_notification_channel_description">الإخطارات لإصدار NewPipe الجديد</string>
<string name="download_to_sdcard_error_title">وحدة التخزين الخارجية غير متوفرة</string>
<string name="download_to_sdcard_error_message">"التنزيل على بطاقة SD الخارجية غير ممكن. إعادة تعيين موقع مجلد التحميل؟"</string>
<string name="download_to_sdcard_error_message">لا يمكن التنزيل على بطاقة SD الخارجية. هل تريد إعادة تعيين موقع مجلد التنزيل؟</string>
<string name="saved_tabs_invalid_json">تعذرت قراءة علامات التبويب المحفوظة, لذا استخدم علامات التبويب الافتراضية</string>
<string name="restore_defaults">استعادة الضبط الافتراضي</string>
<string name="restore_defaults_confirmation">هل تريد استعادة الإعدادات الافتراضية؟</string>
@ -469,7 +468,7 @@
<string name="stop">توقف</string>
<string name="max_retry_msg">أقصى عدد للمحاولات</string>
<string name="max_retry_desc">الحد الأقصى لعدد محاولات قبل إلغاء التحميل</string>
<string name="pause_downloads_on_mobile">"إنقطع الإتصال بالشبكة عند التحويل إلى البيانات المتنقلة"</string>
<string name="pause_downloads_on_mobile">المقاطعة على الشبكات المقيسة</string>
<string name="pause_downloads_on_mobile_desc">مفيد عند التبديل إلى بيانات الجوال ، على الرغم من أنه لا يمكن تعليق بعض التنزيلات</string>
<string name="show_comments_title">إظهار التعليقات</string>
<string name="show_comments_summary">عطّله لإخفاء التعليقات</string>
@ -498,7 +497,8 @@
<string name="pause_downloads">إيقاف التحميل مؤقتا</string>
<string name="downloads_storage_ask_title">اسأل عن مكان التنزيل</string>
<string name="downloads_storage_ask_summary">سيُطلب منك مكان حفظ كل تنزيل</string>
<string name="downloads_storage_ask_summary_kitkat">سيُطلب منك مكان حفظ كل تنزيل. اختر SAF إذا كنت تريد التنزيل على بطاقة SD خارجية</string>
<string name="downloads_storage_ask_summary_kitkat">سيطلب منك مكان حفظ كل تنزيل.
\nاختر SAF إذا كنت تريد التنزيل على بطاقة SD خارجية</string>
<string name="downloads_storage_use_saf_title">استخدام آمن</string>
<string name="downloads_storage_use_saf_summary">يسمح \"إطار الوصول إلى التخزين\" بالتنزيل على بطاقة SD خارجية.
\nبعض الأجهزة غير متوافقة</string>
@ -583,7 +583,6 @@
<string name="settings_category_feed_title">تغذية</string>
<string name="feed_create_new_group_button_title">جديد</string>
<string name="feed_group_dialog_delete_message">هل تريد حذف هذه المجموعة\?</string>
<string name="feed_group_dialog_name_input">الاسم</string>
<string name="feed_group_dialog_empty_name">اسم المجموعة فارغ</string>
<plurals name="feed_group_dialog_selection_count">
<item quantity="zero">%d تحديد</item>
@ -650,4 +649,12 @@
<string name="video_detail_by">لـ %s</string>
<string name="channel_created_by">أنشأها %s</string>
<string name="detail_sub_channel_thumbnail_view_description">الصورة الرمزية للقناة</string>
<string name="playlist_page_summary">صفحة قائمة التشغيل</string>
<string name="feed_group_show_only_ungrouped_subscriptions">إظهار الاشتراكات غير المجمعة فقط</string>
<string name="no_playlist_bookmarked_yet">لا توجد إشارات مرجعية لقائمة التشغيل حتى الآن</string>
<string name="select_a_playlist">حدد قائمة تشغيل</string>
<string name="error_report_open_github_notice">يرجى التحقق مما إذا كانت هناك مشكلة في مناقشة تعطلك بالفعل. عند إنشاء تذاكر مكررة ، ستأخذ وقتًا منا يمكن أن نقضيه في إصلاح الخطأ الفعلي.</string>
<string name="error_report_open_issue_button_text">أبلغ عن خطأ على GitHub</string>
<string name="copy_for_github">نسخ تقرير منسق</string>
<string name="search_showing_result_for">عرض النتائج ل : %s</string>
</resources>

View File

@ -1,5 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources><string name="main_bg_subtitle">Başlamaq üçün axtarışa bas</string>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_bg_subtitle">Başlamaq üçün axtarışa bas</string>
<string name="view_count_text">%1$s baxış</string>
<string name="upload_date_text">Dərc edilib %1$s</string>
<string name="no_player_found">Axın oynadıcısı tapılmadı. VLC ni yükləmək istərdinizmi?</string>
@ -22,22 +23,17 @@
<string name="subscribed_button_title">Abunə olunub</string>
<string name="channel_unsubscribed">Kanal</string>
<string name="show_info">Məlumat göstər</string>
<string name="tab_main">Əsas</string>
<string name="tab_subscriptions">Abunəliklər</string>
<string name="tab_bookmarks">Əlfəcinlər</string>
<string name="fragment_feed_title">Yeni nə var</string>
<string name="controls_background_title">Arxa fon</string>
<string name="download_path_title">Video yükləmə ünvanı</string>
<string name="download_path_summary">Yüklənən videoları saxlamaq üçün yer</string>
<string name="download_path_dialog_title">Videolar üçün yükləmə yerini daxil et</string>
<string name="download_path_audio_title">Audio yükləmə yeri</string>
<string name="download_path_audio_summary">Yüklənən audioları saxlamaq üçün yer</string>
<string name="download_path_audio_dialog_title">Audiolar üçün yükləmə yerini daxil et</string>
<string name="autoplay_by_calling_app_summary">NewPipe başqa bir uyğulamadan çağrıldığı zaman avtomatik olaraq videonu oynadır</string>
<string name="default_resolution_title">Defolt ölçü</string>
<string name="show_higher_resolutions_title">Daha böyük ölçüləri göstər</string>
@ -52,4 +48,8 @@
<string name="light_theme_title">ıq</string>
<string name="dark_theme_title">Qaranlıq</string>
<string name="black_theme_title">Qara</string>
</resources>
<string name="unsubscribe">Abunəlik ləğvi</string>
<string name="popup_mode_share_menu_title">ılan pəncərə</string>
<string name="screen_rotation">Fırlanma</string>
<string name="open_in_popup_mode">ılan pəncərə modunda aç</string>
</resources>

View File

@ -150,7 +150,7 @@
<string name="delete_all_history_prompt">¿De xuru que quies desaniciar tolos elementos del historial\?</string>
<string name="drawer_header_action_paceholder_text">Equí va apaecer dalgo ceo ;D</string>
<string name="create_playlist">Llista nueva de repoducción</string>
<string name="playlist_name_input">Nome</string>
<string name="name">Nome</string>
<string name="append_playlist">Amestar a una llista de repoducción</string>
<string name="delete_playlist_prompt">¿Desaniciar esta llista de reproducción\?</string>
<string name="playlist_delete_failure">Nun pudo desaniciase la llista de reproducción.</string>
@ -276,7 +276,7 @@
<string name="playback_tempo">Tempu</string>
<string name="playback_pitch">Tonu</string>
<string name="decline">Refugar</string>
<string name="url_not_supported_toast">La URL nun se sofita</string>
<string name="unsupported_url">La URL nun se sofita</string>
<string name="background_player_playing_toast">Reproduciendo en segundu planu</string>
<string name="popup_playing_toast">Reproduciendo nel mou ventanu</string>
<string name="enable_search_history_summary">Atroxa llocalmente les consultes de gueta</string>

View File

@ -29,7 +29,7 @@
<string name="black_theme_title">黑色</string>
<string name="download_dialog_title">下载</string>
<string name="next_video_title">下一个</string>
<string name="url_not_supported_toast">不支持的 URL</string>
<string name="unsupported_url">不支持的 URL</string>
<string name="settings_category_appearance_title">外观</string>
<string name="settings_category_other_title">其他</string>
<string name="all">全部</string>
@ -71,7 +71,7 @@
<string name="subscribers_count_not_available">无法得知订阅人数</string>
<string name="updates_setting_description">发布新版本时,通知我升级应用</string>
<string name="grid">网格</string>
<string name="app_update_notification_content_title">NewPipe更新!</string>
<string name="app_update_notification_content_title">NewPipe更新!</string>
<string name="error_http_unsupported_range">服务器不接受 接收 multi-threaded 下载, 以 @string/msg_threads = 1 重试</string>
<string name="autoplay_title">自动播放</string>
<string name="settings_category_clear_data_title">清除数据</string>
@ -191,7 +191,7 @@
<string name="error_snackbar_action">报告</string>
<string name="what_device_headline">信息:</string>
<string name="what_happened_headline">发生了什么:</string>
<string name="info_labels">详情:\\n请求\\n内容语言\\n服务\\nGMT时间\\n包\\n版本\\n操作系统版本</string>
<string name="info_labels">详情:\\n请求\\n内容语言\\n内容国家:\\n客户端语言\\n服务:\\nGMT时间\\n包\\n版本\\n操作系统版本</string>
<string name="your_comment">您的附近说明(请用英文):</string>
<string name="error_details_headline">详细信息:</string>
<string name="list_thumbnail_view_description">视频预览缩略图</string>
@ -324,7 +324,7 @@
<string name="create_playlist">新建播放列表</string>
<string name="delete_playlist">删除</string>
<string name="rename_playlist">重命名</string>
<string name="playlist_name_input">名称</string>
<string name="name">名称</string>
<string name="append_playlist">添加到播放列表</string>
<string name="set_as_playlist_thumbnail">设为播放列表缩略图</string>
<string name="bookmark_playlist">收藏播放列表</string>
@ -341,7 +341,6 @@
<string name="drawer_header_action_paceholder_text">敬请期待</string>
<string name="settings_category_debug_title">调试</string>
<string name="caption_auto_generated">自动生成</string>
<string name="enable_leak_canary_title">启用LeakCanary</string>
<string name="enable_leak_canary_summary">『内存泄漏监视』可能导致应用在『核心转储』时无响应</string>
<string name="enable_disposed_exceptions_title">报告『提前结束Android生命周期』错误</string>
<string name="enable_disposed_exceptions_summary">强制报告处理后的未送达的Activity或Fragment生命周期之外的Rx异常</string>
@ -556,7 +555,6 @@
<item quantity="other">已选中%d</item>
</plurals>
<string name="feed_group_dialog_empty_name">组名为空</string>
<string name="feed_group_dialog_name_input">名称</string>
<string name="feed_group_dialog_delete_message">您要删除该组吗?</string>
<string name="feed_create_new_group_button_title">新建</string>
<string name="settings_category_feed_title">订阅</string>
@ -602,4 +600,11 @@
<string name="show_original_time_ago_title">在项目上显示原始时间</string>
<string name="youtube_restricted_mode_enabled_title">YouTube受限模式</string>
<string name="feed_group_show_only_ungrouped_subscriptions">仅显示未分组订阅</string>
<string name="playlist_page_summary">播放列表页</string>
<string name="no_playlist_bookmarked_yet">尚无播放列表书签</string>
<string name="select_a_playlist">选择播放列表</string>
<string name="error_report_open_github_notice">请检查您的问题是否已经存在。创建重复票证时您需要从我们那里花些时间来让我们修复真正的bug。</string>
<string name="error_report_open_issue_button_text">去GitHub上报告错误</string>
<string name="copy_for_github">复制格式报告</string>
<string name="search_showing_result_for">显示结果为:%s</string>
</resources>

View File

@ -85,7 +85,7 @@
<string name="show_next_and_similar_title">\"Наступнае\" и \"Прапанаванае\" відэа</string>
<string name="show_hold_to_append_title">\"Зацісніце, каб дадаць\"</string>
<string name="show_hold_to_append_summary">Паказаць падказку пры націсканні \"У акне\" ці \"У фоне\" на старонцы звестак аб відэа</string>
<string name="url_not_supported_toast">URL не падтрымліваецца</string>
<string name="unsupported_url">URL не падтрымліваецца</string>
<string name="default_content_country_title">Краіна кантэнту па змаўчанні</string>
<string name="service_title">Сэрвіс</string>
<string name="content_language_title">Мова кантэнту па змаўчанні</string>
@ -337,7 +337,7 @@
<string name="create_playlist">Стварыць плэйліст</string>
<string name="delete_playlist">Выдаліць</string>
<string name="rename_playlist">Перайменаваць</string>
<string name="playlist_name_input">Імя</string>
<string name="name">Імя</string>
<string name="append_playlist">Дадаць у плэйліст</string>
<string name="set_as_playlist_thumbnail">На мініяцюру плэйліста</string>
<string name="bookmark_playlist">Дадаць плэйліст у закладкі</string>
@ -354,7 +354,6 @@
<string name="caption_auto_generated">Створаны аўтаматычна</string>
<string name="caption_setting_title">Тытры</string>
<string name="caption_setting_description">Змяніць памер тэкста і фон тытраў. Патрэбен перазапуск</string>
<string name="enable_leak_canary_title">Уключыць LeakCanary</string>
<string name="enable_leak_canary_summary">Маніторынг уцечкі памяці можа прывесці да завісання прыкладання</string>
<string name="enable_disposed_exceptions_title">Паведамляць пра памылкі жыццёвага цыклу</string>
<string name="enable_disposed_exceptions_summary">Прымусова паведамляць пра недастаўляемыя Rx-выключэнні па-за фрагментам або жыццёвым цыкле пасля выдалення</string>
@ -494,4 +493,11 @@
<string name="downloads_storage_use_saf_title">Выкарыстоўваць SAF</string>
<string name="downloads_storage_use_saf_summary">Storage Framework Access дазваляе захоўваць файлы на вонкавым назапашвальніку.
\nПадтрымліваецца не ўсімі прыладамі</string>
<string name="drawer_header_description">Пераключыць службу, выбраную ў дадзены момант:</string>
<string name="clear_playback_states_summary">Выдаліць ўсе пазіцыі прайгравання</string>
<string name="youtube_restricted_mode_enabled_title">Абмежаваны рэжым YouTube</string>
<string name="peertube_instance_add_https_only">Падтрымліваюцца толькі адрасы URL HTTPS</string>
<string name="peertube_instance_add_title">Дадаць інстанцыю</string>
<string name="peertube_instance_url_title">Інстанцыі PeerTube</string>
<string name="download_choose_new_path">Змяніце папкі загрузкі, каб змены ўступілі ў сілу</string>
</resources>

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="feed_create_new_group_button_title">ⴰⵎⴰⵢⵏⵓ</string>
<string name="name">ⵉⵙⵎ</string>
<plurals name="days">
<item quantity="one">%d ⵡⴰⵙⵙ</item>
<item quantity="other">%d ⵓⵙⵙⴰⵏ</item>
</plurals>
<plurals name="hours">
<item quantity="one">%d ⵜⵙⵔⵉⴳⵜ</item>
<item quantity="other">%d ⵜⵙⵔⵉⴳⵉⵏ</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d ⵜⵙⴷⵉⴷⵉⵜ</item>
<item quantity="other">%d ⵜⵙⴷⵉⴷⵉⵏ</item>
</plurals>
<string name="app_language_title">ⵜⵓⵜⵍⴰⵢⵜ ⵓⵙⵏⵙⵉ</string>
<string name="close">ⵇⵇⵏ</string>
<string name="minimize_on_exit_none_description">ⵡⴰⵍⵓ</string>
<string name="playback_step">ⴰⵙⵓⵔⵉⴼ</string>
<string name="resize_zoom">ⵙⵎⵖⵕ</string>
<string name="mute">ⵙⵓⵙⵎ</string>
<string name="rename_playlist">ⵙⵏⴼⵍ ⵉⵙⵎ</string>
<string name="delete_playlist">ⴽⴽⵙ</string>
<string name="play_queue_audio_settings">ⵜⵉⵙⵖⴰⵍ ⵓⵎⵙⵍⴰⵢ</string>
<string name="play_queue_remove">ⴽⴽⵙ</string>
<string name="action_history">ⴰⵎⵣⵔⵓⵢ</string>
<string name="title_history_search">ⵜⴻⵜⵜⵡⴰⵔⵣⵓⵏ</string>
<string name="title_history_view">ⵜⴻⵜⵜⵓⵥⵕ</string>
<string name="title_activity_history">ⴰⵎⵣⵔⵓⵢ</string>
<string name="website_title">ⴰⵙⵉⵜ</string>
<string name="view_on_github">ⵥⵕ ⴳ GitHub</string>
<string name="tab_licenses">ⵜⵓⵔⴰⴳⵜ</string>
<string name="tab_about">ⵅⴼ</string>
<string name="action_open_website">ⵕⵥⵎ ⴰⵙⵉⵜ</string>
<string name="copyright">© %1$s ⵙⴳ %2$s ⴷⴷⴰⵡ %3$s</string>
<string name="action_about">ⵅⴼ</string>
<string name="action_settings">ⵜⵉⵙⵖⴰⵍ</string>
<string name="title_activity_about">ⵅⴼ NewPipe</string>
<string name="msg_wait">ⵕⴰⵊⴰ…</string>
<string name="msg_error">ⵜⴰⵣⴳⵍⵜ</string>
<string name="msg_name">ⵉⵙⵎ ⵓⴼⴰⵢⵍⵓ</string>
<string name="finish">ⵡⴰⵅⵅⴰ</string>
<string name="rename">ⵙⵙⵏⴼⵍ ⵉⵙⵎ</string>
<string name="dismiss">ⵙⵙⵔ</string>
<string name="delete_all">ⴽⴽⵙ ⵎⴰⵕⵕⴰ</string>
<string name="delete_one">ⴽⵙⵙ ⵢⴰⵏ</string>
<string name="delete">ⴽⴽⵙ</string>
<string name="view">ⵖⵔ</string>
<string name="no_comments">ⵓⵔ ⵍⵍⵉⵏ ⵉⵡⴼⴰⵡⴰⵍⵏ</string>
<plurals name="videos">
<item quantity="one">%s ⵓⴼⵉⴷⵢⵓ</item>
<item quantity="other">%s ⵉⴼⵉⴷⵢⵓⵜⵏ</item>
</plurals>
<string name="infinite_videos">∞ ⵉⴼⵉⴷⵢⵓⵜⵏ</string>
<string name="more_than_100_videos">100+ ⵉⴼⵉⴷⵢⵓⵜⵏ</string>
<string name="short_billion"></string>
<string name="short_million"></string>
<string name="short_thousand"></string>
<string name="audio">ⴰⵎⵙⵍⴰⵢ</string>
<string name="video">ⴰⴼⵉⴷⵢⵓ</string>
<string name="detail_likes_img_view_description">ⵉⵔⵉⵜⵏ</string>
<string name="general_error">ⵜⴰⵣⴳⵍⵜ</string>
<string name="help">ⵜⵉⵡⵉⵙⵉ</string>
<string name="file">ⴰⴼⴰⵢⵍⵓ</string>
<string name="play_all">ⵖⵔ ⵎⴰⵕⵕⴰ</string>
<string name="file_deleted">ⵉⵜⵜⵡⴰⴽⴽⵙ ⵓⴼⴰⵢⵍⵓ</string>
<string name="filter">ⴰⵙⵜⵜⴰⵢ</string>
<string name="yes">ⵢⴰⵀ</string>
<string name="videos_string">ⵉⴼⵉⴷⵢⵓⵜⵏ</string>
<string name="all">ⵎⴰⵕⵕⴰ</string>
<string name="downloads_title">ⵓⴳⴳⴰⵎⵏ</string>
<string name="downloads">ⵓⴳⴳⴰⵎⵏ</string>
<string name="duration_live">ⵓⵙⵔⵉⴷ</string>
<string name="play_btn_text">ⵖⵔ</string>
<string name="settings_category_other_title">ⵢⴰⴹⵏ</string>
<string name="settings_category_video_audio_title">ⴰⴼⵉⴷⵢⵓ ⴷ ⵓⵎⵙⵍⴰⵢ</string>
<string name="download_dialog_title">ⴰⴳⵎ</string>
<string name="enable_watch_history_title">ⵥⵕ ⴰⵎⵣⵔⵓⵢ</string>
<string name="enable_search_history_title">ⴰⵎⵣⵔⵓⵢ ⵓⵔⵣⵣⵓ</string>
<string name="black_theme_title">ⴰⴱⵔⴽⴰⵏ</string>
<string name="play_audio">ⴰⵎⵙⵍⴰⵢ</string>
<string name="play_with_kodi_title">ⵖⵔ ⵙ ⴽⵓⴷⵉ</string>
<string name="controls_add_to_playlist_title">ⵔⵏⵓ ⵖⵔ</string>
<string name="tab_choose">ⵙⵜⵉ ⴰⵙⴽⵙⵍ</string>
<string name="tab_new">ⴰⵙⴽⵙⵍ ⴰⵎⴰⵢⵏⵓ</string>
<string name="share_dialog_title">ⴱⴹⵓ ⵙ</string>
<string name="settings">ⵜⵉⵙⵖⴰⵍ</string>
<string name="search">ⵔⵣⵓ</string>
<string name="download">ⴰⴳⵎ</string>
<string name="share">ⴱⴹⵓ</string>
<string name="install">ⵙⵔⵙ</string>
<string name="cancel">ⵙⵔ</string>
<string name="video_detail_by">ⵙ %s</string>
<string name="channel_created_by">ⵔⵏⵏⵓ ⵜ %s</string>
<string name="feed_group_dialog_delete_message">ⵉⵙ ⵜⵅⵙⴷ ⴰⴷ ⵜⴽⴽⵙⴷ ⵜⵔⴰⴱⴱⵓⵜ ⴰ\?</string>
<string name="stop">ⴱⴷⴷ</string>
<string name="label_code">ⵉⵏⵉⴳⵍ</string>
<string name="grid">ⴰⵥⵟⵟⴰ</string>
<string name="list">ⵜⴰⵍⴳⴰⵎⵜ</string>
<string name="updates_setting_title">ⵜⵓⵙⴷⵖⵉⵏ</string>
<string name="decline">ⴰⴳⵉ</string>
<string name="accept">ⵜⴰⵢⵢⵉⵀⵜ</string>
<string name="resize_fill">ⴽⵜⵔ</string>
<string name="resize_fit">ⵙⴰⵙⵜⵡⴰ</string>
<string name="unmute">ⴽⴽⵙ ⴰⵙⵓⵔⵎ</string>
<string name="background_player">ⴰⵎⵖⵔⵉ ⴷⴼⴼⵉⵔ</string>
<string name="video_player">ⴰⵎⵖⵔⵉ ⵓⴼⵉⴷⵢⵓ</string>
<string name="start_here_on_main">ⵖⵔ ⵙⴰ</string>
<string name="use_tor_title">ⵙⵙⵎⵔⵙ ⵟⵓⵕ</string>
<string name="detail_thumbnail_view_description">ⵖⵔ ⴰⴼⵉⴷⵢⵓ,ⴰⵣⵎⵣ:</string>
<string name="your_comment">ⵉⵅⴼⴰⵡⴰⵍ ⵏⵏⴽ (ⵙ ⵜⵏⴳⵍⵉⵣⵜ):</string>
<string name="what_device_headline">ⴰⵏⵖⵎⵉⵙ:</string>
<string name="error_snackbar_action">ⵎⵍ</string>
<string name="download_path_title">ⴰⵙⴷⴰⵡ ⵓⴳⴰⵎ ⵓⴼⵉⴷⵢⵓ</string>
<string name="tab_subscriptions">ⵜⵉⵙⵓⵔⴰ</string>
<string name="tab_main">ⴰⵙⵏⵓⴱⴳ</string>
<string name="show_info">ⵙⵎⴰⵍ ⴰⵏⵖⵎⵉⵙ</string>
<string name="channel_unsubscribed">ⴽⴽⵙ ⵜⴰⵙⵓⵔⵉ ⵉ ⵓⵙⴰⵔⵓ</string>
<string name="unsubscribe">ⴽⴽⵙ ⵜⴰⵙⵓⵔⵉ</string>
<string name="subscribed_button_title">ⵉⵙⵙⵓⵔ</string>
<string name="subscribe_button_title">ⵙⵙⵓⵔ</string>
<string name="use_external_audio_player_title">ⵙⵎⵔⵙ ⵉⵎⵖⵔⵉ ⵉⵎⵙⵍⵉ ⴰⴱⵕⵕⴰⵏⵉ</string>
<string name="use_external_video_player_title">ⵙⵎⵔⵙ ⵉⵎⵖⵔⵉ ⵓⴼⵉⴷⵢⵓ ⴰⴱⵕⵕⴰⵏⵉ</string>
<string name="screen_rotation">ⵓⵜⵓⵢ</string>
<string name="choose_browser">ⵙⵜⵉ ⵉⵎⵉⵏⵉⴳ</string>
<string name="search_showing_result_for">ⴰⵙⵎⴰⵍ ⵜⴰⵢⴰⴼⵓⵜ ⵉ: %s</string>
<string name="did_you_mean">ⵎⵉⵏ ⵜⵅⵙⴷ ⴰⴷ ⵜⵜ ⵜⵉⵏⵉⴷ: %1$s\?</string>
<string name="view_count_text">%1$s ⵜⴰⵏⵏⴰⵢⵉⵏ</string>
<string name="main_bg_subtitle">ⴰⴷⵔ ⵅ \"ⵔⵣⵓ\"ⴰⴼⴰⴷ ⴰⴷ ⵜⵜⴰⵡⵍⴷ</string>
</resources>

View File

@ -68,7 +68,7 @@
<string name="next_video_title">Следващ клип</string>
<string name="show_next_and_similar_title">Показвай „следващ“ и „подобни“</string>
<string name="show_hold_to_append_title">Показвай съвет „задръж за добавяне“</string>
<string name="url_not_supported_toast">Непознат URL</string>
<string name="unsupported_url">Непознат URL</string>
<string name="content_language_title">Език на съдържанието по подразбиране</string>
<string name="settings_category_player_title">Плейър</string>
<string name="settings_category_player_behavior_title">Поведение</string>
@ -330,7 +330,7 @@
<string name="create_playlist">Нов Плейлист</string>
<string name="delete_playlist">Изтрий</string>
<string name="rename_playlist">"Преименувай "</string>
<string name="playlist_name_input">Име</string>
<string name="name">Име</string>
<string name="append_playlist">Добави Към Плейлист</string>
<string name="set_as_playlist_thumbnail">Задай като миниатюра на плейлиста</string>
<string name="bookmark_playlist">Миниатюрата на плейлиста е сменена</string>
@ -347,7 +347,6 @@
<string name="caption_auto_generated">Авто-генерирани</string>
<string name="caption_setting_title">Надписи</string>
<string name="caption_setting_description">Модифицирай мащаба на текста и фона на надписите. Изисква рестарт на приложението, за да се приложат промените.</string>
<string name="enable_leak_canary_title">Включи LeakCanary</string>
<string name="enable_leak_canary_summary">Следенето за пропускане на памет може да направи приложението нестабилно</string>
<string name="enable_disposed_exceptions_title">Докладвай за извънредни грешки</string>
<string name="import_export_title">Импортиране/Експортиране</string>
@ -413,4 +412,5 @@
<string name="settings_category_updates_title">Промени</string>
<string name="enable_playback_resume_title">Продължи възпроизвеждане</string>
<string name="settings_category_clear_data_title">Изтрии данни</string>
<string name="search_showing_result_for">Показване на резултати за: %s</string>
</resources>

View File

@ -49,7 +49,7 @@
<string name="download_dialog_title">ডাউনলোড</string>
<string name="next_video_title">পরবর্তী ভিডিও</string>
<string name="show_next_and_similar_title">পরবর্তী এবং অনুরূপ ভিডিওগুলি দেখাও</string>
<string name="url_not_supported_toast">URL সমর্থিত নয়</string>
<string name="unsupported_url">URL সমর্থিত নয়</string>
<string name="content_language_title">কন্টেন্ট এর জন্য পছন্দসই ভাষা</string>
<string name="settings_category_video_audio_title">ভিডিও এবং অডিও</string>
<string name="settings_category_popup_title">পপআপ</string>
@ -196,4 +196,16 @@
<string name="volume_gesture_control_title">ভলিউম সংকেত নিয়ন্ত্রণ</string>
<string name="missions_header_finished">সম্পূর্ণ</string>
<string name="list">তালিকা</string>
<string name="enable_playback_state_lists_title">তালিকাতে পজিশন</string>
<string name="enable_playback_resume_summary">শেষ প্লেব্যাক পজিশন এ যাও</string>
<string name="enable_playback_resume_title">পুনরায় প্লে ব্যাক চালু করো</string>
<string name="enable_search_history_summary">সার্চগুলো স্থানীয়ভাবে জমা করো</string>
<string name="show_search_suggestions_summary">সার্চের সময় পরামর্শ দেখাও</string>
<string name="show_search_suggestions_title">সার্চ পরামর্শ</string>
<string name="player_gesture_controls_summary">প্লেয়ারের উজ্জ্বলতা এবং ভলিউম নিয়ন্ত্রণ করতে সংকেত ব্যবহার করো</string>
<string name="search_showing_result_for">রেজাল্ট দেখানো হচ্ছেঃ %s</string>
<string name="tab_about">সম্পর্কিত</string>
<string name="action_about">সম্পর্কিত</string>
<string name="title_activity_about">নিউপাইপ এর সম্বন্ধে</string>
<string name="trending">ট্রেন্ডিং</string>
</resources>

View File

@ -98,7 +98,7 @@
<string name="settings_category_player_title">প্লেয়ার</string>
<string name="content_language_title">কন্টেন্ট এর জন্য পছন্দসই ভাষা</string>
<string name="service_title">সেবা</string>
<string name="url_not_supported_toast">URL সমর্থিত নয়</string>
<string name="unsupported_url">URL সমর্থিত নয়</string>
<string name="show_next_and_similar_title">পরবর্তী এবং অনুরূপ ভিডিওগুলি দেখাও</string>
<string name="next_video_title">পরবর্তী ভিডিও</string>
<string name="download_dialog_title">ডাউনলোড</string>
@ -186,7 +186,6 @@
<string name="view_count_text">%1$s জন দেখেছে</string>
<string name="main_bg_subtitle">অনুসন্ধান এ চাপ দিয়ে শুরু করুন</string>
<string name="feed_create_new_group_button_title">নতুন</string>
<string name="feed_group_dialog_name_input">নাম</string>
<string name="fragment_feed_title">নতুন কি</string>
<string name="app_language_title">অ্যাপ এর ভাষা</string>
<string name="stop">বন্ধ করুন</string>
@ -239,7 +238,7 @@
<string name="invalid_url_toast">অবৈধ ইউ আর এল</string>
<string name="download_to_sdcard_error_title">বাহ্যিক স্টোরেজ নেই</string>
<string name="search_history_deleted">সার্চ ইতিহাস ডিলিট হয়েছে।</string>
<string name="playlist_name_input">নাম</string>
<string name="name">নাম</string>
<string name="rename_playlist">নাম পরিবর্তন</string>
<string name="action_history">ইতিহাস</string>
<string name="read_full_license">লাইসেন্স পড়ুন</string>
@ -329,4 +328,13 @@
<string name="enable_search_history_summary">সার্চ গুলি স্থানীয় ভাবে জমা করুন</string>
<string name="show_search_suggestions_summary">সার্চ এর সময় সাজেশন দেখান</string>
<string name="show_search_suggestions_title">সার্চ সাজেশন</string>
<string name="feed_notification_loading">ফিড লোড হচ্ছে…</string>
<string name="show_error">এরর দেখান</string>
<string name="select_a_playlist">একটি প্লে লিস্ট পছন্দ করুন</string>
<string name="tab_about">সম্পর্কিত</string>
<string name="title_licenses">থার্ড-পার্টি লাইসেন্স সমূহ</string>
<string name="action_about">সম্পর্কিত</string>
<string name="error_report_open_issue_button_text">গিটহাব এ এরর রিপোর্ট করুন</string>
<string name="restore_defaults">ডিফল্ট এ ফিরে যান</string>
<string name="search_showing_result_for">রেজাল্ট দেখান হচ্ছেঃ %s</string>
</resources>

View File

@ -38,7 +38,7 @@
<string name="content">Contingut</string>
<string name="show_age_restricted_content_title">Desactiva les restriccions per edat</string>
<string name="video_is_age_restricted">Mostra el vídeo restringit per edat. Podeu permetre aquesta mena de continguts des dels paràmetres.</string>
<string name="duration_live">EN DIRECTE</string>
<string name="duration_live">Directe</string>
<string name="downloads">Baixades</string>
<string name="downloads_title">Baixades</string>
<string name="all">Tot</string>
@ -105,7 +105,7 @@
<string name="create_playlist">Crea una llista de reproducció</string>
<string name="delete_playlist">Elimina</string>
<string name="rename_playlist">Canvia el nom</string>
<string name="playlist_name_input">Nom</string>
<string name="name">Nom</string>
<string name="append_playlist">Afegeix a una llista de reproducció</string>
<string name="import_title">Importa</string>
<string name="import_from">Importa des de</string>
@ -123,7 +123,7 @@
<string name="share_dialog_title">Comparteix-ho amb</string>
<string name="screen_rotation">rotació</string>
<string name="use_external_video_player_title">Reproductor de vídeo extern</string>
<string name="popup_mode_share_menu_title">Mode emergent del NewPipe</string>
<string name="popup_mode_share_menu_title">Mode emergent</string>
<string name="channel_unsubscribed">Heu eliminat la subscripció a aquest canal</string>
<string name="subscription_change_failed">No s\'ha pogut modificar la subscripció</string>
<string name="subscription_update_failed">No s\'ha pogut actualitzar la subscripció</string>
@ -140,13 +140,13 @@
<string name="show_higher_resolutions_title">Mostra resolucions superiors</string>
<string name="show_higher_resolutions_summary">No tots els dispositius són compatibles amb la reproducció de vídeos en 2K/4K</string>
<string name="play_with_kodi_title">Reprodueix amb el Kodi</string>
<string name="kore_not_found">No s\'ha trobat l\'aplicació Kodi. Voleu instal·lar-la\?</string>
<string name="kore_not_found">No s\'ha trobat l\'aplicació Kore. Voleu instal·lar-la\?</string>
<string name="show_play_with_kodi_title">Mostra «Reprodueix amb el Kodi»</string>
<string name="show_play_with_kodi_summary">Mostra una opció per reproduir un vídeo amb el centre multimèdia Kodi</string>
<string name="popup_remember_size_pos_title">Reproductor emergent intel·ligent</string>
<string name="popup_remember_size_pos_summary">Recorda la darrera mida i posició del reproductor emergent</string>
<string name="use_inexact_seek_title">Cerca ràpida poc precisa</string>
<string name="use_inexact_seek_summary">La cerca poc precisa permet que el reproductor cerqui una posició més ràpidament amb menys precisió</string>
<string name="use_inexact_seek_summary">La cerca poc precisa permet que el reproductor cerqui una posició més ràpidament amb menys precisió. Cerques de 5, 15 o 25 segons no hi funcionaran.</string>
<string name="download_thumbnail_title">Carrega les miniatures</string>
<string name="thumbnail_cache_wipe_complete_notice">S\'ha eliminat la memòria cau d\'imatges</string>
<string name="metadata_cache_wipe_title">Elimina les metadades de la memòria cau</string>
@ -193,7 +193,7 @@
<string name="error_occurred_detail">S\'ha produït un error: %1$s</string>
<string name="error_report_button_text">Informeu de l\'error per correu electrònic</string>
<string name="error_snackbar_message">S\'han produït alguns errors.</string>
<string name="error_snackbar_action">INFORME</string>
<string name="error_snackbar_action">Informe</string>
<string name="what_device_headline">Informació:</string>
<string name="what_happened_headline">Què ha passat:</string>
<string name="your_comment">Comentari (en anglès):</string>
@ -205,7 +205,7 @@
<string name="detail_dislikes_img_view_description">No m\'agrada</string>
<string name="use_tor_title">Fes servir el Tor</string>
<string name="use_tor_summary">(En proves) Força el trànsit de baixada a través del Tor per a més privadesa (no compatible encara amb les emissions de vídeo).</string>
<string name="report_error">Notifiqueu un error</string>
<string name="report_error">Notifiqueu error</string>
<string name="user_report">Informe de l\'usuari</string>
<string name="search_no_results">Cap resultat</string>
<string name="empty_subscription_feed_subtitle">No hi ha res aquí</string>
@ -272,14 +272,14 @@
<string name="playback_speed_control">Controls de la velocitat de reproducció</string>
<string name="playback_tempo">Tempo</string>
<string name="playback_pitch">To</string>
<string name="main_bg_subtitle">Feu un toc al botó de cerca per començar</string>
<string name="main_bg_subtitle">Toca \"Cercar\" per començar</string>
<string name="use_external_video_player_summary">Elimina l\'àudio en algunes resolucions</string>
<string name="use_external_audio_player_title">Reproductor d\'àudio extern</string>
<string name="download_thumbnail_summary">Desactiveu-ho per no generar miniatures i estalviar dades i memòria. Canviant aquesta opció, s\'eliminarà la memòria cau d\'imatges tant de la memòria com de l\'emmagatzematge.</string>
<string name="enable_search_history_summary">Emmagatzema les cerques localment</string>
<string name="enable_watch_history_summary">Crea un historial de vídeos visualitzats</string>
<string name="resume_on_audio_focus_gain_title">Reprèn automàticament</string>
<string name="url_not_supported_toast">Aquest URL no és compatible</string>
<string name="unsupported_url">Aquest URL no és compatible</string>
<string name="error_report_title">Informe d\'error</string>
<string name="later">Més tard</string>
<string name="filter">Filtra</string>
@ -329,7 +329,6 @@
<string name="resize_fill">Omple</string>
<string name="resize_zoom">Escala</string>
<string name="caption_auto_generated">Generats automàticament</string>
<string name="enable_leak_canary_title">Habilita el LeakCanary</string>
<string name="previous_export">Darrera exportació</string>
<string name="subscriptions_import_unsuccessful">No s\'han pogut importar les subscripcions</string>
<string name="subscriptions_export_unsuccessful">No s\'han pogut exportar les subscripcions</string>
@ -503,8 +502,34 @@
<string name="no_one_listening">Cap reproducció</string>
<plurals name="listening">
<item quantity="one">%s escoltant</item>
<item quantity="other">%s escoltant</item>
<item quantity="other">%s escoltants</item>
</plurals>
<string name="localization_changes_requires_app_restart">Es canviarà la llengua en reiniciar l\'aplicació.</string>
<string name="default_kiosk_page_summary">Tendències</string>
<string name="show_original_time_ago_title">Ensenya el temps passat original sobre els \"items\"</string>
<string name="playlist_no_uploader">Auto-generat (no es troba cap uploader)</string>
<string name="unmute">Desactivar Silenci</string>
<string name="mute">Silenciar</string>
<string name="subtitle_activity_recaptcha">Prem \"Fet\" quan estigui resolt</string>
<string name="infinite_videos">∞ vídeos</string>
<string name="more_than_100_videos">100+ vídeos</string>
<string name="permission_display_over_apps">Dona permís per mostrarse per sobre d\'altres apps.</string>
<string name="help">Ajuda</string>
<string name="artists">Artistes</string>
<string name="albums">Albums</string>
<string name="songs">Cançons</string>
<string name="videos_string">Vídeos</string>
<string name="restricted_video">Aquest vídeo té una restricció per edat.
\n
\nSi desitges visualitzar-lo, activa el «Contingut restringit per edat» en la configuració.</string>
<string name="youtube_restricted_mode_enabled_title">Mode de restricció del YouTube</string>
<string name="peertube_instance_add_exists">La instància introduïda ja existeix</string>
<string name="peertube_instance_add_https_only">Només estàn soportades URLs HTTPS</string>
<string name="peertube_instance_add_fail">No ha estat possible validar la instància</string>
<string name="peertube_instance_add_help">Introdueix l\'enllaç d\'una instància</string>
<string name="peertube_instance_add_title">Afegeix-hi una instància</string>
<string name="peertube_instance_url_help">Troba les instàncies que t\'agraden en %s</string>
<string name="peertube_instance_url_summary">Selecciona les teves instàncies preferides del PeerTube</string>
<string name="peertube_instance_url_title">Instàncies del PeerTube</string>
<string name="seek_duration_title">Avançar/-rebobinar duració cerca</string>
</resources>

View File

@ -31,7 +31,7 @@
<string name="settings_category_player_title">کارپێکەر</string>
<string name="import_title">هێنانەوە</string>
<string name="error_report_button_text">سکاڵا لەسەر کێشە لەڕێگای ئیمێڵ</string>
<string name="playlist_name_input">ناو</string>
<string name="name">ناو</string>
<string name="error_postprocessing_failed">چارەسەرکردن شکستی هێنا</string>
<string name="minimize_on_exit_title">بچوکبوونەوە لەکاتی گۆڕینی داوانامە</string>
<string name="feed_page_summary">پەڕەی نوێترینەکان</string>
@ -141,7 +141,6 @@
<item quantity="other">%s گوێی لێدەگرن</item>
</plurals>
<string name="msg_running">داگرتنەکانی داوانامە</string>
<string name="feed_group_dialog_name_input">ناو</string>
<string name="channels">کەناڵەکان</string>
<string name="action_history">مێژوو</string>
<string name="subscriptions_export_unsuccessful">ناتوانرێ بەشدارییەکان پاشەکەوت بکرێن</string>
@ -248,7 +247,6 @@
<string name="channel_page_summary">پەڕەی کەناڵەکان</string>
<string name="switch_to_background">گۆڕین بۆ پاشبنەما</string>
<string name="infinite_videos">∞ ڤیدیۆ</string>
<string name="enable_leak_canary_title">چالاککردنی LeakCanary</string>
<string name="use_inexact_seek_title">بەکارهێنانی بردنەپێشی ناتەواوی خێرا</string>
<string name="error_occurred_detail">هەڵەیەک ڕوویدا : %1$s</string>
<string name="download_path_dialog_title">بوخچەی داگرتن بۆ پەڕگەی ڤیدیۆکان هەڵبژێرە</string>
@ -556,7 +554,7 @@
<string name="install">دامەزراندن</string>
<string name="info_dir_created">شوێنی داگرتن دانرا \'%1$s\'</string>
<string name="videos_string">ڤیدیۆکان</string>
<string name="url_not_supported_toast">بەستەرەکە پشتگیری نەکراوە</string>
<string name="unsupported_url">بەستەرەکە پشتگیری نەکراوە</string>
<string name="playback_pitch">شەپۆلی دەنگ</string>
<string name="minimize_on_exit_summary">کرداری کاتی گۆڕین بۆ داوانامەیەکی تر لە کارپێکەری ڤیدیۆییەوە — %s</string>
<string name="msg_copied">لەبەرگیرایەوە</string>

View File

@ -35,7 +35,7 @@
<string name="download_dialog_title">Stáhnout</string>
<string name="next_video_title">Další</string>
<string name="show_next_and_similar_title">Zobrazovat \'další\' a \'podobná\' videa</string>
<string name="url_not_supported_toast">URL není podporováno</string>
<string name="unsupported_url">URL není podporováno</string>
<string name="content_language_title">Preferovaný jazyk obsahu</string>
<string name="settings_category_video_audio_title">Video a zvuk</string>
<string name="settings_category_appearance_title">Vzhled</string>
@ -108,7 +108,7 @@
<string name="checksum">Kontrolní součet</string>
<string name="no_available_dir">Určete prosím složku pro stahování později v nastavení</string>
<string name="user_report">Hlášení uživatele</string>
<string name="info_labels">Co:\\nŽádost:\\nJazyk obsahu:\\nSlužba:\\nČas GMT:\\nBalíček:\\nVerze:\\nVerze OS:</string>
<string name="info_labels">Co:\\nŽádost:\\nJazyk obsahu\\nZemě obsahu:\\nJazyk aplikace:\\nSlužba:\\nČas GMT:\\nBalíček:\\nVerze:\\nVerze OS:</string>
<string name="all">Vše</string>
<string name="channel">Kanál</string>
<string name="yes">Ano</string>
@ -116,8 +116,8 @@
<string name="short_thousand">tis.</string>
<string name="open_in_popup_mode">Otevřít ve vyskakovacím okně</string>
<string name="short_million">mil.</string>
<string name="msg_popup_permission">Toto oprávnění je vyžadováno pro
otevření ve vyskakovacím okně</string>
<string name="msg_popup_permission">Toto oprávnění je vyžadováno
\npro otevření ve vyskakovacím okně</string>
<string name="use_external_video_player_summary">Odstraňuje zvuk v některých rozlišeních</string>
<string name="show_higher_resolutions_title">Zobrazovat vyšší rozlišení</string>
<string name="show_higher_resolutions_summary">Pouze některá zařízení dokáží přehrát 2K/4K videa</string>
@ -297,7 +297,7 @@ otevření ve vyskakovacím okně</string>
<string name="create_playlist">Nový playlist</string>
<string name="delete_playlist">Vymazat</string>
<string name="rename_playlist">Přejmenovat</string>
<string name="playlist_name_input">Jméno</string>
<string name="name">Jméno</string>
<string name="append_playlist">Přidat do playlistu</string>
<string name="set_as_playlist_thumbnail">Nastavit jako náhled playlistu</string>
<string name="bookmark_playlist">Přidat playlist do záložek</string>
@ -312,8 +312,7 @@ otevření ve vyskakovacím okně</string>
<string name="resize_fill">Vyplnit</string>
<string name="resize_zoom">Zvětšit</string>
<string name="settings_category_debug_title">Ladění</string>
<string name="caption_auto_generated">"Automaticky generováno "</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="caption_auto_generated">Automaticky generováno</string>
<string name="enable_leak_canary_summary">Monitoring úniku paměti může způsobit nereagování aplikace při heap dumpingu</string>
<string name="enable_disposed_exceptions_title">Nahlásit mimo-cyklické chyby</string>
<string name="enable_disposed_exceptions_summary">Vynutit hlášení nedoručitelných výjimek Rx mimo životnost fragmentu nebo aktivity po odstranění</string>
@ -333,12 +332,9 @@ otevření ve vyskakovacím okně</string>
<string name="invalid_file">Soubor neexistuje nebo chybí oprávnění k jeho čtení či zápisu</string>
<string name="file_name_empty_error">Název souboru nesmí být prázdný</string>
<string name="error_occurred_detail">Došlo k chybě: %1$s</string>
<string name="import_export_title">Import/export
\n</string>
<string name="import_title">Importovat
\n</string>
<string name="import_from">Importovat z
\n</string>
<string name="import_export_title">Import/export</string>
<string name="import_title">Importovat</string>
<string name="import_from">Importovat z</string>
<string name="export_to">Exportovat do</string>
<string name="import_ongoing">Importuji…</string>
<string name="export_ongoing">Exportuji…</string>
@ -580,7 +576,6 @@ otevření ve vyskakovacím okně</string>
<item quantity="other">%d vybráno</item>
</plurals>
<string name="feed_group_dialog_empty_name">Prázdné jméno skupiny</string>
<string name="feed_group_dialog_name_input">Jméno</string>
<string name="feed_group_dialog_delete_message">Přejete si smazat tuto skupinu\?</string>
<string name="feed_create_new_group_button_title">Nová</string>
<string name="settings_category_feed_title">Novinky</string>
@ -624,4 +619,12 @@ otevření ve vyskakovacím okně</string>
<string name="video_detail_by">%s</string>
<string name="channel_created_by">Založil %s</string>
<string name="detail_sub_channel_thumbnail_view_description">Miniatura avatara kanálu</string>
<string name="playlist_page_summary">Strana playlistů</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Ukázat jen neseskupené objednávky</string>
<string name="no_playlist_bookmarked_yet">Zatím žádné záložky playlistů</string>
<string name="select_a_playlist">Vybrat playlist</string>
<string name="error_report_open_github_notice">Prosím, ověřte, zda chyba již existuje. Pokud založíte duplikovaný tiket, obíráte nás o čas, který bychom mohli věnovat řešení skutečných chyb.</string>
<string name="error_report_open_issue_button_text">Podat hlášení na GitHubu</string>
<string name="copy_for_github">Zkopírovat formátované hlášení</string>
<string name="search_showing_result_for">Ukazuji výsledky pro: %s</string>
</resources>

View File

@ -92,7 +92,7 @@
<string name="show_next_and_similar_title">Vis \'Næste\' og \'Lignende\' videoer</string>
<string name="show_hold_to_append_title">Vis \"Hold for at tilføje\"-tip</string>
<string name="show_hold_to_append_summary">Vis et tip når der trykkes på baggrunds- eller pop op-knappen på siden med videodetaljer</string>
<string name="url_not_supported_toast">Denne webadresse er ikke understøttet</string>
<string name="unsupported_url">Denne webadresse er ikke understøttet</string>
<string name="default_content_country_title">Standardland for indhold</string>
<string name="service_title">Tjeneste</string>
<string name="content_language_title">Standardsprog for indhold</string>
@ -332,7 +332,7 @@
<string name="create_playlist">Ny spilleliste</string>
<string name="delete_playlist">Slet</string>
<string name="rename_playlist">Omdøb</string>
<string name="playlist_name_input">Navn</string>
<string name="name">Navn</string>
<string name="append_playlist">Føj til spilleliste</string>
<string name="delete_playlist_prompt">Slet denne spilleliste\?</string>
<string name="playlist_creation_success">Spilleliste oprettet</string>
@ -409,7 +409,6 @@
<string name="playlist_thumbnail_change_success">Miniaturebillede for spilleliste ændret.</string>
<string name="playlist_delete_failure">Kunne ikke slette spilleliste.</string>
<string name="caption_setting_description">Ændr undertekststørrelse og baggrundsstil. Kræver genstart af appen for at træde i kraft.</string>
<string name="enable_leak_canary_title">Aktiver LeakCanary</string>
<string name="enable_leak_canary_summary">Monitorering for hukommelseslækager kan få appen til ikke at svare under heap dumping</string>
<string name="enable_disposed_exceptions_title">Rapporter out-of-lifecycle-fejl</string>
<string name="import_export_title">Importer/eksporter</string>

View File

@ -27,14 +27,14 @@
<string name="download_dialog_title">Herunterladen</string>
<string name="next_video_title">Nächste</string>
<string name="show_next_and_similar_title">„Nächste“ und „Ähnliche“ Videos anzeigen</string>
<string name="url_not_supported_toast">Nicht unterstützte URL</string>
<string name="unsupported_url">Nicht unterstützte URL</string>
<string name="settings_category_video_audio_title">Video &amp; Audio</string>
<string name="content_language_title">Bevorzugte Sprache des Inhalts</string>
<string name="list_thumbnail_view_description">Video-Vorschaubild</string>
<string name="detail_thumbnail_view_description">Video abspielen, Dauer:</string>
<string name="detail_uploader_thumbnail_view_description">Avatarbild des Uploaders</string>
<string name="detail_dislikes_img_view_description">Gefällt nicht</string>
<string name="detail_likes_img_view_description">Gefällt</string>
<string name="detail_dislikes_img_view_description">Gefällt mir nicht</string>
<string name="detail_likes_img_view_description">Gefällt mir</string>
<string name="use_external_video_player_title">Externen Video-Player verwenden</string>
<string name="use_external_audio_player_title">Externen Audio-Player verwenden</string>
<string name="background_player_playing_toast">Im Hintergrund abspielen</string>
@ -310,7 +310,6 @@
<string name="file_name_empty_error">Dateiname darf nicht leer sein</string>
<string name="error_occurred_detail">Ein Fehler ist aufgetreten: %1$s</string>
<string name="caption_auto_generated">Automatisch erzeugt</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="import_from">Import von</string>
<string name="export_to">Export nach</string>
<string name="import_ongoing">Importiere…</string>
@ -329,7 +328,7 @@
<string name="invalid_source">Datei-/Inhaltsquelle existiert nicht</string>
<string name="export_complete_toast">Exportiert</string>
<string name="import_complete_toast">Importiert</string>
<string name="playlist_name_input">Name</string>
<string name="name">Name</string>
<string name="import_export_title">Import/Export</string>
<string name="import_title">Import</string>
<string name="subscriptions_import_unsuccessful">Abonnements konnten nicht importiert werden</string>
@ -562,7 +561,6 @@
<item quantity="other">%d ausgewählte</item>
</plurals>
<string name="feed_group_dialog_empty_name">Leerer Gruppenname</string>
<string name="feed_group_dialog_name_input">Name</string>
<string name="feed_group_dialog_delete_message">Möchtest du diese Gruppe löschen\?</string>
<string name="feed_create_new_group_button_title">Neu</string>
<string name="feed_update_threshold_option_always_update">Immer aktualisieren</string>
@ -579,7 +577,7 @@
<string name="feed_oldest_subscription_update">Abos zuletzt aktualisiert: %s</string>
<string name="feed_update_threshold_title">Grenzwert für Feed-Aktualisierung</string>
<string name="feed_use_dedicated_fetch_method_title">Aus fest zugeordnetem Feed abholen wenn verfügbar</string>
<string name="feed_use_dedicated_fetch_method_summary">Steht in manchen Diensten zur Verfügung, ist meist viel schneller, liefert aber eventuell eine eingeschränkte Anzahl an Elementen und oft inkomplette Informationen (z. B. keine Videolänge, keinen Elementtyp, keinen Live-Status).</string>
<string name="feed_use_dedicated_fetch_method_summary">Steht in manchen Diensten zur Verfügung, ist meist viel schneller, liefert aber eventuell eine eingeschränkte Anzahl an Elementen und oft unvollständige Informationen (z. B. keine Videolänge, keinen Elementtyp, keinen Live-Status).</string>
<string name="feed_use_dedicated_fetch_method_help_text">Glaubst du, dass das Laden von Feeds zu langsam ist\? Wenn ja, versuche den Schnelllademodus einzuschalten (du kannst ihn in den Einstellungen oder über die Schaltfläche unten ändern).
\n
\nNewPipe bietet zwei Feed-Ladestrategien:
@ -614,4 +612,9 @@
<string name="channel_created_by">Erstellt von %s</string>
<string name="video_detail_by">Von %s</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Nur nicht gruppierte Abonnements anzeigen</string>
<string name="playlist_page_summary">Playlist-Seite</string>
<string name="no_playlist_bookmarked_yet">Bisher keine Lesezeichen für Wiedergabelisten</string>
<string name="select_a_playlist">Playlist auswählen</string>
<string name="error_report_open_github_notice">Bitte überprüfen Sie, ob es schon Fragen zu diesem Thema gibt. Doppelt erstellte Tickets kosten uns Zeit, die wir nutzen könnten, um diesen Fehler zu beheben.</string>
<string name="search_showing_result_for">Zeige Ergebnisse für: %s</string>
</resources>

View File

@ -35,7 +35,7 @@
<string name="download_dialog_title">Λήψη</string>
<string name="next_video_title">Επόμενο</string>
<string name="show_next_and_similar_title">Εμφάνιση \"Επόμενου\" και \"Σχετικών\" βίντεο</string>
<string name="url_not_supported_toast">Δεν υποστηρίζεται η διεύθυνση URL</string>
<string name="unsupported_url">Δεν υποστηρίζεται η διεύθυνση URL</string>
<string name="content_language_title">Προεπιλεγμένη γλώσσα περιεχομένου</string>
<string name="settings_category_video_audio_title">Βίντεο &amp; Ήχος</string>
<string name="settings_category_appearance_title">Εμφάνιση</string>
@ -122,15 +122,15 @@
<string name="auto_queue_title">Αυτόματη πρόσθεση της επόμενης ροής στην ουρά</string>
<string name="auto_queue_summary">Αυτόματη πρόσθεση μιας σχετικής ροής όταν αναπαράγεται η προηγούμενη ροή σε μια μη-επαναλαμβανόμενη ουρά</string>
<string name="player_gesture_controls_title">Έλεγχος αναπαραγωγής με χειρονομίες</string>
<string name="player_gesture_controls_summary">Χρήση χειρονομιών για τον έλεγχο της φωτεινότητας και της έντασης ήχου της εφαρμογής</string>
<string name="player_gesture_controls_summary">Χρήση χειρονομιών για τον έλεγχο της φωτεινότητας και της έντασης ήχου</string>
<string name="show_search_suggestions_summary">Εμφάνιση υποδείξεων ενώ κάνετε αναζήτηση</string>
<string name="enable_search_history_summary">Αποθήκευση αναζητήσεων στη συσκευή</string>
<string name="enable_watch_history_title">Προβολή Ιστορικού</string>
<string name="enable_watch_history_summary">Κρατήστε ιστορικό των βίντεο που έχετε δει</string>
<string name="resume_on_audio_focus_gain_title">Συνέχεια όταν η εφαρμογή έρθει σε πρώτο πλάνο</string>
<string name="resume_on_audio_focus_gain_summary">Συνέχιση της αναπαραγωγής έπειτα από διακοπές (π.χ.: κλήσεις)</string>
<string name="resume_on_audio_focus_gain_title">Συνέχεια αναπαραγωγής</string>
<string name="resume_on_audio_focus_gain_summary">Συνέχιση της αναπαραγωγής έπειτα από διακοπές (π.χ. κλήσεις)</string>
<string name="show_hold_to_append_title">Εμφάνιση της βοήθειας \"Πιέστε παρατεταμένα για πρόσθεση\"</string>
<string name="show_hold_to_append_summary">Εμφάνιση της βοήθειας όταν έχει πατηθεί το κουμπί Παρασκηνίου ή Αναδυόμενου παραθύρου στη σελίδα λεπτομερειών του βίντεο</string>
<string name="show_hold_to_append_summary">Εμφάνιση υπόδειξης όταν πατηθεί το κουμπί Παρασκηνίου ή Αναδυόμενου παραθύρου στη σελίδα λεπτομερειών του βίντεο</string>
<string name="default_content_country_title">Προεπιλεγμένη χώρα περιεχομένου</string>
<string name="service_title">Υπηρεσία</string>
<string name="settings_category_player_title">Συσκευή Αναπαραγωγής</string>
@ -332,7 +332,7 @@
<string name="create_playlist">Νέα Λίστα Αναπαραγωγής</string>
<string name="delete_playlist">Διαγραφή</string>
<string name="rename_playlist">Μετονομασία</string>
<string name="playlist_name_input">Όνομα</string>
<string name="name">Όνομα</string>
<string name="append_playlist">Προσθήκη στη Λίστα</string>
<string name="set_as_playlist_thumbnail">Ορισμός ως μικρογραφία λίστας αναπαραγωγής</string>
<string name="bookmark_playlist">Προσθήκη Σελιδοδείκτη στη Λίστα</string>
@ -349,7 +349,6 @@
<string name="caption_auto_generated">Αυτόματοι</string>
<string name="caption_setting_title">Υπότιτλοι</string>
<string name="caption_setting_description">Τροποποίηση του μεγέθους και του φόντου των υπότιτλων. Απαιτεί επανεκκίνηση της εφαρμογής.</string>
<string name="enable_leak_canary_title">Ενεργοποίηση του LeakCanary</string>
<string name="enable_leak_canary_summary">Η παρακολούθηση των διαρροών μνήμης μπορεί να προκαλέσει την διακοπή της εφαρμογής</string>
<string name="enable_disposed_exceptions_summary">Υποχρεωτική αναφορά μη παραδοτέων Rx εξαιρέσεων έξω από το κομμάτι ή τον κύκλο δραστηριότητας μετά από απόρριψη</string>
<string name="import_export_title">Εισαγωγή/Εξαγωγή</string>
@ -402,9 +401,9 @@
<string name="tab_new">Νέα Καρτέλα</string>
<string name="tab_choose">Επιλογή Καρτέλας</string>
<string name="volume_gesture_control_title">Ρυθμίσεις χειρονομιών ήχου</string>
<string name="volume_gesture_control_summary">Χρησιμοποιήστε χειρονομίες για τον έλεγχο της έντασης του ήχου</string>
<string name="volume_gesture_control_summary">Χρησιμοποιήστε χειρονομίες για τον έλεγχο έντασης του ήχου</string>
<string name="brightness_gesture_control_title">Ρυθμίσεις χειρονομιών φωτεινότητας</string>
<string name="brightness_gesture_control_summary">Χρησιμοποιήστε χειρονομίες για τον έλεγχο της φωτεινότητας</string>
<string name="brightness_gesture_control_summary">Χρησιμοποιήστε χειρονομίες για τον έλεγχο φωτεινότητας</string>
<string name="settings_category_updates_title">Ενημερώσεις</string>
<string name="events">Συμβάντα</string>
<string name="file_deleted">Το αρχείο διαγράφηκε</string>
@ -517,4 +516,15 @@
<string name="enable_lock_screen_video_thumbnail_title">Μικρογραφίας βίντεο στην οθόνη κλειδώματος</string>
<string name="enable_lock_screen_video_thumbnail_summary">Χρήση μικρογραφίας βίντεο στην οθόνη κλειδώματος</string>
<string name="seek_duration_title">Διάρκεια fastforward και rewind</string>
<string name="systems_language">Προεπιλογή συστήματος</string>
<string name="videos_string">Βίντεο</string>
<string name="search_showing_result_for">Εμφάνιση αποτελεσμάτων για:</string>
<string name="feed_use_dedicated_fetch_method_enable_button">Ενεργοποίηση γρήγορης λειτουργίας</string>
<string name="feed_use_dedicated_fetch_method_disable_button">Απενεργοποίηση γρήγορης λειτουργίας</string>
<string name="content_not_supported">Αυτό το περιεχόμενο δεν υποστηρίζεται ακόμη από το NewPipe.
\n
\nΕλπίζουμε ότι θα υποστηριχθεί σε μια μελλοντική έκδοση.</string>
<string name="detail_sub_channel_thumbnail_view_description">Μικρογραφία avatar του καναλιού</string>
<string name="channel_created_by">Δημιουργήθηκε από %s</string>
<string name="playlist_page_summary">Σελίδα λίστας αναπαραγωγής</string>
</resources>

View File

@ -25,7 +25,7 @@
<string name="light_theme_title">Luma</string>
<string name="download_dialog_title">Elŝuti</string>
<string name="next_video_title">Vica filmeto</string>
<string name="url_not_supported_toast">Ligilo ne subtenita</string>
<string name="unsupported_url">Ligilo ne subtenita</string>
<string name="content_language_title">Preferata enhavlingvo</string>
<string name="settings_category_video_audio_title">Filmeto kaj sono</string>
<string name="settings_category_appearance_title">Apero</string>
@ -190,7 +190,7 @@
<string name="create_playlist">Nova ludlisto</string>
<string name="delete_playlist">Forviŝi</string>
<string name="rename_playlist">Alinomi</string>
<string name="playlist_name_input">Nomo</string>
<string name="name">Nomo</string>
<string name="append_playlist">Aldoni al la ludlisto</string>
<string name="set_as_playlist_thumbnail">Meti kiel bildeto de ludlisto</string>
<string name="bookmark_playlist">Legosigno Ludlisto</string>
@ -402,7 +402,6 @@
<string name="resize_zoom">Zomi</string>
<string name="drawer_header_action_paceholder_text">Io aperos ĉi tie baldaŭ ;D</string>
<string name="caption_auto_generated">Aŭtomate generita</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="enable_leak_canary_summary">La monitorado de la memorlikadoj povas frostigi la apon dum la hejta dumpingo</string>
<string name="enable_disposed_exceptions_title">Signali ekster-vivciklajn erarojn</string>
<string name="enable_disposed_exceptions_summary">Perforti signalante neenretigaj Rx esceptoj eksere la fragmento aŭ aktiveco vivciklo post dispono</string>
@ -564,7 +563,6 @@
</plurals>
<string name="feed_group_dialog_empty_selection">No subscription selected</string>
<string name="feed_group_dialog_empty_name">Malplena grupa nomo</string>
<string name="feed_group_dialog_name_input">Nomo</string>
<string name="feed_group_dialog_delete_message">Ĉu vi volas forviŝi tion grupon?</string>
<string name="feed_create_new_group_button_title">Nova</string>
<string name="settings_category_feed_title">Abonfluo</string>

View File

@ -27,7 +27,7 @@
<string name="default_audio_format_title">Formato de audio predeterminado</string>
<string name="download_dialog_title">Descargar</string>
<string name="next_video_title">Siguiente</string>
<string name="url_not_supported_toast">No se admite el URL</string>
<string name="unsupported_url">No se admite el URL</string>
<string name="use_external_video_player_title">Usar reproductor de vídeo externo</string>
<string name="use_external_audio_player_title">Usar reproductor de audio externo</string>
<string name="theme_title">Tema</string>
@ -51,17 +51,17 @@
<string name="could_not_load_thumbnails">No se pudo cargar las miniaturas</string>
<string name="youtube_signature_decryption_error">No se pudo descifrar la URL del vídeo</string>
<string name="parsing_error">No se pudo analizar el sitio web</string>
<string name="show_next_and_similar_title">Mostrar vídeos «siguientes» y «similares»</string>
<string name="show_next_and_similar_title">Mostrar vídeos \'Siguientes\' y \'Similares\'</string>
<string name="content_language_title">Idioma predeterminado del contenido</string>
<string name="list_thumbnail_view_description">Miniatura de previsualización del vídeo</string>
<string name="detail_thumbnail_view_description">Reproducir vídeo; duración:</string>
<string name="detail_likes_img_view_description">Me gusta</string>
<string name="detail_dislikes_img_view_description">No me gusta</string>
<string name="detail_uploader_thumbnail_view_description">Miniatura del avatar del usuario</string>
<string name="live_streams_not_supported">Aún no se admiten las transmisiones en vivo</string>
<string name="live_streams_not_supported">Las transmisiones en vivo no son soportadas aún</string>
<string name="content">Contenido</string>
<string name="show_age_restricted_content_title">Contenido restringido por edad</string>
<string name="video_is_age_restricted">Mostrar vídeo restringido por edad. Se pueden realizar más cambios desde los ajustes.</string>
<string name="video_is_age_restricted">Mostrar vídeo restringido por edad. Se pueden realizar cambios futuros desde los ajustes.</string>
<string name="main_bg_subtitle">Toque «Buscar» para empezar</string>
<string name="autoplay_by_calling_app_title">Reproducción automática</string>
<string name="autoplay_by_calling_app_summary">Reproducir un vídeo cuando NewPipe es llamado desde otra app</string>
@ -101,12 +101,12 @@
<string name="msg_url_malform">URL mal escrito o Internet no disponible</string>
<string name="msg_running">NewPipe está descargando</string>
<string name="msg_running_detail">Toque para ver detalles</string>
<string name="msg_wait">Espere…</string>
<string name="msg_wait">Espere, por favor</string>
<string name="msg_copied">Copiado en el portapapeles</string>
<string name="no_available_dir">Defina una carpeta de descargas más tarde en la configuración</string>
<string name="could_not_load_image">No se pudo cargar la imagen</string>
<string name="app_ui_crash">La interfaz de la app dejó de funcionar</string>
<string name="info_labels">Lo sucedido:\\nPetición:\\nIdioma del contenido:\\nServicio:\\nHora GMT:\\nPaquete:\\nVersión:\\nVersión del SO:</string>
<string name="info_labels">Lo sucedido:\\nPetición:\\nIdioma del Contenido:\\nPaís del contenido:\\nIdioma de la aplicación:\\nServicio:\\nHora GMT:\\nPaquete:\\nVersión:\\nVersión del SO:</string>
<string name="black_theme_title">Negro</string>
<string name="all">Todo</string>
<string name="channel">Canal</string>
@ -114,7 +114,7 @@
<string name="later">Después</string>
<string name="short_thousand">k</string>
<string name="short_million">M</string>
<string name="short_billion">MM</string>
<string name="short_billion">G</string>
<string name="open_in_popup_mode">Abrir en modo emergente</string>
<string name="msg_popup_permission">Se necesita este permiso
\npara abrir en modo emergente</string>
@ -193,7 +193,7 @@
<string name="playlist">Lista de reproducción</string>
<string name="undo">Deshacer</string>
<string name="search_no_results">No hay resultados</string>
<string name="empty_subscription_feed_subtitle">Aquí no hay nada más que grillos</string>
<string name="empty_subscription_feed_subtitle">Nada aquí, sino grillos</string>
<string name="no_subscribers">Sin suscriptores</string>
<plurals name="subscribers">
<item quantity="one">%s suscriptor</item>
@ -239,12 +239,12 @@
<string name="start_here_on_main">Comenzar a reproducir aquí</string>
<string name="start_here_on_background">Comenzar a reproducir en segundo plano</string>
<string name="start_here_on_popup">Reproducir en modo emergente</string>
<string name="show_hold_to_append_title">Mostrar consejo «Mantener presionado para agregar»</string>
<string name="show_hold_to_append_title">Mostrar consejo \"Mantener presionado para añadir\"</string>
<string name="new_and_hot">Novedades</string>
<string name="hold_to_append">Mantener presionado para agregar a la cola</string>
<string name="donation_title">Donar</string>
<string name="donation_encouragement">NewPipe es desarrollado por voluntarios que emplean su tiempo libre para brindarle la mejor experiencia. Haga una aportación para ayudarlos a crear un NewPipe mejor mientras disfrutan de una taza de café.</string>
<string name="give_back">Donar</string>
<string name="give_back">Dar de vuelta</string>
<string name="website_title">Sitio web</string>
<string name="website_encouragement">Visite el sitio web de NewPipe para más información y noticias.</string>
<string name="default_content_country_title">País predeterminado del contenido</string>
@ -294,7 +294,7 @@
<string name="create_playlist">Lista de reproducción nueva</string>
<string name="delete_playlist">Eliminar</string>
<string name="rename_playlist">Cambiar nombre</string>
<string name="playlist_name_input">Nombre</string>
<string name="name">Nombre</string>
<string name="append_playlist">Añadir a la lista de reproducción</string>
<string name="set_as_playlist_thumbnail">Definir como miniatura de lista de reproducción</string>
<string name="bookmark_playlist">Marcar lista de reproducción</string>
@ -311,7 +311,6 @@
<string name="resize_zoom">Zoom</string>
<string name="settings_category_debug_title">Depuración</string>
<string name="caption_auto_generated">Auto generados</string>
<string name="enable_leak_canary_title">Activar LeakCanary</string>
<string name="enable_leak_canary_summary">La monitorización de fugas de memoria puede causar que la app no responda cuando hay Heap Dump</string>
<string name="enable_disposed_exceptions_title">Reportar errores fuera del ciclo de duración</string>
<string name="enable_disposed_exceptions_summary">Forzar reporte de excepciones no entregables de RX fuera del fragmento o del ciclo de actividad después del descarte</string>
@ -322,7 +321,7 @@
<string name="file">Archivo</string>
<string name="missing_file">Archivo movido o eliminado</string>
<string name="invalid_directory">La carpeta no existe</string>
<string name="invalid_source">No existe la fuente del archivo/contenido</string>
<string name="invalid_source">No existe tal archivo/origen del contenido</string>
<string name="invalid_file">El archivo no existe o carece de los permisos para leer o escribir en él</string>
<string name="file_name_empty_error">El nombre del archivo no puede estar vacío</string>
<string name="error_occurred_detail">Ocurrió un error: %1$s</string>
@ -379,9 +378,11 @@
<string name="app_license">NewPipe es un software copyleft libre: puedes usarlo, estudiarlo, compartirlo y mejorarlo a voluntad. Específicamente, puedes redistribuirlo y/o modificarlo bajo los términos de la Licencia Pública General GNU publicada por la Free Software Foundation, ya sea la versión 3 de la Licencia, o (a tu elección) cualquier versión posterior.</string>
<string name="import_settings">¿Quiere importar también la configuración\?</string>
<string name="privacy_policy_title">Normativa de privacidad de NewPipe</string>
<string name="privacy_policy_encouragement">El proyecto NewPipe toma su privacidad muy en serio. Por ello, la aplicación no recopila ningún dato sin su consentimiento. La normativa de privacidad de NewPipe explica en detalle qué datos se envían y almacenan cuando envía un informe de fallo.</string>
<string name="privacy_policy_encouragement">El proyecto NewPipe toma su privacidad muy en serio. Por ello, la aplicación no recopila algún dato sin su consentimiento.
\nLa normativa de privacidad de NewPipe explica en detalle qué datos se envían y almacenan cuando envía un informe de fallo.</string>
<string name="read_privacy_policy">Leer la normativa de privacidad</string>
<string name="start_accept_privacy_policy">Para cumplir con el Reglamento general europeo de protección de datos (GDPR), podemos llamar su atención sobre la política de privacidad de NewPipe. Por favor léelo cuidadosamente. Debe aceptarlo para enviarnos el informe de error.</string>
<string name="start_accept_privacy_policy">Para cumplir con el Reglamento general europeo de protección de datos (GDPR), atraemos su atención sobre la política de privacidad de NewPipe. Por favor léase cuidadosamente.
\nDebe aceptarlo para enviarnos el informe de error.</string>
<string name="accept">Aceptar</string>
<string name="decline">Declinar</string>
<string name="limit_data_usage_none_description">Sin límite</string>
@ -456,7 +457,7 @@
<string name="downloads_storage_use_saf_title">Usar SAF</string>
<string name="downloads_storage_use_saf_summary">El \'Framework de Acceso al Almacenamiento\' permite descargar en una tarjeta SD externa.
\nAlgunos dispositivos no son compatibles</string>
<string name="unsubscribe">Cancelar suscripción</string>
<string name="unsubscribe">Desuscribirse</string>
<string name="tab_new">Pestaña nueva</string>
<string name="tab_choose">Elija la pestaña</string>
<string name="volume_gesture_control_title">Control de volumen por gestos</string>
@ -526,11 +527,11 @@
<string name="playlist_no_uploader">Generado automáticamente (no se encontró creador)</string>
<string name="choose_instance_prompt">Elige una instancia</string>
<string name="enable_lock_screen_video_thumbnail_title">Miniatura de vídeo en pantalla de bloqueo</string>
<string name="enable_lock_screen_video_thumbnail_summary">Se mostrará una miniatura del vídeo en la pantalla de bloqueo al usar el reproductor en segundo plano</string>
<string name="enable_lock_screen_video_thumbnail_summary">Una miniatura del vídeo es mostrada en la pantalla de bloqueo cuando se está usando el reproductor en segundo plano</string>
<string name="clear_download_history">Limpiar historial de descargas</string>
<string name="delete_downloaded_files">Eliminar archivos descargados</string>
<string name="deleted_downloads">Eliminadas %1$d descargas</string>
<string name="permission_display_over_apps">Dar permisos para que se muestre por sobre otras apps</string>
<string name="permission_display_over_apps">Permitir mostrar sobre otras aplicaciones</string>
<string name="app_language_title">Idioma de aplicación</string>
<string name="systems_language">Predeterminado del sistema</string>
<string name="subtitle_activity_recaptcha">Pulse en «Hecho» cuando esté resuelto</string>
@ -568,7 +569,6 @@
<item quantity="other">%d elegidas</item>
</plurals>
<string name="feed_group_dialog_empty_name">Nombre de grupo vacío</string>
<string name="feed_group_dialog_name_input">Nombre</string>
<string name="feed_group_dialog_delete_message">¿Borrar este grupo\?</string>
<string name="feed_create_new_group_button_title">Nuevo</string>
<string name="settings_category_feed_title">Contenido</string>
@ -612,4 +612,12 @@
<string name="show_original_time_ago_summary">Los textos originales de los servicios serán visibles en los ítems de transmisiones</string>
<string name="show_original_time_ago_title">Mostrar tiempo atrás original en ítems</string>
<string name="youtube_restricted_mode_enabled_title">Modo restringido de YouTube</string>
<string name="playlist_page_summary">Página de lista de reproducción</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Mostrar sólo suscripciones desagrupadas</string>
<string name="no_playlist_bookmarked_yet">Sin marcadores de lista de reproducción aún</string>
<string name="select_a_playlist">Seleccione una lista de reproducción</string>
<string name="error_report_open_github_notice">Por favor revise si ya existe una discusión sobre su problema. Cuando se crean entradas duplicadas, toma tiempo de nosotros que podríamos usar para arreglar tal problema.</string>
<string name="error_report_open_issue_button_text">Reportar error en Github</string>
<string name="copy_for_github">Copiar reporte con formato</string>
<string name="search_showing_result_for">Mostrando resultados para: %s</string>
</resources>

View File

@ -84,7 +84,7 @@
<string name="show_next_and_similar_title">Kuva \'järgmine\' ja \'sarnased\' videod</string>
<string name="show_hold_to_append_title">Kuva vihjet \"lisamiseks hoia\"</string>
<string name="show_hold_to_append_summary">Kuva vihje, kui videoandmete lehel vajutatakse tausta või hüpikakna nupule</string>
<string name="url_not_supported_toast">Mitte toetatud URL</string>
<string name="unsupported_url">Mitte toetatud URL</string>
<string name="default_content_country_title">Sisu vaikimisi riik</string>
<string name="service_title">Teenus</string>
<string name="content_language_title">Sisu vaikimisi keel</string>
@ -318,7 +318,7 @@
<string name="create_playlist">Uus pleilist</string>
<string name="delete_playlist">Kustuta</string>
<string name="rename_playlist">Nimeta ümber</string>
<string name="playlist_name_input">Nimi</string>
<string name="name">Nimi</string>
<string name="append_playlist">Lisa pleilisti</string>
<string name="set_as_playlist_thumbnail">Määra pleilisti pisipildiks</string>
<string name="bookmark_playlist">Lisa pleilist järjehoidjaks</string>
@ -376,7 +376,6 @@
<string name="privacy_policy_encouragement">NewPipe võtab privaatsust väga tõsiselt. Seetõttu ei kogu rakendus ilma nõusolekuta mingeid andmeid.
\nNewPipe privaatsuspoliitika selgitab üksikasjalikult, milliseid andmeid saadetakse ja kogutakse veateate saatmisel.</string>
<string name="app_license">NewPipe vaba avatud koodiga tarkvara. Seada võib kasutada, uurida, jagada ja parandada. Täpsemalt - seda võib levitada ja/või muuta vastavalt Vaba Tarkvara Sihtasutuse avaldatud GNU Üldise Avaliku Litsentsi v.3 (või hilisem) tingimustele.</string>
<string name="enable_leak_canary_title">Luba LeakCanary</string>
<string name="enable_disposed_exceptions_title">Teavita elutsüklist väljas vigadest</string>
<string name="import_soundcloud_instructions">Impordi SoundCloudi profiil trükkides URL või oma ID:
\n

View File

@ -25,7 +25,7 @@
<string name="download_dialog_title">Deskargatu</string>
<string name="next_video_title">Hurrengoa</string>
<string name="show_next_and_similar_title">Erakutsi \'hurrengo\' eta \'antzeko\' bideoak</string>
<string name="url_not_supported_toast">URLak ez du euskarririk</string>
<string name="unsupported_url">URLak ez du euskarririk</string>
<string name="content_language_title">Edukiaren hizkuntz lehenetsia</string>
<string name="settings_category_video_audio_title">Bideoa eta Audioa</string>
<string name="play_btn_text">Erreproduzitu</string>
@ -322,7 +322,7 @@
<string name="create_playlist">Erreprodukzio-zerrenda berria</string>
<string name="delete_playlist">Ezabatu</string>
<string name="rename_playlist">Aldatu izena</string>
<string name="playlist_name_input">Izena</string>
<string name="name">Izena</string>
<string name="append_playlist">Gehitu erreprodukzio-zerrendara</string>
<string name="set_as_playlist_thumbnail">Ezarri erreprodukzio-zerrendaren iruditxo gisa</string>
<string name="bookmark_playlist">Gogoko erreprodukzio-zerrenda</string>
@ -339,7 +339,6 @@
<string name="caption_auto_generated">Automatikoki sortuak</string>
<string name="caption_setting_title">Azpitituluak</string>
<string name="caption_setting_description">Aldatu azpitituluen testuaren eskala eta atzealdeko estiloa. Aplikazioa berrabiarazi behar da aldaketak aplikatzeko.</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="enable_leak_canary_summary">Memoria galeren monitorizazioa. Aplikazioak agian ez du erantzungo memoriaren aitortza egin bitartean</string>
<string name="enable_disposed_exceptions_title">Eman bizitza-ziklo kanpoko erroreen berri</string>
<string name="import_export_title">Inportatu/esportatu</string>
@ -561,7 +560,6 @@
<string name="settings_category_feed_title">Jarioa</string>
<string name="feed_create_new_group_button_title">Berria</string>
<string name="feed_group_dialog_delete_message">Talde hau ezabatu nahi duzu\?</string>
<string name="feed_group_dialog_name_input">Izena</string>
<string name="feed_group_dialog_empty_name">Talde izena hutsik</string>
<plurals name="feed_group_dialog_selection_count">
<item quantity="one">%d hautatuta</item>

View File

@ -38,7 +38,7 @@
<string name="download_dialog_title">بارگیری</string>
<string name="next_video_title">بعدی</string>
<string name="show_next_and_similar_title">نماش ویدیوهای «بعدی» و «مشابه»</string>
<string name="url_not_supported_toast">نشانی پشتیبانی نشده</string>
<string name="unsupported_url">نشانی پشتیبانی نشده</string>
<string name="content_language_title">زبان محتوای ترجیحی</string>
<string name="settings_category_video_audio_title">ویدیو و صدا</string>
<string name="settings_category_appearance_title">ظاهر</string>
@ -269,7 +269,7 @@
<string name="create_playlist">فهرست پخش جدید</string>
<string name="delete_playlist">پاک‌کردن</string>
<string name="rename_playlist">تغییر نام</string>
<string name="playlist_name_input">نام</string>
<string name="name">نام</string>
<string name="append_playlist">افزودن به فهرست پخش</string>
<string name="set_as_playlist_thumbnail">استفاده به عنوان تصویر فهرست پخش</string>
<string name="delete_playlist_prompt">این فهرست پخش پاک شود؟</string>
@ -416,7 +416,7 @@
<string name="metadata_cache_wipe_complete_notice">فراداده‌های کش شده پاکش شدند</string>
<string name="playback_tempo">تندا</string>
<string name="playback_pitch">زیر و بمی</string>
<string name="unhook_checkbox">قطع پیوند (ممکن است باعث اعوجاج شود)</string>
<string name="unhook_checkbox">قطع پیوند (ممکن است باعث انحراف شود)</string>
<string name="preferred_open_action_settings_title">ترجیح کنش «باز کردن»</string>
<string name="preferred_open_action_settings_summary">کنش پیش‌فرض در زمان باز کردن محتوا — %s</string>
<string name="caption_setting_description">سبک پس‌زمینه و اندازه متن توضیحات پخش‌کننده را تغییر بده. برای تاثیرگذاری، نیازمند بازراه‌اندازی برنامه است.</string>
@ -431,7 +431,7 @@
<string name="playback_reset">بازنشانی</string>
<string name="download_to_sdcard_error_title">فضای ذخیره‌سازی خارجی در دسترس نیست</string>
<string name="download_to_sdcard_error_message">بارگیری روی کارت SD خارجی ممکن نیست. مایلید محل پوشه بارگیری را دوباره تعیین کنید؟</string>
<string name="saved_tabs_invalid_json">استفاده از برگه‌های پیش‌فرض، خطا حین خواندن برگه‌های ذخیره شده</string>
<string name="saved_tabs_invalid_json">به دلیل ناتوانی در خواندن برگه‌های ذخیره شده، برگه‌های پیش‌فرض استفاده می‌شوند</string>
<string name="subscribers_count_not_available">تعداد مشترک‌شدگان دردسترس نیست</string>
<string name="main_page_content_summary">چه برگه‌هایی در صفحه اصلی نمایش پیدا کنند</string>
<string name="updates_setting_description">زمانی که نسخه جدید برنامه دردسرس است، اعلانی برای به‌روزرسانی نمایش بده</string>
@ -516,7 +516,6 @@
<string name="settings_category_feed_title">خوراک</string>
<string name="feed_create_new_group_button_title">جدید</string>
<string name="feed_group_dialog_delete_message">می‌خواهید این گروه را پاک کنید؟</string>
<string name="feed_group_dialog_name_input">نام</string>
<plurals name="feed_group_dialog_selection_count">
<item quantity="one">%d مورد انتخاب شده</item>
<item quantity="other">%d مورد انتخاب شده</item>
@ -582,4 +581,17 @@
<string name="albums">آلبوم‌ها</string>
<string name="songs">موسیقی‌ها</string>
<string name="youtube_restricted_mode_enabled_title">حالت محدودیت یوتیوب</string>
<string name="search_showing_result_for">نمایش نتایج برای: %s</string>
<string name="error_report_open_issue_button_text">گزارش خطا در گیت‌هاب</string>
<string name="error_report_open_github_notice">لطفا بررسی کنید که آیا گفتگویی درباره مشکل‌تان از قبل وجود دارد یا خیر. ایجاد گزارش تکراری، وقتی را از ما می‌گیرد که ما می‌توانستیم صرف رفع مشکلات واقعی کنیم.</string>
<string name="select_a_playlist">انتخاب یک فهرست پخش</string>
<string name="no_playlist_bookmarked_yet">نشانک‌های فهرست پخش هنوز موجود نیستند</string>
<string name="copy_for_github">گزارش قالب بندی شده را رونویسی کنید</string>
<string name="playlist_no_uploader">تولید شده به صورت خودکار (بارگذارکننده ای یافت نشد)</string>
<string name="feed_groups_header_title">دسته بندی کانال ها</string>
<string name="feed_group_dialog_select_subscriptions">انتخاب اشتراک ها</string>
<string name="feed_group_dialog_empty_selection">اشتراکی انتخاب نشده است</string>
<string name="feed_group_show_only_ungrouped_subscriptions">نمایش اشتراک های دسته بندی نشده</string>
<string name="detail_sub_channel_thumbnail_view_description">آواتار بندانگشتی کانال</string>
<string name="playlist_page_summary">صفحه فهرست پخش</string>
</resources>

View File

@ -17,14 +17,14 @@
<string name="choose_browser">Valitse selain</string>
<string name="screen_rotation">kierto</string>
<string name="use_external_video_player_title">Käytä ulkoista videosoitinta</string>
<string name="use_external_video_player_summary">Poistaa äänen joillakin resoluutioilla</string>
<string name="use_external_video_player_summary">Ääni saattaa lakata toimimasta joillakin resoluutioilla</string>
<string name="use_external_audio_player_title">Käytä ulkoista äänisoitinta</string>
<string name="popup_mode_share_menu_title">Ponnahdusikkunatila</string>
<string name="subscribe_button_title">Tilaa</string>
<string name="subscribed_button_title">Tilattu</string>
<string name="channel_unsubscribed">Kanavan tilaus peruttu</string>
<string name="subscription_change_failed">Tilauksen vaihtaminen epäonnistui</string>
<string name="subscription_update_failed">Ei pystytty päivittämään tilausta</string>
<string name="subscription_update_failed">Tilausta ei voitu päivittää</string>
<string name="tab_main">Päävalikko</string>
<string name="tab_subscriptions">Tilaukset</string>
<string name="fragment_feed_title">Uudet</string>
@ -40,12 +40,12 @@
<string name="autoplay_by_calling_app_summary">Toistaa videon automaattisesti, kun NewPipe avataan toisesta ohjelmasta</string>
<string name="default_resolution_title">Oletusresoluutio</string>
<string name="default_popup_resolution_title">Ponnahdusikkunan oletusresoluutio</string>
<string name="show_higher_resolutions_title">Näytä korkeampia resoluutioita</string>
<string name="show_higher_resolutions_summary">Vain jotkin laitteet voivat toistaa 2K/4K-videoa</string>
<string name="play_with_kodi_title">Toista Kodi:ssa</string>
<string name="show_higher_resolutions_title">Näytä korkeammat resoluutiot</string>
<string name="show_higher_resolutions_summary">Vain jotkin laitteet voivat toistaa 2K/4K-videota</string>
<string name="play_with_kodi_title">Toista Kodissa</string>
<string name="kore_not_found">Asennetaanko puuttuva Kore-sovellus\?</string>
<string name="show_play_with_kodi_title">Näytä \"Toista Kodi:ssa\" vaihtoehto</string>
<string name="show_play_with_kodi_summary">Näyttää painikkeen, jolla voi toistaa videon Kodi media center:llä</string>
<string name="show_play_with_kodi_title">Näytä \"Toista Kodissa\"-vaihtoehto</string>
<string name="show_play_with_kodi_summary">Näyttää vaihtoehdon videon toistamiseen Kodi-mediasoittimessa</string>
<string name="play_audio">Ääni</string>
<string name="default_audio_format_title">Oletusääniformaatti</string>
<string name="default_video_format_title">Oletusvideoformaatti</string>
@ -67,8 +67,8 @@
<string name="download_dialog_title">Lataus</string>
<string name="next_video_title">Seuraava</string>
<string name="show_next_and_similar_title">Näytä seuraavia ja samankaltaisia videoita</string>
<string name="url_not_supported_toast">URL ei tuettu</string>
<string name="content_language_title">Oletus-sisällon kieli</string>
<string name="unsupported_url">URL ei tuettu</string>
<string name="content_language_title">Sisällon oletuskieli</string>
<string name="settings_category_player_title">Soitin</string>
<string name="settings_category_player_behavior_title">Käyttäytyminen</string>
<string name="settings_category_video_audio_title">Video &amp; ääni</string>
@ -102,12 +102,12 @@
<string name="notification_channel_description">Ilmoitukset NewPipen tausta- ja ponnahdusikkunasoittimille</string>
<string name="general_error">Virhe</string>
<string name="network_error">Verkkovirhe</string>
<string name="could_not_load_thumbnails">Ei pystytty lataamaan kaikkia esikatselukuvia</string>
<string name="youtube_signature_decryption_error">Ei pystytty purkamaan salausta videon URL allekirjoitukselle</string>
<string name="parsing_error">Ei pystytty jäsentämään websivua</string>
<string name="light_parsing_error">Ei pystytty jäsentämään websivua kokonaan</string>
<string name="could_not_load_thumbnails">Kaikkia esikatselukuvia ei voitu ladata</string>
<string name="youtube_signature_decryption_error">Videon URL-allekirjoituksen salausta ei voitu purkaa</string>
<string name="parsing_error">Verkkosivua ei voitu jäsentää</string>
<string name="light_parsing_error">Verkkosivua ei voitu täysin jäsentää</string>
<string name="content_not_available">Sisältö ei ole saatavilla</string>
<string name="could_not_setup_download_menu">Ei pystytty asettamaan latausvalikkoa</string>
<string name="could_not_setup_download_menu">Latausvalikkoa ei voitu asettaa</string>
<string name="live_streams_not_supported">Live-suoratoistoa ei vielä tueta</string>
<string name="could_not_get_stream">Suoratoistosisältöä ei saatu</string>
<string name="could_not_load_image">Kuvan lataus epäonnistui</string>
@ -178,9 +178,9 @@
<string name="recaptcha_request_toast">reCAPTCHA-haaste pyydetty</string>
<string name="settings_category_downloads_title">Lataus</string>
<string name="settings_file_charset_title">Sallitut merkit tiedostonimissä</string>
<string name="settings_file_replacement_character_summary">Epäkelvot merkit korvataan tällä arvolla</string>
<string name="settings_file_replacement_character_summary">Kielletyt merkit korvataan tällä arvolla</string>
<string name="settings_file_replacement_character_title">Korvaava merkki</string>
<string name="charset_letters_and_digits">Kirjaimia ja numeroita</string>
<string name="charset_letters_and_digits">Kirjaimet ja numerot</string>
<string name="charset_most_special_characters">Suurin osa erikoismerkeistä</string>
<string name="title_activity_about">Tietoja NewPipe</string>
<string name="action_settings">Asetukset</string>
@ -208,7 +208,7 @@
<string name="delete_item_search_history">Haluatko poistaa tämän hakuhistoriasta?</string>
<string name="resume_on_audio_focus_gain_title">Jatka toistoa</string>
<string name="what_device_headline">Info:</string>
<string name="info_labels">Mikä:\\nPyyntö:\\nSisällön kieli:\\nPalvelu:\\nGMT Aika:\\nPaketti:\\nVersio:\\nOS versio:</string>
<string name="info_labels">Mikä:\\nPyyntö:\\nSisällön kieli:\\nSisällön maa:\\n:Sovelluksen kieli:\\nPalvelu:\\nGMT Aika:\\nPaketti:\\nVersio:\\nOS versio:</string>
<string name="copyright" formatted="true">© %1$s %2$s %3$s alla</string>
<string name="main_page_content">Pääsivun sisältö</string>
<string name="blank_page_summary">Tyhjä sivu</string>
@ -249,7 +249,7 @@
<string name="no_player_found_toast">Suoratoistosoitinta ei löytynyt (voit asentaa VLC:n toistaaksesi).</string>
<string name="controls_download_desc">Lataa suoratoistotiedosto</string>
<string name="show_info">Näytä lisätietoja</string>
<string name="tab_bookmarks">Kirjanmerkityt soittolistat</string>
<string name="tab_bookmarks">Soittolistakirjanmerkit</string>
<string name="controls_add_to_playlist_title">Lisää soittolistaan</string>
<string name="use_inexact_seek_title">Käytä nopeampaa epätarkkaa pikakelausta</string>
<string name="use_inexact_seek_summary">Epätarkka kelaus mahdollistaa videon kelauksen nopeammin huonommalla tarkkuudella. Kelaaminen 5, 15 tai 25 sekuntia ei toimi tämän kanssa.</string>
@ -334,7 +334,7 @@
<string name="create_playlist">Uusi soittolista</string>
<string name="delete_playlist">Poista</string>
<string name="rename_playlist">Uudelleennimeä</string>
<string name="playlist_name_input">Nimi</string>
<string name="name">Nimi</string>
<string name="append_playlist">Lisää soittolistaan</string>
<string name="set_as_playlist_thumbnail">Aseta soittolistan kuvakkeeksi</string>
<string name="bookmark_playlist">Tallenna soittolista kirjanmerkkeihin</string>
@ -351,7 +351,6 @@
<string name="caption_auto_generated">Automaattisesti luotu</string>
<string name="caption_setting_title">Tekstitykset</string>
<string name="caption_setting_description">Muokkaa soittimen tekstitysten kokoa ja taustatyylejä. Asetusten käyttöönotto vaatii uudelleenkäynnistyksen.</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="enable_leak_canary_summary">Muistivuotojen valvonta voi aiheuttaa ohjelman hidastumisen virhetilanteissa</string>
<string name="enable_disposed_exceptions_title">Raportoi yhteensopivuusvirheitä, jotka aiheutuvat vanhoista ohjelmista</string>
<string name="enable_disposed_exceptions_summary">Pakota raportointi toimituskelvottomille Rx-poikkeuksille, jotka ovat poiston jälkeen muistisirpaleiden tai aktiviteettielämänkaaren ulkopuolella</string>
@ -392,7 +391,7 @@
<string name="accept">Hyväksy</string>
<string name="decline">Hylkää</string>
<string name="limit_data_usage_none_description">Ei rajaa</string>
<string name="limit_mobile_data_usage_title">Rajoita resoluutiota kun mobiilidata on käytössä</string>
<string name="limit_mobile_data_usage_title">Rajoita resoluutiota mobiilidataa käytettäessä</string>
<string name="minimize_on_exit_title">Pienennä vaihdettaessa ohjelmaa</string>
<string name="minimize_on_exit_summary">Toiminto vaihdettaessa toiseen ohjelmaan päävideosoittimesta — %s</string>
<string name="minimize_on_exit_none_description">Ei koskaan</string>
@ -510,11 +509,10 @@
<string name="feed_use_dedicated_fetch_method_title">Hae erityisestä syötteestä, kun sellainen on saatavilla</string>
<string name="feed_update_threshold_option_always_update">Päivitä aina</string>
<string name="feed_update_threshold_summary">Edellisestä päivityksestä kulunut aika, jonka jälkeen tilaus katsotaan vanhentuneeksi</string>
<string name="feed_update_threshold_title">Syötteen päivitysvälin kynnysarvo</string>
<string name="feed_update_threshold_title">Syötteen päivitysväli</string>
<string name="settings_category_feed_title">Syöte</string>
<string name="feed_create_new_group_button_title">Uusi</string>
<string name="feed_group_dialog_delete_message">Haluatko poistaa tämän ryhmän\?</string>
<string name="feed_group_dialog_name_input">Nimi</string>
<string name="feed_group_dialog_empty_name">Tyhjä ryhmän nimi</string>
<plurals name="feed_group_dialog_selection_count">
<item quantity="one">%d valittu</item>
@ -550,13 +548,13 @@
<string name="choose_instance_prompt">Valitse instanssi</string>
<string name="downloads_storage_use_saf_summary">\'Storage Access Framework\' sallii lataukset ulkoiselle SD-kortille.
\nJotkin laitteet eivät ole yhteensopivia</string>
<string name="downloads_storage_use_saf_title">Käytä SAF:ää</string>
<string name="downloads_storage_use_saf_title">Ota SAF käyttöön</string>
<string name="downloads_storage_ask_summary_kitkat">Jokaisen latauksen kohde kysytään.
\nValitse SAF, jos haluat ladata ulkoiselle SD-kortille</string>
<string name="downloads_storage_ask_summary">Jokaisen latauksen kohde kysytään</string>
<string name="downloads_storage_ask_title">Kysy mihin ladataan</string>
<string name="start_downloads">Aloita lataukset</string>
<string name="enable_queue_limit_desc">Yksi lataus kerrallaan on käynnissä</string>
<string name="enable_queue_limit_desc">Salli vain yksi lataus kerrallaan</string>
<string name="enable_queue_limit">Rajoita latausjonon kokoa</string>
<string name="max_retry_desc">Suurin määrä yrityksiä ennen kuin lataus perutaan</string>
<string name="max_retry_msg">Uudelleenyritysten maksimimäärä</string>
@ -596,7 +594,7 @@
<string name="show_original_time_ago_title">Näytä alkuperäinen aika sisällölle</string>
<string name="pause_downloads">Tauota lataukset</string>
<string name="pause_downloads_on_mobile_desc">Hyödyllinen vaihdettaessa mobiilidataan, vaikka joitakin latauksia ei voi pysäyttää</string>
<string name="pause_downloads_on_mobile">Keskeytä käytön mukaan laskutettavilla yhteyksillä</string>
<string name="pause_downloads_on_mobile">Keskeytä, kun yhteys on käytön mukaan laskutettava</string>
<string name="paused">tauotettu</string>
<string name="app_update_notification_content_text">Napauta ladataksesi</string>
<string name="app_update_notification_content_title">NewPipe-päivitys on saatavilla!</string>
@ -611,4 +609,12 @@
<string name="unmute">Poista mykistys</string>
<string name="mute">Mykistä</string>
<string name="conferences">Konferenssit</string>
<string name="playlist_page_summary">Soittolistasivu</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Näytä vain ryhmittelemättömät tilaukset</string>
<string name="no_playlist_bookmarked_yet">Ei soittolistakirjanmerkkejä vielä</string>
<string name="select_a_playlist">Valitse soittolista</string>
<string name="error_report_open_github_notice">Ole hyvä ja tarkasta onko kaatumiseen liittyvä ongelma jo raportoitu. Tikettien kaksoiskappaleiden selvittely vie aikaa varsinaisten ohjelmavirheiden korjaamiselta.</string>
<string name="error_report_open_issue_button_text">Raportoi virhe GitHubissa</string>
<string name="copy_for_github">Kopioi muotoiltu raportti</string>
<string name="search_showing_result_for">Näytetään tulokset haulle: %s</string>
</resources>

View File

@ -42,4 +42,9 @@
<string name="download_path_dialog_title">Pumili ng folder kung saan ido-download ang mga bidyo</string>
<string name="download_path_audio_summary">Nakaimbak sa folder na ito ang mga nai-download na mga audio files</string>
<string name="download_path_audio_dialog_title">Pumili ng folder kung saan ido-download ang mga audio files</string>
<string name="light_theme_title">Maliwanag</string>
<string name="play_with_kodi_title">Buksan gamit Kodi</string>
<string name="dark_theme_title">Madilim</string>
<string name="download_choose_new_path">Palitan ang folder na paglalagyan ng download para umipekto</string>
<string name="download_path_summary">Dito makikita ang mga nadownload na video</string>
</resources>

View File

@ -27,7 +27,7 @@
<string name="download_dialog_title">Télécharger</string>
<string name="next_video_title">Suivant</string>
<string name="show_next_and_similar_title">Afficher les vidéos « Suivantes » et « Similaires »</string>
<string name="url_not_supported_toast">URL non pris en charge</string>
<string name="unsupported_url">URL non pris en charge</string>
<string name="settings_category_video_audio_title">Vidéo et audio</string>
<string name="settings_category_other_title">Autre</string>
<string name="list_thumbnail_view_description">Miniature daperçu vidéo</string>
@ -116,7 +116,7 @@
<string name="yes">Oui</string>
<string name="later">Plus tard</string>
<string name="disabled">Désactivés</string>
<string name="info_labels">Quoi :\\nRequête :\\nLangue du contenu :\\nService :\\nHeure UTC :\\nPaquet :\\nVersion :\\nVersion du système dexploitation :</string>
<string name="info_labels">Quoi :\\nRequête :\\nLangue du contenu :\\nPays du contenu :\\nLangue de lapplication :\\nService :\\nDate UTC :\\nPaquet :\\nVersion :\\nVersion du système dexploitation :</string>
<string name="short_thousand">k</string>
<string name="short_million">M</string>
<string name="msg_popup_permission">Cette autorisation est nécessaire pour
@ -290,7 +290,7 @@
<string name="create_playlist">Nouvelle liste de lecture</string>
<string name="delete_playlist">Supprimer</string>
<string name="rename_playlist">Renommer</string>
<string name="playlist_name_input">Nom</string>
<string name="name">Nom</string>
<string name="append_playlist">Ajouter à la liste de lecture</string>
<string name="set_as_playlist_thumbnail">Définir comme miniature de la liste de lecture</string>
<string name="bookmark_playlist">Enregister la liste de lecture</string>
@ -325,7 +325,6 @@
<string name="settings_category_debug_title">Débogage</string>
<string name="resize_fill">Remplir</string>
<string name="caption_auto_generated">Générés automatiquement</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="enable_leak_canary_summary">La surveillance des fuites de mémoire peut geler lapplication durant le vidage du tas</string>
<string name="enable_disposed_exceptions_title">Rapporter les erreurs hors cycle de vie</string>
<string name="enable_disposed_exceptions_summary">Forcer le rapport des exceptions Rx non livrables en dehors des fragments ou activités durant le cycle de vie après traitement</string>
@ -568,7 +567,6 @@
<item quantity="other">%d sélectionnés</item>
</plurals>
<string name="feed_group_dialog_empty_name">Nom de groupe vide</string>
<string name="feed_group_dialog_name_input">Nom</string>
<string name="feed_group_dialog_delete_message">Voulez-vous supprimer ce groupe ?</string>
<string name="feed_create_new_group_button_title">Nouveau</string>
<string name="settings_category_feed_title">Flux</string>
@ -612,4 +610,11 @@
<string name="show_original_time_ago_title">Afficher la date originelle sur les items</string>
<string name="youtube_restricted_mode_enabled_title">Mode restreint de YouTube</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Afficher les abonnements sans groupes uniquement</string>
<string name="playlist_page_summary">Page des listes de lecture</string>
<string name="no_playlist_bookmarked_yet">Aucune liste de lecture encore enregistrée</string>
<string name="select_a_playlist">Sélectionner une liste de lecture</string>
<string name="error_report_open_github_notice">Veuillez vérifier si un ticket concernant votre problème existe déjà. Lorsque vous créez des tickets dupliqués, cela nous prend du temps que nous pourrions passer à résoudre effectivement le problème.</string>
<string name="error_report_open_issue_button_text">Rapporter lerreur sur GitHub</string>
<string name="copy_for_github">Copier le rapport formaté</string>
<string name="search_showing_result_for">Affichage des résultats pour : %s</string>
</resources>

View File

@ -1,59 +1,54 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources><string name="main_bg_subtitle">Toque em «Procurar» para comezar</string>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_bg_subtitle">Toque en \"Buscar\" para comezar</string>
<string name="view_count_text">%1$s visualizacións</string>
<string name="upload_date_text">Publicado o día %1$s</string>
<string name="no_player_found">Non foi encontrado ningún reprodutor. Desexa instalar o VLC?</string>
<string name="no_player_found_toast">Non foi encontrado ningún reprodutor (pode instalar o VLC para o reproducir)</string>
<string name="no_player_found">Non foi encontrado ningún reprodutor. Quere instalar o VLC\?</string>
<string name="no_player_found_toast">Non foi encontrado ningún reprodutor (pode instalar o VLC para o reproducir).</string>
<string name="install">Instalar</string>
<string name="cancel">Cancelar</string>
<string name="open_in_browser">Abrir no navegador</string>
<string name="open_in_popup_mode">Abrir no modo popup</string>
<string name="share">Compartillar</string>
<string name="download">Descarregar</string>
<string name="controls_download_desc">Descarregar o ficheiro de emisión.</string>
<string name="controls_download_desc">Descargar o ficheiro de transmisión</string>
<string name="search">Procurar</string>
<string name="settings">Opcións</string>
<string name="did_you_mean">Non querería dicir «%1$s»?</string>
<string name="did_you_mean">Non querería dicir %1$s\?</string>
<string name="share_dialog_title">Compartillar con</string>
<string name="choose_browser">Escoller un navegador</string>
<string name="screen_rotation">rotación</string>
<string name="use_external_video_player_title">Usar un reprodutor de vídeo externo</string>
<string name="use_external_video_player_summary">Podería NON haber audio con algunhas resolucións se esta opción estiver activa</string>
<string name="use_external_video_player_summary">Elimina o audio con algunhas resolucións</string>
<string name="use_external_audio_player_title">Usar un reprodutor externo de audio</string>
<string name="popup_mode_share_menu_title">Modo popup do NewPipe</string>
<string name="popup_mode_share_menu_title">Modo xurdir de repente do NewPipe</string>
<string name="subscribe_button_title">Subscribir</string>
<string name="subscribed_button_title">Subscrito</string>
<string name="channel_unsubscribed">Xa non está subscrito ao canal</string>
<string name="subscription_change_failed">Non foi posíbel modificar a subscrición</string>
<string name="subscription_update_failed">Non foi posíbel actualizar a subscrición</string>
<string name="subscription_change_failed">Non se pode modificar a subscrición</string>
<string name="subscription_update_failed">Non se pode actualizar a subscrición</string>
<string name="show_info">Mostrar información</string>
<string name="tab_main">Principal</string>
<string name="tab_subscriptions">Subscricións</string>
<string name="tab_bookmarks">Favoritos</string>
<string name="tab_bookmarks">Listas de reprodución marcadas</string>
<string name="fragment_feed_title">Novidades</string>
<string name="controls_background_title">Segundo plano</string>
<string name="controls_popup_title">Modo popup</string>
<string name="controls_add_to_playlist_title">Engadir a</string>
<string name="download_path_title">Ruta de descarga de vídeos</string>
<string name="download_path_summary">Ruta onde gardar os vídeos descarregados</string>
<string name="download_path_dialog_title">Introduza a ruta de descarga de vídeos</string>
<string name="download_path_audio_title">Ruta de descarga de audio</string>
<string name="download_path_audio_summary">Ruta onde gardar o audio descarregado</string>
<string name="download_path_audio_dialog_title">Introduza a ruta de descarga dos ficheiros de audio</string>
<string name="download_path_title">Cartafol de descargas para os vídeos</string>
<string name="download_path_summary">Os vídeos descargados están almacenados aquí</string>
<string name="download_path_dialog_title">Elixa un cartafol de descargas para os vídeos</string>
<string name="download_path_audio_title">Cartafol de descarga de audio</string>
<string name="download_path_audio_summary">Os audios descargados están gardados aquí</string>
<string name="download_path_audio_dialog_title">Elixa un cartafol para descargar os audios</string>
<string name="autoplay_by_calling_app_title">Reproducir automaticamente</string>
<string name="autoplay_by_calling_app_summary">Reproducir o vídeo pedido cando o NewPipe sexa invocado por outro aplicativo</string>
<string name="default_resolution_title">Resolución predeterminada</string>
<string name="default_popup_resolution_title">Resolución predeterminada do popup</string>
<string name="show_higher_resolutions_title">Mostrar resolucións máis altas</string>
<string name="show_higher_resolutions_summary">Moitos dispositivos non permiten reproducir vídeos en 2K/4K</string>
<string name="show_higher_resolutions_summary">Só algúns dispositivos poden reproducir vídeos en 2K/4K</string>
<string name="play_with_kodi_title">Reproducir co Kodi</string>
<string name="kore_not_found">O aplicativo Kore non foi encontrado. Desexa instalalo?</string>
<string name="kore_not_found">Quere instalar o aplicativo Kore que falta\?</string>
<string name="show_play_with_kodi_title">Mostrar a opción «Reproducir co Kodi»</string>
<string name="show_play_with_kodi_summary">Mostrar unha opción para reproducir o vídeo co Kodi Media Center</string>
<string name="play_audio">Audio</string>
@ -66,38 +61,38 @@
<string name="popup_remember_size_pos_title">Lembrar o tamaño e a posición do «popup»</string>
<string name="popup_remember_size_pos_summary">Lembrar o tamaño e a posición anteriores do «popup»</string>
<string name="use_inexact_seek_title">Usar un salto inexacto mais inexacto</string>
<string name="use_inexact_seek_summary">O salto inexacto permite saltar a posicións máis rápido, mais con menos precisión</string>
<string name="use_inexact_seek_summary">Busca incorrecta permite ao xogador buscar posicións máis rápidas con precisión reducida. A busca de 5, 15 ou 25 segundos non funciona con isto.</string>
<string name="download_thumbnail_title">Carregar miniaturas</string>
<string name="download_thumbnail_summary">Desactíveo para evitar a carga de miniaturas e poupar datos e memoria. Modificar esta opción limpa a caché de imaxes da memoria e do disco</string>
<string name="download_thumbnail_summary">Desactíveo para evitar a carga de miniaturas e poupar datos e memoria. Modificar esta opción limpa a caché de imaxes da memoria e do disco.</string>
<string name="thumbnail_cache_wipe_complete_notice">A caché de imaxes foi limpada</string>
<string name="metadata_cache_wipe_title">Os metadatos da caché foron eliminados</string>
<string name="metadata_cache_wipe_summary">Eliminar todos os datos de páxinas en caché</string>
<string name="metadata_cache_wipe_complete_notice">Os metadatos da caché foron eliminados</string>
<string name="auto_queue_title">Colocar a seguinte emisión na cola automaticamente</string>
<string name="auto_queue_summary">Engadir automaticamente unha emisión ao reproducir a última emisión nunha cola sen repetición</string>
<string name="auto_queue_summary">Continúa rematando (non se repite) a cola de reprodución engadindo unha transmisión relacionada</string>
<string name="player_gesture_controls_title">Controis de xesto do reprodutor</string>
<string name="player_gesture_controls_summary">Usar xestos para controlar o brillo e volume do reprodutor</string>
<string name="player_gesture_controls_summary">Use xestos para controlar o brillo e o volume do reprodutor</string>
<string name="show_search_suggestions_title">Suxestións de procura</string>
<string name="show_search_suggestions_summary">Mostrar suxestións ao procurar</string>
<string name="enable_search_history_title">Historial de procura</string>
<string name="enable_search_history_summary">Gardar os termos de pesquisa localmente</string>
<string name="enable_watch_history_title">Historial e caché</string>
<string name="enable_watch_history_title">Ver o historial</string>
<string name="enable_watch_history_summary">Gardar historial de vídeos vistos</string>
<string name="resume_on_audio_focus_gain_title">Retormar o vídeo ao enfocar</string>
<string name="resume_on_audio_focus_gain_summary">Continuar a reprodución as interrupcións (como chamadas)</string>
<string name="resume_on_audio_focus_gain_title">Retormar o vídeo reproducíndoo</string>
<string name="resume_on_audio_focus_gain_summary">Continuar reproducindo o vídeo despois das interrupcións (como, por exemplo, as chamadas)</string>
<string name="download_dialog_title">Descarregar</string>
<string name="next_video_title">Vídeo seguinte</string>
<string name="show_next_and_similar_title">Mostrar vídeos «seguintes» e «semellantes»</string>
<string name="show_hold_to_append_title">Mostrar a suxestión «Manteña presionado para engadir á cola»</string>
<string name="show_hold_to_append_summary">Mostrar unha suxestión ao premer o botón de segundo plano ou o de popup na páxina de detalles do vídeo</string>
<string name="url_not_supported_toast">Este URL non está soportado</string>
<string name="next_video_title">Seguinte</string>
<string name="show_next_and_similar_title">Mostrar vídeos \"seguintes\" e \"semellantes\"</string>
<string name="show_hold_to_append_title">Mostrar a suxestión \"Manteña presionado para engadir á cola\"</string>
<string name="show_hold_to_append_summary">Amosar o consello ao premer o fondo ou o botón emerxente \"Detalles:\" no vídeo</string>
<string name="unsupported_url">URL non soportado</string>
<string name="default_content_country_title">País predeterminado para o contido</string>
<string name="service_title">Servizo</string>
<string name="settings_category_player_title">Reprodutor</string>
<string name="settings_category_player_behavior_title">Comportamento</string>
<string name="settings_category_video_audio_title">Vídeo e audio</string>
<string name="settings_category_history_title">Historial e caché</string>
<string name="settings_category_popup_title">Popup</string>
<string name="settings_category_video_audio_title">Vídeo &amp; audio</string>
<string name="settings_category_history_title">Historial &amp; caché</string>
<string name="settings_category_popup_title">Xurdir</string>
<string name="settings_category_appearance_title">Aparencia</string>
<string name="settings_category_other_title">Outros</string>
<string name="settings_category_debug_title">Depuración</string>
@ -107,9 +102,9 @@
<string name="popup_playing_append">Na cola do reprodutor popup</string>
<string name="play_btn_text">Reproducir</string>
<string name="content">Contido</string>
<string name="show_age_restricted_content_title">Mostrar contido con restrición de idade</string>
<string name="video_is_age_restricted">Vídeo con restrición de idade. Pode permitir a reprodución deste material nas Opcións.</string>
<string name="duration_live">en directo</string>
<string name="show_age_restricted_content_title">Contido restrinxido para certa idade</string>
<string name="video_is_age_restricted">Mostrar vídeo restrinxido por idade. Os cambios futuros son posibles na configuración.</string>
<string name="duration_live">En directo</string>
<string name="downloads">Descargas</string>
<string name="downloads_title">Descargas</string>
<string name="error_report_title">Relatorio de erro</string>
@ -133,28 +128,24 @@
<string name="always">Sempre</string>
<string name="just_once">Só unha vez</string>
<string name="file">Ficheiro</string>
<string name="notification_channel_name">Notificación do NewPipe</string>
<string name="notification_channel_description">Notificacións para o NewPipe e os reprodutores «popup»</string>
<string name="notification_channel_description">Notificacións para os reprodutores de fondo e reprodutores emerxentes de NewPipe</string>
<string name="unknown_content">[Descoñecido]</string>
<string name="toggle_orientation">Mudar a orientación</string>
<string name="switch_to_background">Mudar para o segundo plano</string>
<string name="switch_to_popup">Mudar para o «popup»</string>
<string name="switch_to_main">Mudar para principal</string>
<string name="import_data_title">Importar base de datos</string>
<string name="export_data_title">Exportar base de datos</string>
<string name="import_data_summary">Isto vai sobreescribir o seu historial e as súas subscricións actuais</string>
<string name="import_data_summary">Anula o teu historial e subscricións actuais</string>
<string name="export_data_summary">Exportar historial, subscricións e listas de reprodución</string>
<string name="clear_views_history_title">Limpar historial de reproducións</string>
<string name="clear_views_history_summary">Elimina o historial de emisións reproducidas</string>
<string name="delete_view_history_alert">Elimina todo o historial de reproducións.</string>
<string name="clear_views_history_summary">Elimina o historial de transmisións reproducidas e as posicións da reprodución</string>
<string name="delete_view_history_alert">Eliminar todo o historial de reproducións\?</string>
<string name="watch_history_deleted">O historial de reproducións foi eliminado.</string>
<string name="clear_search_history_title">Limpar o historial de procura</string>
<string name="clear_search_history_summary">Elimina o historial de termos procurados</string>
<string name="delete_search_history_alert">Elimina todo o historial de procura.</string>
<string name="delete_search_history_alert">Eliminar todo o historial de procura\?</string>
<string name="search_history_deleted">O historial de procuras foi eliminado.</string>
<string name="general_error">Erro</string>
<string name="network_error">Erro de rede</string>
@ -162,10 +153,9 @@
<string name="youtube_signature_decryption_error">Non foi posíbel descifrar a asinatura do vídeo</string>
<string name="parsing_error">Non foi posíbel procesar o sitio web</string>
<string name="light_parsing_error">Non foi posíbel procesar o sitio web por completo</string>
<string name="content_not_available">O contido non está dispoñíbel
\n</string>
<string name="content_not_available">Contido non dispoñíbel</string>
<string name="could_not_setup_download_menu">Non foi posíbel configurar o menú de descargas</string>
<string name="live_streams_not_supported">Isto é unha emisión en directo, polo que aínda non está soportado.</string>
<string name="live_streams_not_supported">Isto é unha emisión en directo, polo que aínda non está soportado</string>
<string name="could_not_get_stream">Non foi posíbel obter unha emisión</string>
<string name="could_not_load_image">Non foi posíbel carregar a imaxe</string>
<string name="app_ui_crash">O aplicativo pechouse</string>
@ -176,67 +166,57 @@
<string name="invalid_url_toast">URL inválido</string>
<string name="video_streams_empty">Non foi encontrada ningunha emisión de vídeo</string>
<string name="audio_streams_empty">Non foi encontrada ningunha emisión de audio</string>
<string name="invalid_directory">Directorio inválido</string>
<string name="invalid_source">A fonte do ficheiro ou contido é inválida</string>
<string name="invalid_file">O ficheiro non existe ou non ten permisos suficientes para o ler ou escribir</string>
<string name="file_name_empty_error">O nome do ficheiro non pode estar vacío</string>
<string name="invalid_directory">Non hai ningún cartafol</string>
<string name="invalid_source">Non hai ningún ficheiro / fonte de contido</string>
<string name="invalid_file">O ficheiro non existe ou falta permiso para lelo ou escribilo</string>
<string name="file_name_empty_error">O nome do ficheiro non pode estar baleiro</string>
<string name="error_occurred_detail">Ocorreu un erro: %1$s</string>
<string name="no_streams_available_download">Non hai emisións para descargar</string>
<string name="sorry_string">Deculpe, isto non debería ter acontecido.</string>
<string name="error_report_button_text">Informar do erro por correo electrónico</string>
<string name="error_report_button_text">Informar deste erro por enderezo electrónico</string>
<string name="error_snackbar_message">Desculpe, ocorreron algúns erros.</string>
<string name="error_snackbar_action">Relatorio</string>
<string name="error_snackbar_action">Informe</string>
<string name="what_device_headline">Información:</string>
<string name="what_happened_headline">Que ocorreu:</string>
<string name="info_labels">Problema:\\nPetición:\\nIdioma do contido:\\nServizo:\\nHora GMT:\\nPaquete:\\nVersión:\\nVersión do SO:</string>
<string name="info_labels">Que: \\n Solicitar: \\n Idioma de contido: \\n País de contido: \\n Idioma do aplicativo: \\nServicio: \\n Tempo GMT: \\n Paquete: \\n Versión: \\n versión de nOS:</string>
<string name="your_comment">O teu comentario (en inglés):</string>
<string name="error_details_headline">Detalles:</string>
<string name="list_thumbnail_view_description">Miniatura do vídeo</string>
<string name="detail_thumbnail_view_description">Miniatura do vídeo</string>
<string name="detail_thumbnail_view_description">Reproducir o vídeo, duración:</string>
<string name="detail_uploader_thumbnail_view_description">Miniatura do avatar do autor</string>
<string name="detail_likes_img_view_description">Gosto</string>
<string name="detail_dislikes_img_view_description">Non gosto</string>
<string name="use_tor_title">Usar o Tor</string>
<string name="use_tor_summary">(Experimental) Redirixir o tráfico polo Tor para aumentar a privacidade (as emisións aínda non están soportadas).</string>
<string name="report_error">Informar dun erro</string>
<string name="report_error">Informe do erro</string>
<string name="user_report">Relatorio do usuario</string>
<string name="search_no_results">Non hai resultados</string>
<string name="empty_subscription_feed_subtitle">Nada que ver</string>
<string name="empty_subscription_feed_subtitle">Nada que ver aquí</string>
<string name="detail_drag_description">Arrastre para reordenar</string>
<string name="err_dir_create">Non foi posíbel crear o directorio «%1$s»</string>
<string name="info_dir_created">O directorio de descargas «%1$s» foi creado</string>
<string name="video">Vídeo</string>
<string name="audio">Audio</string>
<string name="retry">Tentar de novo</string>
<string name="storage_permission_denied">A permisión de acceso ao almacenamento foi denegada</string>
<string name="short_thousand">K</string>
<string name="storage_permission_denied">Outorga primeiro o acceso ao almacenamento</string>
<string name="short_thousand">k</string>
<string name="short_million">M</string>
<string name="short_billion">MM</string>
<string name="short_billion">B</string>
<string name="no_subscribers">Ningún subscrito</string>
<plurals name="subscribers">
<item quantity="one">%s subscrito</item>
<item quantity="other">%s subscritos</item>
</plurals>
<item quantity="one">%s subscrito</item>
<item quantity="other">%s subscritos</item>
</plurals>
<string name="no_views">Ningunha visualización</string>
<plurals name="views">
<item quantity="one">%s visualización</item>
<item quantity="other">%s visualizacións</item>
</plurals>
<item quantity="one">%s visualización</item>
<item quantity="other">%s visualizacións</item>
</plurals>
<string name="no_videos">Ningún vídeo</string>
<plurals name="videos">
<item quantity="one">%s vídeo</item>
<item quantity="other">%s vídeos</item>
</plurals>
<item quantity="one">%s vídeo</item>
<item quantity="other">%s vídeos</item>
</plurals>
<string name="start">Comezar</string>
<string name="pause">Pausar</string>
<string name="view">Reproducir</string>
@ -247,38 +227,31 @@
<string name="checksum">Suma de comprobación</string>
<string name="dismiss">Descartar</string>
<string name="rename">Renomear</string>
<string name="add">Nova misión</string>
<string name="finish">OK</string>
<string name="msg_name">Nome do ficheiro</string>
<string name="msg_threads">Fios</string>
<string name="msg_error">Erro</string>
<string name="msg_server_unsupported">O servidor non está soportado</string>
<string name="msg_server_unsupported">Servidor non soportado</string>
<string name="msg_exists">O ficheiro xa existe</string>
<string name="msg_url_malform">O URL está mal formado ou a Internet non está dispoñíbel</string>
<string name="msg_running">Descarga do NewPipe</string>
<string name="msg_running_detail">Toque para ver detalles</string>
<string name="msg_wait">Por favor, agarde…</string>
<string name="msg_copied">Copiado para o portarretallos</string>
<string name="no_available_dir">Por favor, seleccione o directorio para descargas</string>
<string name="no_available_dir">Selecciona un cartafol de descarga máis tarde na configuración</string>
<string name="msg_popup_permission">Esta permisión é necesaria
\npara abrir o vídeo no modo «popup»</string>
<string name="one_item_deleted">1 elemento foi eliminado.</string>
<string name="title_activity_recaptcha">Desafío reCAPTCHA</string>
<string name="recaptcha_request_toast">Desafío reCAPTCHA solicitado</string>
<string name="recaptcha_request_toast">ReCAPTCHA reto solicitado</string>
<string name="settings_category_downloads_title">Descarregar</string>
<string name="settings_file_charset_title">Caracteres permitidos nos nomes de ficheiros</string>
<string name="settings_file_replacement_character_summary">Os caracteres inválidos serán substituídos por este valor</string>
<string name="settings_file_replacement_character_title">Carácter de substitución</string>
<string name="charset_letters_and_digits">Letras e díxitos</string>
<string name="charset_most_special_characters">A maioría dos caracteres especiais</string>
<string name="toast_no_player">Non hai ningún aplicativo instalado para reproducir este ficheiro</string>
<string name="title_activity_about">Sobre o NewPipe</string>
<string name="action_settings">Opcións</string>
<string name="action_about">Sobre</string>
@ -294,7 +267,7 @@
<string name="contribution_encouragement">Se ten ideas de tradución, mudanzas ao deseño, limpeza de código ou mudanzas serias deste—a axuda sempre é benvida. Canto máis fixermos, tanto máis vai mellorar!</string>
<string name="view_on_github">Ver no GitHub</string>
<string name="donation_title">Doar</string>
<string name="donation_encouragement">O NewPipe é desenvolvido por voluntarios que empregan o seu tempo libre para lle ofrecer a mellor experiencia. Pode retribuír e así axudar os desenvolvedores a tornaren o NewPipe aínda mellor en canto desfrutan dunha cunca de café.</string>
<string name="donation_encouragement">NewPipe é desenvolvido por voluntarios que pasan o seu tempo libre para brindarte a mellor experiencia de usuario. Regresa aos desenvolvedores para que NewPipe sexa aínda mellor mentres gozan dunha cunca de café.</string>
<string name="give_back">Retribuír</string>
<string name="website_title">Sitio web</string>
<string name="website_encouragement">Visite o sitio web do NewPipe para saber máis e ver noticias sobre o proxecto.</string>
@ -303,14 +276,12 @@
\nA política de privacidade do NewPipe explica con máis detalle que datos son enviados e gardados cando envía un relatorio de erros.</string>
<string name="read_privacy_policy">Ler a política de privacidade</string>
<string name="app_license_title">Licenza do NewPipe</string>
<string name="app_license">O NewPipe é software copyleft libre: pode usalo, estudalo, compartillalo e melloralo como quixer. En concreto, pode redistribuílo e/ou modificalo so os termos da Licenza Pública Xeral GNU, publicada pola Free Software Foundation, quer a versión 3 da Licenza, ou calquera outra versión posterior da súa escolla.</string>
<string name="app_license">NewPipe é un software libre copyleft: Podes usar, estudar compartir e melloralo a vontade. En concreto, pode redistribuír e / ou modificala segundo os termos da Licenza Pública Xeral GNU publicada pola Free Software Foundation, xa sexa a versión 3 da licenza, ou (na súa opción) calquera outra versión posterior.</string>
<string name="read_full_license">Ler a licenza</string>
<string name="title_activity_history">Historial</string>
<string name="title_history_search">Procurado</string>
<string name="title_history_view">Visto</string>
<string name="history_disabled">O historial está desactivado</string>
<string name="history_disabled">A historia está desactivada</string>
<string name="action_history">Historial</string>
<string name="history_empty">O historial está vacío</string>
<string name="history_cleared">O historial foi limpado</string>
@ -320,7 +291,6 @@
<string name="delete_all_history_prompt">Ten a certeza de querer eliminar todos os elementos do historial?</string>
<string name="title_last_played">Última reprodución</string>
<string name="title_most_played">Máis reproducido</string>
<string name="main_page_content">Contido da páxina principal</string>
<string name="blank_page_summary">Páxina en branco</string>
<string name="kiosk_page_summary">Páxina do «kiosk»</string>
@ -328,92 +298,71 @@
<string name="feed_page_summary">Páxina da fonte</string>
<string name="channel_page_summary">Páxina do canal</string>
<string name="select_a_channel">Seleccione un canal</string>
<string name="no_channel_subscribed_yet">Non subscribiu ningún canal</string>
<string name="no_channel_subscribed_yet">Non se subscribiu a ningunha canle aínda</string>
<string name="select_a_kiosk">Seleccione un «kiosk»</string>
<string name="export_complete_toast">Exportación completa</string>
<string name="import_complete_toast">Importación completada</string>
<string name="export_complete_toast">Exportado</string>
<string name="import_complete_toast">Importado</string>
<string name="no_valid_zip_file">Ficheiro ZIP inválido</string>
<string name="could_not_import_all_files">Aviso: non todos os ficheiros foron importados.</string>
<string name="override_current_data">Isto vai reescribir a súa configuración actual.</string>
<string name="import_settings">Desexa importar tamén as opcións?</string>
<string name="kiosk">Kiosk</string>
<string name="kiosk">Quiosco</string>
<string name="trending">Tendencias</string>
<string name="top_50">Top 50</string>
<string name="new_and_hot">Novo e popular</string>
<string name="play_queue_remove">Eliminar</string>
<string name="play_queue_stream_detail">Detalles</string>
<string name="play_queue_audio_settings">Opcións de audio</string>
<string name="hold_to_append">Manteña para colocar na cola</string>
<string name="enqueue_on_background">Colocar na cola de segundo plano</string>
<string name="enqueue_on_popup">Colocar na cola de popup</string>
<string name="hold_to_append">Manteña para colocalo na cola</string>
<string name="enqueue_on_background">Colocar na cola en segundo plano</string>
<string name="enqueue_on_popup">Executa nunha xanela emerxente</string>
<string name="start_here_on_main">Comezar a reprodución aquí</string>
<string name="start_here_on_background">Comezar aquí en segundo plano</string>
<string name="start_here_on_popup">Comezar aquí en popup</string>
<string name="start_here_on_background">Comezar a reproducir en segundo plano</string>
<string name="start_here_on_popup">Comezar reproducindo nunha xanela emerxente</string>
<string name="drawer_open">Abrir o menú</string>
<string name="drawer_close">Fechar o menú</string>
<string name="drawer_header_action_paceholder_text">Algo vai xurdir aquí en breve ;D</string>
<string name="preferred_open_action_settings_title">Acción «abrir» preferida</string>
<string name="preferred_open_action_settings_summary">Acción predeterminada ao abrir o contido — %s</string>
<string name="video_player">Reprodutor de vídeo</string>
<string name="background_player">Reprodutor en segundo plano</string>
<string name="popup_player">Reprodutor en popup</string>
<string name="always_ask_open_action">Preguntar sempre</string>
<string name="preferred_player_fetcher_notification_title">Obtendo información…</string>
<string name="preferred_player_fetcher_notification_message">Carregando o contido solicitado</string>
<string name="create_playlist">Crear unha nova lista de reprodución</string>
<string name="delete_playlist">Eliminar a lista de reprodución</string>
<string name="rename_playlist">Renomear a lista de reprodución</string>
<string name="playlist_name_input">Nome</string>
<string name="create_playlist">Nova lista de reprodución</string>
<string name="delete_playlist">Eliminar</string>
<string name="rename_playlist">Renomear</string>
<string name="name">Nome</string>
<string name="append_playlist">Engadir á lista de reprodución</string>
<string name="set_as_playlist_thumbnail">Estabelecer como miniatura da lista de reprodución</string>
<string name="bookmark_playlist">Gardar a lista de reprodución nos marcadores</string>
<string name="unbookmark_playlist">Eliminar o marcador</string>
<string name="delete_playlist_prompt">Desexa eliminar esta lista de reprodución?</string>
<string name="delete_playlist_prompt">Eliminar esta lista de reprodución\?</string>
<string name="playlist_creation_success">A lista de reprodución foi creada</string>
<string name="playlist_add_stream_success">O vídeo foi engadido á lista de reprodución</string>
<string name="playlist_thumbnail_change_success">A miniatura da lista de reprodución foi modificada</string>
<string name="playlist_delete_failure">Non foi posíbel eliminar a lista de reprodución</string>
<string name="playlist_add_stream_success">Lista de reprodución</string>
<string name="playlist_thumbnail_change_success">A miniatura da lista de reprodución foi modificada.</string>
<string name="playlist_delete_failure">Non foi posíbel eliminar a lista de reprodución.</string>
<string name="caption_none">Sen lenda</string>
<string name="resize_fit">Axustar</string>
<string name="resize_fill">Encher</string>
<string name="resize_zoom">Zoom</string>
<string name="caption_auto_generated">Xerado automaticamente</string>
<string name="caption_setting_title">Lenda</string>
<string name="caption_setting_description">Modificar a escala de texto da lenda e os estilos de segundo plano do reprodutor. Para ter efecto, é preciso reiniciar o aplicativo</string>
<string name="enable_leak_canary_title">Activar LeakCanary</string>
<string name="caption_setting_description">Modificar a escala de texto da lenda e os estilos de segundo plano do reprodutor. Para ter efecto, é preciso reiniciar o aplicativo.</string>
<string name="enable_leak_canary_summary">A monitorización de fugas de memoria pode facer que o aplicativo deixe de responder cando hai vertedura da pila</string>
<string name="enable_disposed_exceptions_title">Informar de erros de fóra do ciclo de vida</string>
<string name="enable_disposed_exceptions_title">Informar de erros fóra do ciclo de vida</string>
<string name="enable_disposed_exceptions_summary">Forzar a comunicación de excepcións Rx non entregábeis fóra do ciclo de vida do fragmento ou actividade após o descarte</string>
<string name="import_export_title">Importar/Exportar</string>
<string name="import_export_title">Importar/exportar</string>
<string name="import_title">Importar</string>
<string name="import_from">Importar de</string>
<string name="export_to">Exportar a</string>
<string name="import_ongoing">Importando…</string>
<string name="export_ongoing">Exportando…</string>
<string name="import_file_title">Importar un ficheiro</string>
<string name="previous_export">Exportación anterior</string>
<string name="subscriptions_import_unsuccessful">Non foi posíbel importar as subscricións</string>
<string name="subscriptions_export_unsuccessful">Non foi posíbel exportar as subscricións</string>
<string name="import_youtube_instructions">Pode importar as súas subscricións de YouTube descarregando o ficheiro de exportacións:
\n
\n1. Acceda ao URL %1$s
@ -426,30 +375,246 @@
\n3. Inicie a sesión cando lle for solicitado
\n4. Copie o URL de perfil a que foi redirixido.</string>
<string name="import_soundcloud_instructions_hint">oseuID, soundcloud.com/oseuid</string>
<string name="import_network_expensive_warning">Teña en conta que esta operación pode consumir moitos recursos de rede.
\n
\nDesexa continuar?</string>
<string name="playback_speed_control">Controis de velocidade da reprodución</string>
<string name="playback_tempo">Tempo</string>
<string name="playback_tempo">A tempo</string>
<string name="playback_pitch">Ton</string>
<string name="unhook_checkbox">Desvincular (pode causar distorsión)</string>
<string name="unhook_checkbox">Desactivar (pode causar distorsións)</string>
<string name="skip_silence_checkbox">Avanzar rápido durante os momentos de silencio</string>
<string name="playback_step">Paso</string>
<string name="playback_reset">Reiniciar</string>
<string name="start_accept_privacy_policy">Para cumprirmos co Regulamento Xeral Europeo de Protección de Datos (GDPR), chamamos a súa atención sobre a nova política de privacidade do NewPipe. Por favor, léao con coidado.
\nDebe aceptalo para nos enviar un relatorio de erro.</string>
<string name="accept">Aceptar</string>
<string name="decline">Recusar</string>
<string name="limit_data_usage_none_description">Sen límite</string>
<string name="limit_mobile_data_usage_title">Limitar a resolución ao usar datos móbiles</string>
<string name="minimize_on_exit_title">Minimizar ao mudar de aplicativo</string>
<string name="minimize_on_exit_summary">Acción ao mudar de aplicativo desde o reprodutor orixinal — %s</string>
<string name="minimize_on_exit_title">Minimizar cando se mude de aplicativo</string>
<string name="minimize_on_exit_summary">Acción ao cambiar a outro aplicativo do reprodutor de vídeo principal - %s</string>
<string name="minimize_on_exit_none_description">Ningunha</string>
<string name="minimize_on_exit_background_description">Minimizar ao reprodutor en segundo plano</string>
<string name="minimize_on_exit_popup_description">Minimizar o reprodutor popup</string>
</resources>
<string name="local">Limitado</string>
<string name="peertube_instance_add_https_only">Só son compatibles os URLs HTTPS</string>
<string name="volume_gesture_control_title">Control xestual do volume</string>
<string name="show_comments_summary">Desactíveo para agochar os comentarios</string>
<string name="enable_playback_resume_title">Retomar a reprodución</string>
<string name="playlist_page_summary">Páxina das listas de reprodución</string>
<string name="video_detail_by">Por %s</string>
<string name="channel_created_by">Creado por %s</string>
<string name="detail_sub_channel_thumbnail_view_description">Miniatura do avatar da canle</string>
<string name="content_not_supported">NewPipe aínda non é compatible con este contido.
\n
\nCon toda esperanza será compatible cunha futura versión.</string>
<string name="feed_use_dedicated_fetch_method_help_text">Cres que a carga de alimentación é demasiado lenta\? En caso afirmativo, intente habilitar a carga rápida (pode cambiala na configuración ou premendo o botón a continuación).
\n
\nNewPipe ofrece dúas estratexias de carga de fontes:
\n• Obtendo toda a canle de subscrición, que é lenta pero completa.
\n• Usar un punto final de servizo dedicado, rápido pero normalmente non completo.
\n
\nA diferenza entre ambos é que o rápido normalmente carece de información, como a duración ou o tipo do elemento (non pode distinguir entre os vídeos en directo e os normais) e pode devolver menos elementos.
\n
\nYouTube é un exemplo dun servizo que ofrece este método rápido coa súa fonte RSS.
\n
\nDe modo que a elección redúcese ao que prefires: velocidade ou información precisa.</string>
<string name="feed_use_dedicated_fetch_method_disable_button">Desactivar o modo rápido</string>
<string name="feed_use_dedicated_fetch_method_enable_button">Activa o modo rápido</string>
<string name="feed_use_dedicated_fetch_method_summary">Dispoñible nalgúns servizos, normalmente é moito máis rápido pero pode devolver unha cantidade limitada de elementos e moitas veces información incompleta (por exemplo, sen duración, tipo de elemento, sen estado en directo).</string>
<string name="feed_use_dedicated_fetch_method_title">Obtén unha transmisión dedicada cando estea dispoñible</string>
<string name="feed_update_threshold_option_always_update">Sempre actualizado</string>
<string name="feed_update_threshold_summary">Tempo despois da última actualización antes de que se subscriba unha subscrición - %s</string>
<string name="feed_update_threshold_title">Limiar da actualización das fontes</string>
<string name="settings_category_feed_title">Transmisión</string>
<string name="feed_group_show_only_ungrouped_subscriptions">Amosar só as subscricións non agrupadas</string>
<string name="feed_create_new_group_button_title">Novo</string>
<string name="feed_group_dialog_delete_message">Quere eliminar este grupo\?</string>
<string name="feed_group_dialog_empty_name">Nome do grupo vacío</string>
<plurals name="feed_group_dialog_selection_count">
<item quantity="one">%d seleccionado</item>
<item quantity="other">%d seleccionados</item>
</plurals>
<string name="feed_group_dialog_empty_selection">Non se seleccionou ningunha subscrición</string>
<string name="feed_group_dialog_select_subscriptions">Seleccionar subscricións</string>
<string name="feed_processing_message">Procesando a transmisión…</string>
<string name="feed_notification_loading">Cargando transmisión…</string>
<string name="feed_subscription_not_loaded_count">Non se cargou:% d</string>
<string name="feed_oldest_subscription_update">Actualizada a última información: %s</string>
<string name="feed_groups_header_title">Grupos da canle</string>
<plurals name="days">
<item quantity="one">%d día</item>
<item quantity="other">%d días</item>
</plurals>
<plurals name="hours">
<item quantity="one">%d hora</item>
<item quantity="other">%d horas</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d minuto</item>
<item quantity="other">%d minutos</item>
</plurals>
<plurals name="seconds">
<item quantity="one">%d segundo</item>
<item quantity="other">%d segundos</item>
</plurals>
<string name="new_seek_duration_toast">Debido ás restricións de ExoPlayer, a duración da busca estableceuse en% d segundos</string>
<string name="remove_watched_popup_yes_and_partially_watched_videos">Si, e visualizou parcialmente estes vídeos</string>
<string name="remove_watched_popup_warning">Eliminaranse os vídeos vistos antes e despois de seren engadidos á lista de reprodución.
\nEstás seguro\? Isto non se pode desfacer.!</string>
<string name="remove_watched_popup_title">Borrar todos os vídeos vistos\?</string>
<string name="remove_watched">Eliminar o visto</string>
<string name="systems_language">Sistema predeterminado</string>
<string name="app_language_title">Lingua do aplicativo</string>
<string name="choose_instance_prompt">Elixir unha instancia</string>
<string name="downloads_storage_use_saf_summary">O \'Framework Access Framework\' permite a descarga a unha tarxeta SD externa.
\nAlgúns dispositivos son incompatibles</string>
<string name="downloads_storage_use_saf_title">Usar SAF</string>
<string name="downloads_storage_ask_summary_kitkat">Preguntaralle onde gardar cada descarga.
\nEscolla SAF se o desexa descargar nunha tarxeta SD externa</string>
<string name="downloads_storage_ask_summary">Preguntaralle onde gardar cada descarga</string>
<string name="downloads_storage_ask_title">Pregunta onde se descarga</string>
<string name="pause_downloads">Parar as descagas</string>
<string name="start_downloads">Comezar as descargas</string>
<string name="enable_queue_limit_desc">Executarase unha descarga ao mesmo tempo</string>
<string name="enable_queue_limit">Limitar a cola de descarga</string>
<string name="close">Pechar</string>
<string name="pause_downloads_on_mobile_desc">Útil para cambiar aos datos móbiles, aínda que non se poden suspender algunhas descargas</string>
<string name="pause_downloads_on_mobile">Interrupción en redes contadas</string>
<string name="max_retry_desc">Número máximo de intentos antes de cancelar a descarga</string>
<string name="max_retry_msg">Reintento máximo</string>
<string name="stop">Parar</string>
<string name="deleted_downloads">Eliminar %1$d descargas</string>
<string name="delete_downloaded_files">Eliminar os ficheiros descargados</string>
<string name="confirm_prompt">Quere limpar o seu historial de descargas ou eliminar todos os ficheiros descargados\?</string>
<string name="clear_download_history">Borrar o historial de descargas</string>
<string name="error_download_resource_gone">Non se pode recuperar esta descarga</string>
<string name="error_timeout">O tempo de espera da conexión</string>
<string name="error_progress_lost">Perdeuse o progreso porque se eliminou o ficheiro</string>
<string name="error_insufficient_storage">Non queda espazo no dispositivo</string>
<string name="error_postprocessing_stopped">NewPipe pechouse mentres se traballaba no ficheiro</string>
<string name="error_postprocessing_failed">Fallou o post-procesamento</string>
<string name="error_http_not_found">Non se atopou</string>
<string name="error_http_unsupported_range">O servidor non acepta descargas múltiples con fíos e tente con @ string / msg_threads = 1</string>
<string name="error_http_no_content">O servidor non envía datos</string>
<string name="error_connect_host">Non se pode conectar ao servidor</string>
<string name="error_unknown_host">Non se puido atopar o servidor</string>
<string name="error_ssl_exception">Non se puido establecer unha conexión segura</string>
<string name="error_permission_denied">Permiso denegado polo sistema</string>
<string name="error_path_creation">Non se pode crear o cartafol de destino</string>
<string name="error_file_creation">Non se puido crear este ficheiro</string>
<string name="label_code">Código</string>
<string name="show_error">Amosar o erro</string>
<string name="download_already_pending">Hai unha descarga pendente con este nome</string>
<string name="download_already_running">Hai unha descarga en curso con este nome</string>
<string name="overwrite_failed">Non se pode sobreescribir este ficheiro</string>
<string name="overwrite_finished_warning">Xa existe un ficheiro descargado con este nome</string>
<string name="overwrite_unrelated_warning">Xa existe un ficheiro con este nome</string>
<string name="overwrite">Sobreescribir</string>
<string name="generate_unique_name">Xera un nome único</string>
<string name="download_finished_more">rematáronse %s descargas</string>
<string name="download_finished">Rematou a descarga</string>
<string name="download_failed">Fallou a descarga</string>
<string name="permission_denied">Acción denegada polo sistema</string>
<string name="enqueue">En cola</string>
<string name="recovering">recuperando</string>
<string name="post_processing">post-procesamento</string>
<string name="queued">en cola</string>
<string name="paused">pausado</string>
<string name="missions_header_pending">Pendente</string>
<string name="missions_header_finished">Rematado</string>
<string name="app_update_notification_content_text">Prema para descargar</string>
<string name="app_update_notification_content_title">A actualización de NewPipe está dispoñible!</string>
<string name="switch_view">Cambiar a vista</string>
<string name="auto">Automático</string>
<string name="enable_playback_state_lists_summary">Amosar indicadores de posición de reprodución en listas</string>
<string name="brightness_gesture_control_summary">Use xestos para controlar o brillo do reprodutor</string>
<string name="grid">Rede</string>
<string name="list">Lista</string>
<string name="list_view_mode">Modo de visualización da lista</string>
<string name="updates_setting_description">Amosar unha notificación para solicitar a actualización do aplicativo cando unha nova versión estea dispoñible</string>
<string name="updates_setting_title">Actualizacións</string>
<string name="show_original_time_ago_summary">Os textos orixinais dos servizos serán visibles nos elementos do fluxo</string>
<string name="show_original_time_ago_title">Amosar o tempo orixinal anterior nos elementos</string>
<string name="playlist_no_uploader">Xerado automaticamente (non se atopou ningún cargador)</string>
<string name="unmute">Non silenciar</string>
<string name="mute">Silenciar</string>
<string name="conferences">Conferencias</string>
<string name="most_liked">O que ten mais gústames</string>
<string name="recently_added">Engadiuse recentemente</string>
<string name="localization_changes_requires_app_restart">O idioma cambiará unha vez que se reinicie o aplicativo.</string>
<string name="error_unable_to_load_comments">Non se puideron cargar os comentarios</string>
<string name="no_playlist_bookmarked_yet">Aínda non hai marcadores nesta lista de reprodución</string>
<string name="select_a_playlist">Seleccionar unha lista de reprodución</string>
<string name="default_kiosk_page_summary">Quiosco predeterminado</string>
<string name="selection">Selección</string>
<string name="main_page_content_summary">Que lapelas se amosan na páxina principal</string>
<string name="recaptcha_done_button">Feito</string>
<string name="subtitle_activity_recaptcha">Prema \"Feito\" cando o resolva</string>
<string name="no_comments">Ningún comentario</string>
<string name="infinite_videos">∞ vídeos</string>
<string name="more_than_100_videos">+100 vídeos</string>
<plurals name="listening">
<item quantity="one">%s oínte</item>
<item quantity="other">%s oíntes</item>
</plurals>
<string name="no_one_listening">Ninguén está escoitando</string>
<plurals name="watching">
<item quantity="one">%s vendo</item>
<item quantity="other">%s véndoos</item>
</plurals>
<string name="no_one_watching">Ninguén está vendo</string>
<string name="subscribers_count_not_available">Non hai dispoñible conta de subscritores</string>
<string name="drawer_header_description">Cambiar o servizo actualmente seleccionado:</string>
<string name="error_report_open_github_notice">Verifique se xa existe un problema que fala do seu fallo. Ao crear billetes duplicados, gasta o tempo que nós poderiamos gastar en solucionar o erro real.</string>
<string name="error_report_open_issue_button_text">Informar dun erro en GitHub</string>
<string name="copy_for_github">Copia o informe con formato</string>
<string name="permission_display_over_apps">Dar permiso para mostrar noutros aplicativos</string>
<string name="restore_defaults_confirmation">Quere restaurar os valores predeterminados\?</string>
<string name="restore_defaults">Restaurar os valores predeterminados</string>
<string name="saved_tabs_invalid_json">Non se puideron ler as pestanas gardadas, polo que usar as predeterminadas</string>
<string name="missing_file">Ficheiro movido ou eliminado</string>
<string name="download_to_sdcard_error_message">Non é posible descargar na tarxeta SD externa. Restaurar a localización do cartafol de descarga\?</string>
<string name="download_to_sdcard_error_title">Non hai dispoñible almacenamento externo</string>
<string name="help">Axuda</string>
<string name="watch_history_states_deleted">Elimináronse as posicións de reprodución.</string>
<string name="delete_playback_states_alert">Eliminas todas as posicións de reprodución\?</string>
<string name="clear_playback_states_summary">Elimina todas as posicións de reprodución</string>
<string name="clear_playback_states_title">Elimina as posicións de reprodución</string>
<string name="app_update_notification_channel_description">Notificacións para a nova versión de NewPipe</string>
<string name="app_update_notification_channel_name">Notificación da actualización do aplicativo</string>
<string name="file_deleted">Ficheiro eliminado</string>
<string name="artists">Artistas</string>
<string name="albums">Álbumes</string>
<string name="songs">Cancións</string>
<string name="events">Eventos</string>
<string name="videos_string">Vídeos</string>
<string name="restricted_video">Este vídeo está restrinxido por idade.
\n
\nSe desexa visualizalo, habilite \"Contido restrinxido por idade\" nos axustes.</string>
<string name="youtube_restricted_mode_enabled_title">Modo restrinxido de YouTube</string>
<string name="settings_category_updates_title">Actualizacións</string>
<string name="peertube_instance_add_exists">A instancia xa existe</string>
<string name="peertube_instance_add_fail">Non se puido validar a instancia</string>
<string name="peertube_instance_add_help">Introduza o URL da instancia</string>
<string name="peertube_instance_add_title">Engadir instancia</string>
<string name="peertube_instance_url_help">Atopar as instancias que lle gustan en %s</string>
<string name="peertube_instance_url_summary">Selecciona as instancias favoritas de PeerTube</string>
<string name="peertube_instance_url_title">Instancias de PeerTube</string>
<string name="content_language_title">Idioma do contido predeterminado</string>
<string name="autoplay_title">Reprodución automática</string>
<string name="settings_category_clear_data_title">Eliminar datos</string>
<string name="enable_playback_state_lists_title">Posicións nas listas</string>
<string name="enable_playback_resume_summary">Restaurar a última posición de reprodución</string>
<string name="brightness_gesture_control_title">Control do xesto de brillo</string>
<string name="volume_gesture_control_summary">Use xestos para controlar o volume do reprodutor</string>
<string name="show_comments_title">Amosar comentarios</string>
<string name="seek_duration_title">Duración da busca rápida cara a adiante / cara atrás</string>
<string name="enable_lock_screen_video_thumbnail_summary">Na pantalla de bloqueo móstrase unha miniatura de vídeo cando se usa o reprodutor de fondo</string>
<string name="enable_lock_screen_video_thumbnail_title">Miniatura do vídeo de pantalla de bloqueo</string>
<string name="download_choose_new_path">Cambie os cartafoles de descarga para facer efecto</string>
<string name="tab_choose">Elixir lapela</string>
<string name="tab_new">Nova lapela</string>
<string name="unsubscribe">Darse de baixa</string>
<string name="search_showing_result_for">Amosando resultados para: %s</string>
</resources>

View File

@ -54,7 +54,7 @@
<string name="download_dialog_title">הורדה</string>
<string name="next_video_title">הבא</string>
<string name="show_next_and_similar_title">להציג סרטונים דומים ובאים בתור</string>
<string name="url_not_supported_toast">כתובת לא נתמכת</string>
<string name="unsupported_url">כתובת לא נתמכת</string>
<string name="content_language_title">שפת התוכן המועדפת</string>
<string name="settings_category_video_audio_title">סרטונים ושמע</string>
<string name="settings_category_popup_title">חלון צף</string>
@ -97,7 +97,7 @@
<string name="error_snackbar_action">דיווח</string>
<string name="what_device_headline">מידע:</string>
<string name="what_happened_headline">מה קרה:</string>
<string name="info_labels">מה:\\nבקשה:\\nשפת התוכן:\\nשירות:\\nשעון גריניץ׳:\\nחבילה:\\nגרסה:\\nגרסת מערכת ההפעלה:</string>
<string name="info_labels">מה:\\nבקשה:\\nשפת התוכן:\\nמדינת התוכן:\\nשפת היישומון:\\nשירות:\\nשעון גריניץ׳:\\nחבילה:\\nגרסה:\\nגרסת מערכת ההפעלה:</string>
<string name="subscribe_button_title">עריכת מינוי</string>
<string name="subscribed_button_title">נרשמת</string>
<string name="channel_unsubscribed">ביטול מינוי לערוץ</string>
@ -301,7 +301,7 @@
<string name="create_playlist">רשימת נגינה חדשה</string>
<string name="delete_playlist">מחיקה</string>
<string name="rename_playlist">שינוי שם</string>
<string name="playlist_name_input">שם</string>
<string name="name">שם</string>
<string name="append_playlist">הוספה לרשימת נגינה</string>
<string name="bookmark_playlist">הוספת רשימת נגינה לסימניות</string>
<string name="unbookmark_playlist">הסרת סימנייה</string>
@ -373,7 +373,6 @@
<string name="resize_fit">התאמה</string>
<string name="caption_setting_title">כתוביות</string>
<string name="caption_setting_description">שינוי גודל כותרת הנגן וסגנונות הרקע. נדרשת הפעלה מחדש כדי ששינויים אלה יכנסו לתוקף.</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="enable_leak_canary_summary">מעקב אחר זליגת זיכרון עשויה לגרום ליישומון להיות בלתי זמין בזמן העתקת תוכן הזיכרון לקובץ</string>
<string name="import_soundcloud_instructions_hint">המזהה שלך, soundcloud.com/המזהה שלך</string>
<string name="import_network_expensive_warning">נא לשים לב כי פעולה זו עשויה להעמיס על תקשורת הנתונים.
@ -581,7 +580,6 @@
<string name="feed_group_dialog_select_subscriptions">בחירת מינויים</string>
<string name="feed_group_dialog_empty_selection">לא נבחר מינוי</string>
<string name="feed_group_dialog_empty_name">שם הקבוצה ריק</string>
<string name="feed_group_dialog_name_input">שם</string>
<string name="feed_group_dialog_delete_message">למחוק את הקבוצה הזאת\?</string>
<string name="feed_create_new_group_button_title">חדשה</string>
<string name="settings_category_feed_title">הזנה</string>
@ -632,4 +630,11 @@
<string name="channel_created_by">נוצר ע״י %s</string>
<string name="detail_sub_channel_thumbnail_view_description">תמונה ממוזערת של הערוץ</string>
<string name="feed_group_show_only_ungrouped_subscriptions">להציג רק מינויים שאינם בקבוצות</string>
<string name="playlist_page_summary">עמוד רשימת נגינה</string>
<string name="no_playlist_bookmarked_yet">אין עדיין סימניות ברשימת הנגינה</string>
<string name="select_a_playlist">בחירת רשימת נגינה</string>
<string name="error_report_open_github_notice">נא לבדוק אם כבר קיים דיווח על הקריסה שלך. יצירת דיווחים כפולים גוזלת מאתנו זמן שיכולנו להשקיע בתיקון התקלה עצמה.</string>
<string name="error_report_open_issue_button_text">דיווח על שגיאה ב־GitHub</string>
<string name="copy_for_github">העתקת דוח מעוצב</string>
<string name="search_showing_result_for">מוצגות תוצאות עבור: %s</string>
</resources>

View File

@ -96,7 +96,7 @@
<string name="show_next_and_similar_title">\'अगला\' और \'पहले समान\' वीडियो दिखाए</string>
<string name="show_hold_to_append_title">\"जोड़ने के लिए पकड़ें रहे\" दिखाए</string>
<string name="show_hold_to_append_summary">जब बैकग्राउंड और पॉपअप बटन विडियो के विवरण पन्ने में दबाई जाए तो tip को दिखाए</string>
<string name="url_not_supported_toast">ये वाला URL इसमें नहीं चलेगा</string>
<string name="unsupported_url">ये वाला URL इसमें नहीं चलेगा</string>
<string name="content_language_title">डिफ़ॉल्ट विषय की भाषा</string>
<string name="settings_category_player_title">प्लेयर</string>
<string name="settings_category_player_behavior_title">चाल चलन</string>
@ -293,7 +293,7 @@
<string name="create_playlist">नई प्लेलिस्ट</string>
<string name="delete_playlist">हटाएं</string>
<string name="rename_playlist">नाम बदलें</string>
<string name="playlist_name_input">नाम</string>
<string name="name">नाम</string>
<string name="append_playlist">प्लेलिस्ट में जोड़ें</string>
<string name="set_as_playlist_thumbnail">प्लेलिस्ट थंबनेल के रूप में सेट करें</string>
<string name="bookmark_playlist">प्लेलिस्ट बुकमार्क करें</string>
@ -309,7 +309,6 @@
<string name="resize_zoom">ज़ूम करें</string>
<string name="settings_category_debug_title">डीबग करें</string>
<string name="caption_auto_generated">ऑटो-जनरेटेड</string>
<string name="enable_leak_canary_title">LeakCanary सक्षम करें</string>
<string name="enable_leak_canary_summary">हीप डंप करने के दौरान मेमोरी लीक मॉनिटरिंग ऐप को अनुत्तरदायी बना सकता है</string>
<string name="enable_disposed_exceptions_title">Out-of-Lifecycle त्रुटियों की रिपोर्ट करें</string>
<string name="download_thumbnail_title">छायाप्रारुप लोड करें</string>

View File

@ -68,7 +68,7 @@
<string name="download_dialog_title">Preuzmi</string>
<string name="next_video_title">Sljedeće</string>
<string name="show_next_and_similar_title">Prikaži \'Sljedeće\' i \'Slične\' videozapise</string>
<string name="url_not_supported_toast">URL nije podržan</string>
<string name="unsupported_url">URL nije podržan</string>
<string name="content_language_title">Zadani jezik sadržaja</string>
<string name="settings_category_video_audio_title">Video i zvuk</string>
<string name="settings_category_popup_title">Skočni prozor</string>
@ -258,7 +258,7 @@
<string name="create_playlist">Nova reprodukcijska lista</string>
<string name="delete_playlist">Izbriši</string>
<string name="rename_playlist">Preimenuj</string>
<string name="playlist_name_input">Ime liste</string>
<string name="name">Ime</string>
<string name="append_playlist">Dodaj na reprodukcijsku listu</string>
<string name="set_as_playlist_thumbnail">Postavi kao sliku na listu</string>
<string name="bookmark_playlist">Markirajte reprodukcijsku listu</string>
@ -273,7 +273,6 @@
<string name="resize_fill">Ispuniti</string>
<string name="resize_zoom">Povećaj</string>
<string name="caption_auto_generated">Auto generirano</string>
<string name="enable_leak_canary_title">LeakCanary</string>
<string name="enable_leak_canary_summary">Monitoring curenja memorije može uzrokovati greške u radu aplikacije prilikom odlaganje gomile</string>
<string name="enable_disposed_exceptions_title">Izvijestite o pogreškama izvan životnog ciklusa</string>
<string name="show_info">Prikaži informacije</string>
@ -503,11 +502,19 @@
<string name="unmute">Uključi</string>
<string name="help">Pomoć</string>
<string name="feed_notification_loading">Učitavanje feeda…</string>
<string name="feed_group_dialog_name_input">Ime</string>
<string name="feed_group_dialog_delete_message">Želite li izbrisati ovu grupu\?</string>
<string name="feed_create_new_group_button_title">Novi</string>
<string name="feed_update_threshold_option_always_update">Uvijek ažuriraj</string>
<string name="feed_use_dedicated_fetch_method_enable_button">Omogući brz način</string>
<string name="feed_use_dedicated_fetch_method_disable_button">Onemogući brz način</string>
<string name="error_insufficient_storage">Memorija uređaja je popunjena</string>
<string name="most_liked">Najomiljenije</string>
<string name="subtitle_activity_recaptcha">Pritisnite \"Gotovo\" kad riješeno</string>
<string name="recaptcha_done_button">Gotovo</string>
<string name="infinite_videos">∞ videozapisa</string>
<string name="more_than_100_videos">100+ videozapisa</string>
<string name="error_report_open_issue_button_text">Prijavite grešku na GitHub</string>
<string name="artists">Umjetnici</string>
<string name="albums">Albumi</string>
<string name="songs">Pjesme</string>
</resources>

View File

@ -26,7 +26,7 @@
<string name="default_audio_format_title">Alapértelmezett hang formátum</string>
<string name="download_dialog_title">Letöltés</string>
<string name="next_video_title">Következő</string>
<string name="url_not_supported_toast">Nem támogatott webcím</string>
<string name="unsupported_url">Nem támogatott webcím</string>
<string name="use_external_video_player_title">Külső videólejátszó használata</string>
<string name="use_external_audio_player_title">Külső hanglejátszó használata</string>
<string name="download_path_audio_dialog_title">Válaszd ki a hangfájlok letöltési helyét</string>
@ -105,7 +105,7 @@
<string name="add">Új küldetés</string>
<string name="channel_unsubscribed">Csatornáról leiratkozva</string>
<string name="subscription_change_failed">Nem sikerült megváltoztatni a feliratkozást</string>
<string name="subscription_update_failed">"Nem sikerült frissíteni a feliratkozást "</string>
<string name="subscription_update_failed">Nem sikerült frissíteni a feliratkozást</string>
<string name="tab_main">Főoldal</string>
<string name="tab_subscriptions">Feliratkozások</string>
<string name="tab_bookmarks">Könyvjelzőzött lejátszási listák</string>
@ -131,7 +131,7 @@
<string name="enable_search_history_title">Keresési előzmények</string>
<string name="enable_watch_history_title">Előzmények</string>
<string name="enable_watch_history_summary">Megnézett videók nyomon követése</string>
<string name="resume_on_audio_focus_gain_summary">"Lejátszás folytatása félbeszakítás után (pl.: telefonhívás) "</string>
<string name="resume_on_audio_focus_gain_summary">Lejátszás folytatása félbeszakítás után (pl.: telefonhívás)</string>
<string name="settings_category_player_title">Lejátszó</string>
<string name="settings_category_player_behavior_title">Működés</string>
<string name="settings_category_history_title">Előzmények és gyorsítótár</string>
@ -310,7 +310,7 @@
<string name="create_playlist">Új lejátszási lista létrehozása</string>
<string name="delete_playlist">Lejátszási lista törlése</string>
<string name="rename_playlist">Lejátszási lista átnevezése</string>
<string name="playlist_name_input">Név</string>
<string name="name">Név</string>
<string name="append_playlist">Lejátszási listához adás</string>
<string name="set_as_playlist_thumbnail">Beállítás lejátszási lista előképeként</string>
<string name="unbookmark_playlist">Könyvjelző törlése</string>
@ -326,7 +326,6 @@
<string name="caption_auto_generated">Automatikusan létrehozott</string>
<string name="caption_setting_title">Feliratok</string>
<string name="caption_setting_description">Feliratok méretének és hátterének stílusbeli módosítása. A módosítások életbelépésehez az alkalmazás újraindítása szükséges.</string>
<string name="enable_leak_canary_title">LeakCanary bekapcsolása</string>
<string name="import_export_title">Import/Export</string>
<string name="import_title">Import</string>
<string name="import_from">Importálás a következőből</string>
@ -387,4 +386,81 @@
<string name="enable_playback_resume_title">Lejátszás folytatása</string>
<string name="enable_lock_screen_video_thumbnail_summary">Megjeleníti a videó bélyegképét a képernyőzáron, amikor a háttér lejátszó van használva</string>
<string name="download_choose_new_path">Változtasd meg a letöltési helyet, hogy érvénybe lépjen</string>
<string name="app_update_notification_channel_description">Jelentés új NewPipe verzióról</string>
<string name="app_update_notification_channel_name">Alkalmazás-frissítés jelzése</string>
<string name="file_deleted">File törölve</string>
<string name="settings_category_updates_title">Frissítések</string>
<string name="show_hold_to_append_summary">Tipp mutatása háttér vagy felbukkanó gomb megnyomásakor a videó részletei oldalon</string>
<string name="autoplay_title">Automatikus lejátszás</string>
<string name="settings_category_clear_data_title">Adatok törlése</string>
<string name="enable_playback_state_lists_summary">Lejátszási pozíciók mutatása a listákban</string>
<string name="enable_playback_state_lists_title">Pozíciók a listákban</string>
<string name="player_gesture_controls_summary">Gesztusvezérlés használata hangerő és fényerő szabályzásra</string>
<string name="brightness_gesture_control_summary">Gesztusvezérlés használata fényerő szabályzásra</string>
<string name="brightness_gesture_control_title">Fényerő gesztus</string>
<string name="volume_gesture_control_summary">Gesztusvezérlés használata hangerő szabályzásra</string>
<string name="volume_gesture_control_title">Hangerő gesztus</string>
<string name="downloads_storage_ask_summary">A rendszer megkérdezi, hogy hova mentse el az egyes letöltéseket</string>
<string name="downloads_storage_ask_title">Kérdezze meg, hova töltse le</string>
<string name="pause_downloads">Letöltések szüneteltetése</string>
<string name="start_downloads">Letöltések indítása</string>
<string name="enable_queue_limit_desc">Egyszerre egy letöltés fog futni ugyanabban az időben</string>
<string name="enable_queue_limit">Korlátozza a letöltési sort</string>
<string name="close">Bezár</string>
<string name="pause_downloads_on_mobile_desc">Hasznos, amikor átvált a mobil adatokra, bár néhány letöltést nem lehet felfüggeszteni</string>
<string name="pause_downloads_on_mobile">Megszakítás a mért hálózatokon</string>
<string name="max_retry_desc">A letöltés megszakítása előtti kísérletek maximális száma</string>
<string name="max_retry_msg">Maximális próbálkozások</string>
<string name="stop">Állj</string>
<string name="deleted_downloads">%1$s letöltés törölve</string>
<string name="delete_downloaded_files">Letöltött fájlok törlése</string>
<string name="confirm_prompt">Törli a letöltési előzményeket, vagy törli az összes letöltött fájlt\?</string>
<string name="clear_download_history">Letöltési előzmények törlése</string>
<string name="error_download_resource_gone">A letöltést nem lehet visszaállítani</string>
<string name="error_timeout">Kapcsolat időtúllépés</string>
<string name="error_progress_lost">A folyamat elveszett, mert a fájlt törölték</string>
<string name="error_insufficient_storage">Nincs hely az eszközön</string>
<string name="error_postprocessing_stopped">NewPipe leállt a fájl feldolgozása közben</string>
<string name="error_postprocessing_failed">Utófeldolgozás sikertelen</string>
<string name="error_http_not_found">Nincs talalat</string>
<string name="error_http_unsupported_range">A szerver nem fogad többszálú letöltést, próbálkozzon újra @ string / msg_threads = 1</string>
<string name="error_http_no_content">A szerver nem küld adatokat</string>
<string name="error_connect_host">Nem lehet csatlakozni a szerverhez</string>
<string name="error_unknown_host">A szerver nem talalható</string>
<string name="error_ssl_exception">Nem sikerült biztonságos kapcsolatot létesíteni</string>
<string name="error_permission_denied">A rendszer megtagadta az engedélyt</string>
<string name="error_path_creation">A célmappa nem hozható létre</string>
<string name="error_file_creation">A fájlt nem lehet létrehozni</string>
<string name="label_code">Kód</string>
<string name="show_error">Hiba megjelenítése</string>
<string name="download_already_pending">Ezzel a névvel egy letötés már várakozás alatt áll</string>
<string name="download_already_running">Ezzel a névvel egy letöltés már folyamatban van</string>
<string name="overwrite_finished_warning">Az ilyen névvel letöltött fájl már létezik</string>
<string name="overwrite_unrelated_warning">Az ilyen névű fájl már létezik</string>
<string name="overwrite">Átír</string>
<string name="generate_unique_name">Generáljon egyedi nevet</string>
<string name="download_finished_more">%s letöltés kész</string>
<string name="download_finished">Letöltés kész</string>
<string name="download_failed">Letöltés sikertelen</string>
<string name="recovering">Helyrehozás</string>
<string name="post_processing">Utófeldolgozás</string>
<string name="queued">Sorban álló</string>
<string name="paused">Szünet</string>
<string name="missions_header_pending">Függőben lévő</string>
<string name="missions_header_finished">Befejezett</string>
<string name="app_update_notification_content_text">Kattints a letöltéshez</string>
<string name="app_update_notification_content_title">NewPipe frissítés elérhető!</string>
<string name="switch_view">Nézet váltás</string>
<string name="auto">Auto</string>
<string name="grid">Rács</string>
<string name="list">Lista</string>
<string name="list_view_mode">Lista nézet</string>
<string name="missing_file">File áthelyezve vagy törölve</string>
<string name="download_to_sdcard_error_message">Külső SD-kártyára mentés nem lehetséges. Visszaállítsuk a letöltési mappa helyét\?</string>
<string name="download_to_sdcard_error_title">Külső tárhely nem elérhető</string>
<string name="watch_history_states_deleted">Lejátszási pozíciók törölve.</string>
<string name="delete_playback_states_alert">Összes lejátszási pozíció törlése\?</string>
<string name="clear_playback_states_summary">Összes lejátszási pozíció törlése</string>
<string name="clear_playback_states_title">Lejátszási pozíciók törlése</string>
<string name="search_showing_result_for">Találatok a következőre: %s</string>
</resources>

View File

@ -1,4 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_bg_subtitle">Սեղմեք որոնման կոճակը որ սկսել</string>
<string name="search">Որոնել</string>
@ -18,8 +18,6 @@
<string name="finish">Այո</string>
<string name="delete">Ջնջել</string>
<string name="start">Սկսել</string>
<string name="detail_likes_img_view_description">Հավանում եմ</string>
<string name="detail_dislikes_img_view_description">Չեմ հավանում</string>
<string name="clear">Մաքրել</string>
@ -29,4 +27,32 @@
<string name="cancel">Վերացնել</string>
<string name="open_in_browser">Բացել բրաուզերում</string>
<string name="choose_browser">Ընտրեք բրաուզերը</string>
</resources>
<string name="download_path_audio_title">Ձայնային բեռնման պանակ</string>
<string name="download_path_dialog_title">Ընտրեք ներբեռնման թղթապանակը տեսաֆայլերի համար</string>
<string name="download_path_summary">Ներբեռնված տեսաֆայլերը պահվում են այստեղ</string>
<string name="download_path_title">Տեսանյութի ներբեռնման պանակ</string>
<string name="controls_add_to_playlist_title">Ավելացնել</string>
<string name="controls_popup_title">Թռուցիկ</string>
<string name="controls_background_title">Ետին պլան</string>
<string name="tab_choose">Ընտրեք ներդիր</string>
<string name="tab_new">Նոր էջանշան</string>
<string name="tab_bookmarks">Էջանշված երգացանկեր</string>
<string name="tab_subscriptions">Բաժանորդագրումները</string>
<string name="tab_main">Հիմնական</string>
<string name="show_info">Ցուցադրել տեղեկույթը</string>
<string name="subscription_update_failed">Հնարավոր չէ թարմացնել բաժանորդագրումը</string>
<string name="subscription_change_failed">Հնարավոր չէ փոխել Բաժանորդագրումը</string>
<string name="channel_unsubscribed">Չեղարկել բաժանորդագրման հեռացումը</string>
<string name="unsubscribe">Բաժանորդագրման հեռացու</string>
<string name="subscribe_button_title">Բաժանորդագրվել</string>
<string name="use_external_video_player_summary">Հառացնում է ձայնը որոշ լուծաչափերոկմ</string>
<string name="screen_rotation">Դիրք</string>
<string name="share_dialog_title">Կիսվել</string>
<string name="controls_download_desc">Բեռնել հոսքի նշքը</string>
<string name="open_in_popup_mode">Բացել լողացող պատուհանում</string>
<string name="no_player_found_toast">Նվագարկիչ չի գտնվել (դուք կարող եք լբեռնել VLC և դիտել)։</string>
<string name="no_player_found">Նվագարկիչ չի գտնվել, ցանկանո՞ւմ եք բեռնել VLC։</string>
<string name="use_external_audio_player_title">Օգտագործել արտաքին աուդիո նվագարկիչ</string>
<string name="use_external_video_player_title">Օգտագործել արտաքին դերակատար</string>
<string name="popup_mode_share_menu_title">Լողացող ռեժիմ NewPipe</string>
</resources>

View File

@ -66,7 +66,7 @@
<string name="next_video_title">Sequente</string>
<string name="autoplay_title">Reproduction automatic</string>
<string name="show_next_and_similar_title">Monstrar le videos sequente e simile</string>
<string name="url_not_supported_toast">URL non supportate</string>
<string name="unsupported_url">URL non supportate</string>
<string name="default_content_country_title">Pais predefinite del contentos</string>
<string name="service_title">Servicio</string>
<string name="content_language_title">Lingua predefinite del contento</string>

Some files were not shown because too many files have changed in this diff Show More