1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 08:30:44 +00:00

Merge pull request #7934 from TeamNewPipe/release/0.22.1

Release 0.22.1
This commit is contained in:
Stypox 2022-02-26 22:01:30 +01:00 committed by GitHub
commit 47f9ed08e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 599 additions and 271 deletions

View File

@ -4,7 +4,12 @@
module.exports = async ({github, context}) => { module.exports = async ({github, context}) => {
const IGNORE_KEY = '<!-- IGNORE IMAGE MINIFY -->'; const IGNORE_KEY = '<!-- IGNORE IMAGE MINIFY -->';
const IGNORE_ALT_NAME_END = 'ignoreImageMinify'; const IGNORE_ALT_NAME_END = 'ignoreImageMinify';
// Targeted maximum height
const IMG_MAX_HEIGHT_PX = 600; const IMG_MAX_HEIGHT_PX = 600;
// maximum width of GitHub issues/comments
const IMG_MAX_WIDTH_PX = 800;
// all images that have a lower aspect ratio (-> have a smaller width) than this will be minimized
const MIN_ASPECT_RATIO = IMG_MAX_WIDTH_PX / IMG_MAX_HEIGHT_PX
// Get the body of the image // Get the body of the image
let initialBody = null; let initialBody = null;
@ -39,6 +44,8 @@ module.exports = async ({github, context}) => {
// Require the probe lib for getting the image dimensions // Require the probe lib for getting the image dimensions
const probe = require('probe-image-size'); const probe = require('probe-image-size');
var wasMatchModified = false;
// Try to find and replace the images with minimized ones // Try to find and replace the images with minimized ones
let newBody = await replaceAsync(initialBody, REGEX_IMAGE_LOOKUP, async (match, g1, g2) => { let newBody = await replaceAsync(initialBody, REGEX_IMAGE_LOOKUP, async (match, g1, g2) => {
console.log(`Found match '${match}'`); console.log(`Found match '${match}'`);
@ -48,7 +55,7 @@ module.exports = async ({github, context}) => {
return match; return match;
} }
let shouldModifiy = false; let shouldModify = false;
try { try {
console.log(`Probing ${g2}`); console.log(`Probing ${g2}`);
let probeResult = await probe(g2); let probeResult = await probe(g2);
@ -58,15 +65,26 @@ module.exports = async ({github, context}) => {
if (probeResult.hUnits != 'px') { if (probeResult.hUnits != 'px') {
throw `Unexpected probeResult.hUnits (expected px but got ${probeResult.hUnits})`; throw `Unexpected probeResult.hUnits (expected px but got ${probeResult.hUnits})`;
} }
if (probeResult.height <= 0) {
throw `Unexpected probeResult.height (height is invalid: ${probeResult.height})`;
}
if (probeResult.wUnits != 'px') {
throw `Unexpected probeResult.wUnits (expected px but got ${probeResult.wUnits})`;
}
if (probeResult.width <= 0) {
throw `Unexpected probeResult.width (width is invalid: ${probeResult.width})`;
}
console.log(`Probing resulted in ${probeResult.width}x${probeResult.height}px`);
shouldModifiy = probeResult.height > IMG_MAX_HEIGHT_PX; shouldModify = probeResult.height > IMG_MAX_HEIGHT_PX && (probeResult.width / probeResult.height) < MIN_ASPECT_RATIO;
} catch(e) { } catch(e) {
console.log('Probing failed:', e); console.log('Probing failed:', e);
// Immediately abort // Immediately abort
return match; return match;
} }
if (shouldModifiy) { if (shouldModify) {
wasMatchModified = true;
console.log(`Modifying match '${match}'`); console.log(`Modifying match '${match}'`);
return `<img alt="${g1}" src="${g2}" height=${IMG_MAX_HEIGHT_PX} />`; return `<img alt="${g1}" src="${g2}" height=${IMG_MAX_HEIGHT_PX} />`;
} }
@ -75,6 +93,11 @@ module.exports = async ({github, context}) => {
return match; return match;
}); });
if (!wasMatchModified) {
console.log('Nothing was modified. Skipping update');
return;
}
// Update the corresponding element // Update the corresponding element
if (context.eventName == 'issue_comment') { if (context.eventName == 'issue_comment') {
console.log('Updating comment with id', context.payload.comment.id); console.log('Updating comment with id', context.payload.comment.id);

View File

@ -8,7 +8,7 @@ plugins {
} }
android { android {
compileSdk 30 compileSdk 31
buildToolsVersion '30.0.3' buildToolsVersion '30.0.3'
defaultConfig { defaultConfig {
@ -16,8 +16,8 @@ android {
resValue "string", "app_name", "NewPipe" resValue "string", "app_name", "NewPipe"
minSdk 19 minSdk 19
targetSdk 29 targetSdk 29
versionCode 983 versionCode 984
versionName "0.22.0" versionName "0.22.1"
multiDexEnabled true multiDexEnabled true
@ -260,7 +260,7 @@ dependencies {
implementation "com.nononsenseapps:filepicker:4.2.1" implementation "com.nononsenseapps:filepicker:4.2.1"
// Crash reporting // Crash reporting
implementation "ch.acra:acra-core:5.7.0" implementation "ch.acra:acra-core:5.8.4"
// Properly restarting // Properly restarting
implementation 'com.jakewharton:process-phoenix:2.1.2' implementation 'com.jakewharton:process-phoenix:2.1.2'

View File

@ -13,13 +13,8 @@ import androidx.preference.PreferenceManager;
import com.jakewharton.processphoenix.ProcessPhoenix; import com.jakewharton.processphoenix.ProcessPhoenix;
import org.acra.ACRA; import org.acra.ACRA;
import org.acra.config.ACRAConfigurationException;
import org.acra.config.CoreConfiguration;
import org.acra.config.CoreConfigurationBuilder; import org.acra.config.CoreConfigurationBuilder;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.ReCaptchaActivity;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.ktx.ExceptionUtils;
@ -210,16 +205,9 @@ public class App extends MultiDexApplication {
return; return;
} }
try { final CoreConfigurationBuilder acraConfig = new CoreConfigurationBuilder(this)
final CoreConfiguration acraConfig = new CoreConfigurationBuilder(this) .withBuildConfigClass(BuildConfig.class);
.setBuildConfigClass(BuildConfig.class)
.build();
ACRA.init(this, acraConfig); ACRA.init(this, acraConfig);
} catch (final ACRAConfigurationException exception) {
exception.printStackTrace();
ErrorUtil.openActivity(this, new ErrorInfo(exception,
UserAction.SOMETHING_ELSE, "Could not initialize ACRA crash report"));
}
} }
private void initNotificationChannels() { private void initNotificationChannels() {

View File

@ -1994,9 +1994,7 @@ public final class VideoDetailFragment
// Prevent jumping of the player on devices with cutout // Prevent jumping of the player on devices with cutout
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
activity.getWindow().getAttributes().layoutInDisplayCutoutMode = activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
isMultiWindowOrFullscreen() WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
: WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
} }
activity.getWindow().getDecorView().setSystemUiVisibility(0); activity.getWindow().getDecorView().setSystemUiVisibility(0);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
@ -2018,9 +2016,7 @@ public final class VideoDetailFragment
// Prevent jumping of the player on devices with cutout // Prevent jumping of the player on devices with cutout
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
activity.getWindow().getAttributes().layoutInDisplayCutoutMode = activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
isMultiWindowOrFullscreen() WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
: WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
} }
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@ -2037,7 +2033,7 @@ public final class VideoDetailFragment
activity.getWindow().getDecorView().setSystemUiVisibility(visibility); activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& isMultiWindowOrFullscreen()) { && (isInMultiWindow || (isPlayerAvailable() && player.isFullscreen()))) {
activity.getWindow().setStatusBarColor(Color.TRANSPARENT); activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
activity.getWindow().setNavigationBarColor(Color.TRANSPARENT); activity.getWindow().setNavigationBarColor(Color.TRANSPARENT);
} }
@ -2053,11 +2049,6 @@ public final class VideoDetailFragment
} }
} }
private boolean isMultiWindowOrFullscreen() {
return DeviceUtils.isInMultiWindow(activity)
|| (isPlayerAvailable() && player.isFullscreen());
}
private boolean playerIsNotStopped() { private boolean playerIsNotStopped() {
return isPlayerAvailable() && !player.isStopped(); return isPlayerAvailable() && !player.isStopped();
} }

View File

@ -17,10 +17,8 @@ import androidx.appcompat.app.ActionBar;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.PignateFooterBinding;
import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
@ -44,6 +42,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.function.Supplier;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
@ -79,11 +78,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
} }
} }
@Override
public void onDetach() {
super.onDetach();
}
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -220,14 +214,10 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Nullable @Nullable
protected ViewBinding getListHeader() { protected Supplier<View> getListHeaderSupplier() {
return null; return null;
} }
protected ViewBinding getListFooter() {
return PignateFooterBinding.inflate(activity.getLayoutInflater(), itemsList, false);
}
protected RecyclerView.LayoutManager getListLayoutManager() { protected RecyclerView.LayoutManager getListLayoutManager() {
return new SuperScrollLayoutManager(activity); return new SuperScrollLayoutManager(activity);
} }
@ -252,11 +242,10 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
infoListAdapter.setUseGridVariant(useGrid); infoListAdapter.setUseGridVariant(useGrid);
infoListAdapter.setFooter(getListFooter().getRoot());
final ViewBinding listHeader = getListHeader(); final Supplier<View> listHeaderSupplier = getListHeaderSupplier();
if (listHeader != null) { if (listHeaderSupplier != null) {
infoListAdapter.setHeader(listHeader.getRoot()); infoListAdapter.setHeaderSupplier(listHeaderSupplier);
} }
itemsList.setAdapter(infoListAdapter); itemsList.setAdapter(infoListAdapter);
@ -271,7 +260,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
@Override @Override
protected void initListeners() { protected void initListeners() {
super.initListeners(); super.initListeners();
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() { infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<>() {
@Override @Override
public void selected(final StreamInfoItem selectedItem) { public void selected(final StreamInfoItem selectedItem) {
onStreamSelected(selectedItem); onStreamSelected(selectedItem);
@ -315,20 +304,96 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
} }
}); });
infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture<CommentsInfoItem>() { infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture<>() {
@Override @Override
public void selected(final CommentsInfoItem selectedItem) { public void selected(final CommentsInfoItem selectedItem) {
onItemSelected(selectedItem); onItemSelected(selectedItem);
} }
}); });
// Ensure that there is always a scroll listener (e.g. when rotating the device)
useNormalItemListScrollListener();
}
/**
* Removes all listeners and adds the normal scroll listener to the {@link #itemsList}.
*/
protected void useNormalItemListScrollListener() {
if (DEBUG) {
Log.d(TAG, "useNormalItemListScrollListener called");
}
itemsList.clearOnScrollListeners(); itemsList.clearOnScrollListeners();
itemsList.addOnScrollListener(new OnScrollBelowItemsListener() { itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener());
}
/**
* Removes all listeners and adds the initial scroll listener to the {@link #itemsList}.
* <br/>
* Which tries to load more items when not enough are in the view (not scrollable)
* and more are available.
* <br/>
* Note: This method only works because "This callback will also be called if visible
* item range changes after a layout calculation. In that case, dx and dy will be 0."
* - which might be unexpected because no actual scrolling occurs...
* <br/>
* This listener will be replaced by DefaultItemListOnScrolledDownListener when
* <ul>
* <li>the view was actually scrolled</li>
* <li>the view is scrollable</li>
* <li>no more items can be loaded</li>
* </ul>
*/
protected void useInitialItemListLoadScrollListener() {
if (DEBUG) {
Log.d(TAG, "useInitialItemListLoadScrollListener called");
}
itemsList.clearOnScrollListeners();
itemsList.addOnScrollListener(new DefaultItemListOnScrolledDownListener() {
@Override
public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy != 0) {
log("Vertical scroll occurred");
useNormalItemListScrollListener();
return;
}
if (isLoading.get()) {
log("Still loading data -> Skipping");
return;
}
if (!hasMoreItems()) {
log("No more items to load");
useNormalItemListScrollListener();
return;
}
if (itemsList.canScrollVertically(1)
|| itemsList.canScrollVertically(-1)) {
log("View is scrollable");
useNormalItemListScrollListener();
return;
}
log("Loading more data");
loadMoreItems();
}
private void log(final String msg) {
if (DEBUG) {
Log.d(TAG, "initItemListLoadScrollListener - " + msg);
}
}
});
}
class DefaultItemListOnScrolledDownListener extends OnScrollBelowItemsListener {
@Override @Override
public void onScrolledDown(final RecyclerView recyclerView) { public void onScrolledDown(final RecyclerView recyclerView) {
onScrollToBottom(); onScrollToBottom();
} }
});
} }
private void onStreamSelected(final StreamInfoItem selectedItem) { private void onStreamSelected(final StreamInfoItem selectedItem) {
@ -418,6 +483,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
// Load and handle // Load and handle
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override
protected void startLoading(final boolean forceLoad) {
useInitialItemListLoadScrollListener();
super.startLoading(forceLoad);
}
protected abstract void loadMoreItems(); protected abstract void loadMoreItems();
protected abstract boolean hasMoreItems(); protected abstract boolean hasMoreItems();

View File

@ -65,7 +65,7 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
super.onResume(); super.onResume();
// Check if it was loading when the fragment was stopped/paused, // Check if it was loading when the fragment was stopped/paused,
if (wasLoading.getAndSet(false)) { if (wasLoading.getAndSet(false)) {
if (hasMoreItems() && infoListAdapter.getItemsList().size() > 0) { if (hasMoreItems() && !infoListAdapter.getItemsList().isEmpty()) {
loadMoreItems(); loadMoreItems();
} else { } else {
doInitialLoadLogic(); doInitialLoadLogic();
@ -105,6 +105,7 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
// Load and handle // Load and handle
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override
protected void doInitialLoadLogic() { protected void doInitialLoadLogic() {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "doInitialLoadLogic() called"); Log.d(TAG, "doInitialLoadLogic() called");
@ -158,6 +159,7 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
*/ */
protected abstract Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic(); protected abstract Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic();
@Override
protected void loadMoreItems() { protected void loadMoreItems() {
isLoading.set(true); isLoading.set(true);
@ -171,9 +173,9 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doFinally(this::allowDownwardFocusScroll) .doFinally(this::allowDownwardFocusScroll)
.subscribe((@NonNull ListExtractor.InfoItemsPage InfoItemsPage) -> { .subscribe(infoItemsPage -> {
isLoading.set(false); isLoading.set(false);
handleNextItems(InfoItemsPage); handleNextItems(infoItemsPage);
}, (@NonNull Throwable throwable) -> }, (@NonNull Throwable throwable) ->
dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable, dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable,
errorUserAction, "Loading more items: " + url, serviceId))); errorUserAction, "Loading more items: " + url, serviceId)));
@ -223,7 +225,7 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
setTitle(name); setTitle(name);
if (infoListAdapter.getItemsList().isEmpty()) { if (infoListAdapter.getItemsList().isEmpty()) {
if (result.getRelatedItems().size() > 0) { if (!result.getRelatedItems().isEmpty()) {
infoListAdapter.addInfoItemList(result.getRelatedItems()); infoListAdapter.addInfoItemList(result.getRelatedItems());
showListFooter(hasMoreItems()); showListFooter(hasMoreItems());
} else { } else {
@ -240,7 +242,7 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
final List<Throwable> errors = new ArrayList<>(result.getErrors()); final List<Throwable> errors = new ArrayList<>(result.getErrors());
// handling ContentNotSupportedException not to show the error but an appropriate string // handling ContentNotSupportedException not to show the error but an appropriate string
// so that crashes won't be sent uselessly and the user will understand what happened // so that crashes won't be sent uselessly and the user will understand what happened
errors.removeIf(throwable -> throwable instanceof ContentNotSupportedException); errors.removeIf(ContentNotSupportedException.class::isInstance);
if (!errors.isEmpty()) { if (!errors.isEmpty()) {
dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(),

View File

@ -1,5 +1,9 @@
package org.schabi.newpipe.fragments.list.channel; package org.schabi.newpipe.fragments.list.channel;
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
@ -17,7 +21,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.viewbinding.ViewBinding;
import com.jakewharton.rxbinding4.view.RxView; import com.jakewharton.rxbinding4.view.RxView;
@ -29,7 +32,6 @@ import org.schabi.newpipe.databinding.PlaylistControlBinding;
import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
@ -43,13 +45,14 @@ import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.util.PicassoHelper; import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observable;
@ -61,10 +64,6 @@ import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.schedulers.Schedulers;
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
implements View.OnClickListener { implements View.OnClickListener {
@ -145,12 +144,12 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
protected ViewBinding getListHeader() { protected Supplier<View> getListHeaderSupplier() {
headerBinding = ChannelHeaderBinding headerBinding = ChannelHeaderBinding
.inflate(activity.getLayoutInflater(), itemsList, false); .inflate(activity.getLayoutInflater(), itemsList, false);
playlistControlBinding = headerBinding.playlistControl; playlistControlBinding = headerBinding.playlistControl;
return headerBinding; return headerBinding::getRoot;
} }
@Override @Override
@ -183,13 +182,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
} }
} }
private void openRssFeed() {
final ChannelInfo info = currentInfo;
if (info != null) {
ShareUtils.openUrlInBrowser(requireContext(), info.getFeedUrl(), false);
}
}
@Override @Override
public boolean onOptionsItemSelected(final MenuItem item) { public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
@ -197,7 +189,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
NavigationHelper.openSettings(requireContext()); NavigationHelper.openSettings(requireContext());
break; break;
case R.id.menu_item_rss: case R.id.menu_item_rss:
openRssFeed(); if (currentInfo != null) {
ShareUtils.openUrlInBrowser(
requireContext(), currentInfo.getFeedUrl(), false);
}
break; break;
case R.id.menu_item_openInBrowser: case R.id.menu_item_openInBrowser:
if (currentInfo != null) { if (currentInfo != null) {
@ -516,12 +511,11 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
} }
private PlayQueue getPlayQueue(final int index) { private PlayQueue getPlayQueue(final int index) {
final List<StreamInfoItem> streamItems = new ArrayList<>(); final List<StreamInfoItem> streamItems = infoListAdapter.getItemsList().stream()
for (final InfoItem i : infoListAdapter.getItemsList()) { .filter(StreamInfoItem.class::isInstance)
if (i instanceof StreamInfoItem) { .map(StreamInfoItem.class::cast)
streamItems.add((StreamInfoItem) i); .collect(Collectors.toList());
}
}
return new ChannelPlayQueue(currentInfo.getServiceId(), currentInfo.getUrl(), return new ChannelPlayQueue(currentInfo.getServiceId(), currentInfo.getUrl(),
currentInfo.getNextPage(), streamItems, index); currentInfo.getNextPage(), streamItems, index);
} }

View File

@ -1,5 +1,9 @@
package org.schabi.newpipe.fragments.list.playlist; package org.schabi.newpipe.fragments.list.playlist;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
@ -15,7 +19,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
import androidx.viewbinding.ViewBinding;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription; import org.reactivestreams.Subscription;
@ -42,17 +45,18 @@ import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.StreamDialogEntry; import org.schabi.newpipe.util.StreamDialogEntry;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Flowable;
@ -60,10 +64,6 @@ import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.disposables.Disposable;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
private static final String PICASSO_PLAYLIST_TAG = "PICASSO_PLAYLIST_TAG"; private static final String PICASSO_PLAYLIST_TAG = "PICASSO_PLAYLIST_TAG";
@ -120,12 +120,12 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
protected ViewBinding getListHeader() { protected Supplier<View> getListHeaderSupplier() {
headerBinding = PlaylistHeaderBinding headerBinding = PlaylistHeaderBinding
.inflate(activity.getLayoutInflater(), itemsList, false); .inflate(activity.getLayoutInflater(), itemsList, false);
playlistControlBinding = headerBinding.playlistControl; playlistControlBinding = headerBinding.playlistControl;
return headerBinding; return headerBinding::getRoot;
} }
@Override @Override
@ -413,7 +413,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
} }
private Subscriber<List<PlaylistRemoteEntity>> getPlaylistBookmarkSubscriber() { private Subscriber<List<PlaylistRemoteEntity>> getPlaylistBookmarkSubscriber() {
return new Subscriber<List<PlaylistRemoteEntity>>() { return new Subscriber<>() {
@Override @Override
public void onSubscribe(final Subscription s) { public void onSubscribe(final Subscription s) {
if (bookmarkReactor != null) { if (bookmarkReactor != null) {

View File

@ -1,6 +1,5 @@
package org.schabi.newpipe.fragments.list.videos; package org.schabi.newpipe.fragments.list.videos;
import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -12,7 +11,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.viewbinding.ViewBinding;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding; import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding;
@ -24,14 +22,14 @@ import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.util.RelatedItemInfo; import org.schabi.newpipe.util.RelatedItemInfo;
import java.io.Serializable; import java.io.Serializable;
import java.util.function.Supplier;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo> public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
implements SharedPreferences.OnSharedPreferenceChangeListener { implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String INFO_KEY = "related_info_key"; private static final String INFO_KEY = "related_info_key";
private final CompositeDisposable disposables = new CompositeDisposable();
private RelatedItemInfo relatedItemInfo; private RelatedItemInfo relatedItemInfo;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -54,11 +52,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
// LifeCycle // LifeCycle
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
}
@Override @Override
public View onCreateView(@NonNull final LayoutInflater inflater, public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container, @Nullable final ViewGroup container,
@ -66,12 +59,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
return inflater.inflate(R.layout.fragment_related_items, container, false); return inflater.inflate(R.layout.fragment_related_items, container, false);
} }
@Override
public void onDestroy() {
super.onDestroy();
disposables.clear();
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
headerBinding = null; headerBinding = null;
@ -79,8 +66,11 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
} }
@Override @Override
protected ViewBinding getListHeader() { protected Supplier<View> getListHeaderSupplier() {
if (relatedItemInfo != null && relatedItemInfo.getRelatedItems() != null) { if (relatedItemInfo == null || relatedItemInfo.getRelatedItems() == null) {
return null;
}
headerBinding = RelatedItemsHeaderBinding headerBinding = RelatedItemsHeaderBinding
.inflate(activity.getLayoutInflater(), itemsList, false); .inflate(activity.getLayoutInflater(), itemsList, false);
@ -91,10 +81,8 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) ->
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() PreferenceManager.getDefaultSharedPreferences(requireContext()).edit()
.putBoolean(getString(R.string.auto_queue_key), b).apply()); .putBoolean(getString(R.string.auto_queue_key), b).apply());
return headerBinding;
} else { return headerBinding::getRoot;
return null;
}
} }
@Override @Override
@ -128,7 +116,6 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
} }
ViewUtils.slideUp(requireView(), 120, 96, 0.06f); ViewUtils.slideUp(requireView(), 120, 96, 0.06f);
disposables.clear();
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -137,11 +124,13 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
@Override @Override
public void setTitle(final String title) { public void setTitle(final String title) {
// Nothing to do - override parent
} }
@Override @Override
public void onCreateOptionsMenu(@NonNull final Menu menu, public void onCreateOptionsMenu(@NonNull final Menu menu,
@NonNull final MenuInflater inflater) { @NonNull final MenuInflater inflater) {
// Nothing to do - override parent
} }
private void setInitialData(final StreamInfo info) { private void setInitialData(final StreamInfo info) {
@ -169,11 +158,10 @@ public class RelatedItemsFragment extends BaseListInfoFragment<RelatedItemInfo>
@Override @Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
final String s) { final String s) {
final SharedPreferences pref =
PreferenceManager.getDefaultSharedPreferences(requireContext());
final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
if (headerBinding != null) { if (headerBinding != null) {
headerBinding.autoplaySwitch.setChecked(autoplay); headerBinding.autoplaySwitch.setChecked(
sharedPreferences.getBoolean(
getString(R.string.auto_queue_key), false));
} }
} }

View File

@ -2,6 +2,7 @@ package org.schabi.newpipe.info_list;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -10,7 +11,7 @@ import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.schabi.newpipe.database.stream.model.StreamStateEntity; import org.schabi.newpipe.databinding.PignateFooterBinding;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
@ -34,6 +35,7 @@ import org.schabi.newpipe.util.OnClickGesture;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
/* /*
* Created by Christian Schabesberger on 01.08.16. * Created by Christian Schabesberger on 01.08.16.
@ -74,18 +76,20 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private static final int MINI_COMMENT_HOLDER_TYPE = 0x400; private static final int MINI_COMMENT_HOLDER_TYPE = 0x400;
private static final int COMMENT_HOLDER_TYPE = 0x401; private static final int COMMENT_HOLDER_TYPE = 0x401;
private final LayoutInflater layoutInflater;
private final InfoItemBuilder infoItemBuilder; private final InfoItemBuilder infoItemBuilder;
private final ArrayList<InfoItem> infoItemList; private final List<InfoItem> infoItemList;
private final HistoryRecordManager recordManager; private final HistoryRecordManager recordManager;
private boolean useMiniVariant = false; private boolean useMiniVariant = false;
private boolean useGridVariant = false; private boolean useGridVariant = false;
private boolean showFooter = false; private boolean showFooter = false;
private View header = null;
private View footer = null; private Supplier<View> headerSupplier = null;
public InfoListAdapter(final Context context) { public InfoListAdapter(final Context context) {
this.recordManager = new HistoryRecordManager(context); layoutInflater = LayoutInflater.from(context);
recordManager = new HistoryRecordManager(context);
infoItemBuilder = new InfoItemBuilder(context); infoItemBuilder = new InfoItemBuilder(context);
infoItemList = new ArrayList<>(); infoItemList = new ArrayList<>();
} }
@ -129,12 +133,12 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", " Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", "
+ "infoItemList.size() = " + infoItemList.size() + ", " + "infoItemList.size() = " + infoItemList.size() + ", "
+ "header = " + header + ", footer = " + footer + ", " + "hasHeader = " + hasHeader() + ", "
+ "showFooter = " + showFooter); + "showFooter = " + showFooter);
} }
notifyItemRangeInserted(offsetStart, data.size()); notifyItemRangeInserted(offsetStart, data.size());
if (footer != null && showFooter) { if (showFooter) {
final int footerNow = sizeConsideringHeaderOffset(); final int footerNow = sizeConsideringHeaderOffset();
notifyItemMoved(offsetStart, footerNow); notifyItemMoved(offsetStart, footerNow);
@ -145,43 +149,6 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
} }
} }
public void setInfoItemList(final List<? extends InfoItem> data) {
infoItemList.clear();
infoItemList.addAll(data);
notifyDataSetChanged();
}
public void addInfoItem(@Nullable final InfoItem data) {
if (data == null) {
return;
}
if (DEBUG) {
Log.d(TAG, "addInfoItem() before > infoItemList.size() = "
+ infoItemList.size() + ", thread = " + Thread.currentThread());
}
final int positionInserted = sizeConsideringHeaderOffset();
infoItemList.add(data);
if (DEBUG) {
Log.d(TAG, "addInfoItem() after > position = " + positionInserted + ", "
+ "infoItemList.size() = " + infoItemList.size() + ", "
+ "header = " + header + ", footer = " + footer + ", "
+ "showFooter = " + showFooter);
}
notifyItemInserted(positionInserted);
if (footer != null && showFooter) {
final int footerNow = sizeConsideringHeaderOffset();
notifyItemMoved(positionInserted, footerNow);
if (DEBUG) {
Log.d(TAG, "addInfoItem() footer from " + positionInserted
+ " to " + footerNow);
}
}
}
public void clearStreamItemList() { public void clearStreamItemList() {
if (infoItemList.isEmpty()) { if (infoItemList.isEmpty()) {
return; return;
@ -190,16 +157,16 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void setHeader(final View header) { public void setHeaderSupplier(@Nullable final Supplier<View> headerSupplier) {
final boolean changed = header != this.header; final boolean changed = headerSupplier != this.headerSupplier;
this.header = header; this.headerSupplier = headerSupplier;
if (changed) { if (changed) {
notifyDataSetChanged(); notifyDataSetChanged();
} }
} }
public void setFooter(final View view) { protected boolean hasHeader() {
this.footer = view; return this.headerSupplier != null;
} }
public void showFooter(final boolean show) { public void showFooter(final boolean show) {
@ -219,48 +186,49 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
} }
private int sizeConsideringHeaderOffset() { private int sizeConsideringHeaderOffset() {
final int i = infoItemList.size() + (header != null ? 1 : 0); final int i = infoItemList.size() + (hasHeader() ? 1 : 0);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "sizeConsideringHeaderOffset() called → " + i); Log.d(TAG, "sizeConsideringHeaderOffset() called → " + i);
} }
return i; return i;
} }
public ArrayList<InfoItem> getItemsList() { public List<InfoItem> getItemsList() {
return infoItemList; return infoItemList;
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
int count = infoItemList.size(); int count = infoItemList.size();
if (header != null) { if (hasHeader()) {
count++; count++;
} }
if (footer != null && showFooter) { if (showFooter) {
count++; count++;
} }
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "getItemCount() called with: " Log.d(TAG, "getItemCount() called with: "
+ "count = " + count + ", infoItemList.size() = " + infoItemList.size() + ", " + "count = " + count + ", infoItemList.size() = " + infoItemList.size() + ", "
+ "header = " + header + ", footer = " + footer + ", " + "hasHeader = " + hasHeader() + ", "
+ "showFooter = " + showFooter); + "showFooter = " + showFooter);
} }
return count; return count;
} }
@SuppressWarnings("FinalParameters")
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "getItemViewType() called with: position = [" + position + "]"); Log.d(TAG, "getItemViewType() called with: position = [" + position + "]");
} }
if (header != null && position == 0) { if (hasHeader() && position == 0) {
return HEADER_TYPE; return HEADER_TYPE;
} else if (header != null) { } else if (hasHeader()) {
position--; position--;
} }
if (footer != null && position == infoItemList.size() && showFooter) { if (position == infoItemList.size() && showFooter) {
return FOOTER_TYPE; return FOOTER_TYPE;
} }
final InfoItem item = infoItemList.get(position); final InfoItem item = infoItemList.get(position);
@ -290,10 +258,16 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
+ "parent = [" + parent + "], type = [" + type + "]"); + "parent = [" + parent + "], type = [" + type + "]");
} }
switch (type) { switch (type) {
// #4475 and #3368
// Always create a new instance otherwise the same instance
// is sometimes reused which causes a crash
case HEADER_TYPE: case HEADER_TYPE:
return new HFHolder(header); return new HFHolder(headerSupplier.get());
case FOOTER_TYPE: case FOOTER_TYPE:
return new HFHolder(footer); return new HFHolder(PignateFooterBinding
.inflate(layoutInflater, parent, false)
.getRoot()
);
case MINI_STREAM_HOLDER_TYPE: case MINI_STREAM_HOLDER_TYPE:
return new StreamMiniInfoItemHolder(infoItemBuilder, parent); return new StreamMiniInfoItemHolder(infoItemBuilder, parent);
case STREAM_HOLDER_TYPE: case STREAM_HOLDER_TYPE:
@ -322,42 +296,17 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
} }
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder,
final int position) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onBindViewHolder() called with: " Log.d(TAG, "onBindViewHolder() called with: "
+ "holder = [" + holder.getClass().getSimpleName() + "], " + "holder = [" + holder.getClass().getSimpleName() + "], "
+ "position = [" + position + "]"); + "position = [" + position + "]");
} }
if (holder instanceof InfoItemHolder) { if (holder instanceof InfoItemHolder) {
// If header isn't null, offset the items by -1 ((InfoItemHolder) holder).updateFromItem(
if (header != null) { // If header is present, offset the items by -1
position--; infoItemList.get(hasHeader() ? position - 1 : position), recordManager);
}
((InfoItemHolder) holder).updateFromItem(infoItemList.get(position), recordManager);
} else if (holder instanceof HFHolder && position == 0 && header != null) {
((HFHolder) holder).view = header;
} else if (holder instanceof HFHolder && position == sizeConsideringHeaderOffset()
&& footer != null && showFooter) {
((HFHolder) holder).view = footer;
}
}
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position,
@NonNull final List<Object> payloads) {
if (!payloads.isEmpty() && holder instanceof InfoItemHolder) {
for (final Object payload : payloads) {
if (payload instanceof StreamStateEntity) {
((InfoItemHolder) holder).updateState(infoItemList
.get(header == null ? position : position - 1), recordManager);
} else if (payload instanceof Boolean) {
((InfoItemHolder) holder).updateState(infoItemList
.get(header == null ? position : position - 1), recordManager);
}
}
} else {
onBindViewHolder(holder, position);
} }
} }
@ -371,12 +320,9 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}; };
} }
public static class HFHolder extends RecyclerView.ViewHolder { static class HFHolder extends RecyclerView.ViewHolder {
public View view;
HFHolder(final View v) { HFHolder(final View v) {
super(v); super(v);
view = v;
} }
} }
} }

View File

@ -580,11 +580,17 @@ public final class Player implements
v.getPaddingTop(), v.getPaddingTop(),
v.getPaddingRight(), v.getPaddingRight(),
v.getPaddingBottom()); v.getPaddingBottom());
binding.fastSeekOverlay.setPadding(
v.getPaddingLeft(), // If we added padding to the fast seek overlay, too, it would not go under the
v.getPaddingTop(), // system ui. Instead we apply negative margins equal to the window insets of
v.getPaddingRight(), // the opposite side, so that the view covers all of the player (overflowing on
v.getPaddingBottom()); // some sides) and its center coincides with the center of other controls.
final RelativeLayout.LayoutParams fastSeekParams = (RelativeLayout.LayoutParams)
binding.fastSeekOverlay.getLayoutParams();
fastSeekParams.leftMargin = -v.getPaddingRight();
fastSeekParams.topMargin = -v.getPaddingBottom();
fastSeekParams.rightMargin = -v.getPaddingLeft();
fastSeekParams.bottomMargin = -v.getPaddingTop();
}); });
} }
@ -593,8 +599,7 @@ public final class Player implements
*/ */
private void setupPlayerSeekOverlay() { private void setupPlayerSeekOverlay() {
binding.fastSeekOverlay binding.fastSeekOverlay
.seekSecondsSupplier( .seekSecondsSupplier(() -> retrieveSeekDurationFromPreferences(this) / 1000)
() -> (int) (retrieveSeekDurationFromPreferences(this) / 1000.0f))
.performListener(new PlayerFastSeekOverlay.PerformListener() { .performListener(new PlayerFastSeekOverlay.PerformListener() {
@Override @Override
@ -607,6 +612,7 @@ public final class Player implements
animate(binding.fastSeekOverlay, false, SEEK_OVERLAY_DURATION); animate(binding.fastSeekOverlay, false, SEEK_OVERLAY_DURATION);
} }
@NonNull
@Override @Override
public FastSeekDirection getFastSeekDirection( public FastSeekDirection getFastSeekDirection(
@NonNull final DisplayPortion portion @NonNull final DisplayPortion portion

View File

@ -329,7 +329,7 @@
\nتوضح سياسة خصوصية NewPipe بالتفصيل البيانات التي يتم إرسالها وتخزينها عند إرسال تقرير الأعطال.</string> \nتوضح سياسة خصوصية NewPipe بالتفصيل البيانات التي يتم إرسالها وتخزينها عند إرسال تقرير الأعطال.</string>
<string name="read_privacy_policy">الإطلاع على سياسة الخصوصية</string> <string name="read_privacy_policy">الإطلاع على سياسة الخصوصية</string>
<string name="start_accept_privacy_policy">من أجل الامتثال للائحة الأوروبية العامة لحماية البيانات (GDPR)، فإننا نلفت انتباهك إلى سياسة خصوصية NewPipe. يرجى قراءتها بعناية. <string name="start_accept_privacy_policy">من أجل الامتثال للائحة الأوروبية العامة لحماية البيانات (GDPR)، فإننا نلفت انتباهك إلى سياسة خصوصية NewPipe. يرجى قراءتها بعناية.
\nو يجب عليك قبولها لإرسال تقرير الأخطاء إلينا.</string> \nويجب عليك قبولها لإرسال تقرير الأخطاء إلينا.</string>
<string name="accept">قبول</string> <string name="accept">قبول</string>
<string name="decline">رفض</string> <string name="decline">رفض</string>
<string name="limit_data_usage_none_description">لا حدود</string> <string name="limit_data_usage_none_description">لا حدود</string>
@ -637,7 +637,7 @@
<string name="georestricted_content">هذا المحتوى غير متوفر في بلدك.</string> <string name="georestricted_content">هذا المحتوى غير متوفر في بلدك.</string>
<string name="crash_the_app">اغلق التطبيق قسريا</string> <string name="crash_the_app">اغلق التطبيق قسريا</string>
<string name="restricted_video_no_stream">هذا الفيديو مقيد بالفئة العمرية. <string name="restricted_video_no_stream">هذا الفيديو مقيد بالفئة العمرية.
\nنظرا لسياسات YouTube الجديدة المتعلقة بمقاطع الفيديو المقيدة بالفئة العمرية، لا يمكن لـNewPipe الوصول إلى أي من مقاطع الفيديو الخاصة بها وبالتالي لا يمكن تشغيلها.</string> \nنظرًا لسياسات YouTube الجديدة المتعلقة بمقاطع الفيديو المقيدة بالفئة العمرية، لا يمكن لـNewPipe الوصول إلى أي من مقاطع الفيديو الخاصة بها وبالتالي لا يمكن تشغيلها.</string>
<string name="radio">إذاعة</string> <string name="radio">إذاعة</string>
<string name="featured">المميزة</string> <string name="featured">المميزة</string>
<string name="recaptcha_solve">حل</string> <string name="recaptcha_solve">حل</string>
@ -688,7 +688,7 @@
<string name="high_quality_larger">جودة عالية (أكبر)</string> <string name="high_quality_larger">جودة عالية (أكبر)</string>
<string name="seekbar_preview_thumbnail_title">معاينة مصغرة على شريط التمرير</string> <string name="seekbar_preview_thumbnail_title">معاينة مصغرة على شريط التمرير</string>
<string name="mark_as_watched">علّمه كفيديو تمت مشاهدته</string> <string name="mark_as_watched">علّمه كفيديو تمت مشاهدته</string>
<string name="detail_heart_img_view_description">أعجب بها منشئ المحتوى</string> <string name="detail_heart_img_view_description">أُعجب بها منشئ المحتوى</string>
<string name="loading_channel_details">جاري تحميل تفاصيل القناة…</string> <string name="loading_channel_details">جاري تحميل تفاصيل القناة…</string>
<string name="error_show_channel_details">خطأ في عرض تفاصيل القناة</string> <string name="error_show_channel_details">خطأ في عرض تفاصيل القناة</string>
<string name="show_image_indicators_summary">أظهر أشرطة ملونة لبيكاسو أعلى الصور تشير إلى مصدرها: الأحمر للشبكة والأزرق للقرص والأخضر للذاكرة</string> <string name="show_image_indicators_summary">أظهر أشرطة ملونة لبيكاسو أعلى الصور تشير إلى مصدرها: الأحمر للشبكة والأزرق للقرص والأخضر للذاكرة</string>

View File

@ -215,7 +215,7 @@
<string name="playback_speed_control">Controls de la velocitat de reproducció</string> <string name="playback_speed_control">Controls de la velocitat de reproducció</string>
<string name="playback_tempo">Tempo</string> <string name="playback_tempo">Tempo</string>
<string name="playback_pitch">To</string> <string name="playback_pitch">To</string>
<string name="main_bg_subtitle">Toca la lupa per començar.</string> <string name="main_bg_subtitle">Toca \"Cerca\" per començar.</string>
<string name="use_external_video_player_summary">Elimina l\'àudio en algunes resolucions</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="use_external_audio_player_title">Reproductor d\'àudio extern</string>
<string name="download_thumbnail_summary">Desactiveu-ho per no guardar 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="download_thumbnail_summary">Desactiveu-ho per no guardar 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>
@ -685,7 +685,7 @@
<string name="feed_new_items">Elements de feed nous</string> <string name="feed_new_items">Elements de feed nous</string>
<string name="feed_load_error_fast_unknown">El mode d\'alimentació ràpida no proporciona més informació sobre això.</string> <string name="feed_load_error_fast_unknown">El mode d\'alimentació ràpida no proporciona més informació sobre això.</string>
<string name="detail_pinned_comment_view_description">Comentari fixat</string> <string name="detail_pinned_comment_view_description">Comentari fixat</string>
<string name="show_crash_the_player_title">Mostrar \"tancar de forma violenta el reproductor\"</string> <string name="show_crash_the_player_title">Mostra \"Força el tancament del reproductor\"</string>
<string name="show_crash_the_player_summary">Mostra una opció de fallada quan s\'utilitza el reproductor</string> <string name="show_crash_the_player_summary">Mostra una opció de fallada quan s\'utilitza el reproductor</string>
<string name="show_image_indicators_summary">Mostra les cintes de color Picasso a la part superior de les imatges que indiquen la seva font: vermell per a la xarxa, blau per al disc i verd per a la memòria</string> <string name="show_image_indicators_summary">Mostra les cintes de color Picasso a la part superior de les imatges que indiquen la seva font: vermell per a la xarxa, blau per al disc i verd per a la memòria</string>
<string name="leak_canary_not_available">El LeakCanary no està disponible</string> <string name="leak_canary_not_available">El LeakCanary no està disponible</string>

View File

@ -71,7 +71,7 @@
<string name="title_activity_history">Ιστορικό</string> <string name="title_activity_history">Ιστορικό</string>
<string name="action_history">Ιστορικό</string> <string name="action_history">Ιστορικό</string>
<string name="show_info">Εμφάνιση πληροφοριών</string> <string name="show_info">Εμφάνιση πληροφοριών</string>
<string name="main_bg_subtitle">Πατήστε το μεγενθυτικό φακό για να ξεκινήσετε.</string> <string name="main_bg_subtitle">Πατήστε το μεγεθυντικό φακό για να ξεκινήσετε.</string>
<string name="no_player_found_toast">Δε βρέθηκε πρόγραμμα αναπαραγωγής ροής δεδομένων (μπορείτε να εγκαταστήσετε το VLC για να κάνετε αναπαραγωγή).</string> <string name="no_player_found_toast">Δε βρέθηκε πρόγραμμα αναπαραγωγής ροής δεδομένων (μπορείτε να εγκαταστήσετε το VLC για να κάνετε αναπαραγωγή).</string>
<string name="controls_download_desc">Λήψη του αρχείου ροής</string> <string name="controls_download_desc">Λήψη του αρχείου ροής</string>
<string name="use_external_video_player_summary">Αφαιρείται ο ήχος από κάποιες αναλύσεις</string> <string name="use_external_video_player_summary">Αφαιρείται ο ήχος από κάποιες αναλύσεις</string>

View File

@ -52,7 +52,7 @@
<string name="duration_live">En direct</string> <string name="duration_live">En direct</string>
<string name="could_not_load_thumbnails">Impossible de charger toutes les miniatures</string> <string name="could_not_load_thumbnails">Impossible de charger toutes les miniatures</string>
<string name="youtube_signature_deobfuscation_error">Impossible de déchiffrer la signature URL de la vidéo</string> <string name="youtube_signature_deobfuscation_error">Impossible de déchiffrer la signature URL de la vidéo</string>
<string name="sorry_string">Désolé, cela n\'aurait pas dû se produire.</string> <string name="sorry_string">Désolé, cela naurait pas dû se produire.</string>
<string name="error_report_button_text">Signaler cette erreur par courriel</string> <string name="error_report_button_text">Signaler cette erreur par courriel</string>
<string name="what_device_headline">Information :</string> <string name="what_device_headline">Information :</string>
<string name="what_happened_headline">Ce qui sest passé :</string> <string name="what_happened_headline">Ce qui sest passé :</string>
@ -73,7 +73,7 @@
<string name="checksum">Somme de contrôle</string> <string name="checksum">Somme de contrôle</string>
<string name="ok">OK</string> <string name="ok">OK</string>
<string name="msg_name">Nom du fichier</string> <string name="msg_name">Nom du fichier</string>
<string name="msg_threads">Nombre de connexions simultanées</string> <string name="msg_threads">Connexions simultanées</string>
<string name="msg_error">Erreur</string> <string name="msg_error">Erreur</string>
<string name="msg_running">NewPipe télécharge</string> <string name="msg_running">NewPipe télécharge</string>
<string name="msg_running_detail">Appuyer pour plus de détails</string> <string name="msg_running_detail">Appuyer pour plus de détails</string>
@ -668,8 +668,8 @@
<string name="main_page_content_swipe_remove">Balayez un élément pour le supprimer</string> <string name="main_page_content_swipe_remove">Balayez un élément pour le supprimer</string>
<string name="start_main_player_fullscreen_summary">Ne pas lancer les vidéos dans le mini lecteur mais directement en plein écran si la rotation automatique est verrouillée. Vous pouvez toujours accéder au mini-lecteur en quittant le mode plein écran</string> <string name="start_main_player_fullscreen_summary">Ne pas lancer les vidéos dans le mini lecteur mais directement en plein écran si la rotation automatique est verrouillée. Vous pouvez toujours accéder au mini-lecteur en quittant le mode plein écran</string>
<string name="start_main_player_fullscreen_title">Lancer le lecteur principal en plein écran</string> <string name="start_main_player_fullscreen_title">Lancer le lecteur principal en plein écran</string>
<string name="enqueue_next_stream">Mettre en file dattente la suivante</string> <string name="enqueue_next_stream">Ajouter à la liste de lecture</string>
<string name="enqueued_next">Placé comme suivant dans liste de lecture</string> <string name="enqueued_next">Suivant dans la liste de lecture</string>
<string name="processing_may_take_a_moment">Traitement en cours… Veuillez patienter</string> <string name="processing_may_take_a_moment">Traitement en cours… Veuillez patienter</string>
<string name="manual_update_description">Vérifier manuellement de nouvelles versions</string> <string name="manual_update_description">Vérifier manuellement de nouvelles versions</string>
<string name="checking_updates_toast">Vérification des mises à jour…</string> <string name="checking_updates_toast">Vérification des mises à jour…</string>
@ -685,7 +685,7 @@
<string name="create_error_notification">Créer une notification d\'erreur</string> <string name="create_error_notification">Créer une notification d\'erreur</string>
<string name="no_appropriate_file_manager_message_android_10">Aucun gestionnaire de fichiers approprié n\'a été trouvé pour cette action. <string name="no_appropriate_file_manager_message_android_10">Aucun gestionnaire de fichiers approprié n\'a été trouvé pour cette action.
\nVeuillez installer un gestionnaire de fichiers compatible avec l\'Infrastructure d\'accès au stockage.</string> \nVeuillez installer un gestionnaire de fichiers compatible avec l\'Infrastructure d\'accès au stockage.</string>
<string name="show_error_snackbar">Afficher une barre d\'erreur</string> <string name="show_error_snackbar">Afficher une barre derreur</string>
<string name="no_appropriate_file_manager_message">Aucun gestionnaire de fichier approprié n\'a été trouvé pour cette action. <string name="no_appropriate_file_manager_message">Aucun gestionnaire de fichier approprié n\'a été trouvé pour cette action.
\nVeuillez installer un gestionnaire de fichiers ou essayez de désactiver \'%s\' dans les paramètres de téléchargement.</string> \nVeuillez installer un gestionnaire de fichiers ou essayez de désactiver \'%s\' dans les paramètres de téléchargement.</string>
<string name="detail_pinned_comment_view_description">Commentaire épinglé</string> <string name="detail_pinned_comment_view_description">Commentaire épinglé</string>

View File

@ -661,7 +661,7 @@
<string name="manual_update_description">Periksa manual untuk versi baru</string> <string name="manual_update_description">Periksa manual untuk versi baru</string>
<string name="checking_updates_toast">Memeriksa pembaruan…</string> <string name="checking_updates_toast">Memeriksa pembaruan…</string>
<string name="feed_new_items">Item feed baru</string> <string name="feed_new_items">Item feed baru</string>
<string name="show_crash_the_player_title">Tampilkan \"hentikan pemain video\"</string> <string name="show_crash_the_player_title">Tampilkan \"Mogokkan pemutar\"</string>
<string name="show_crash_the_player_summary">Menampilkan opsi penghentian ketika menggunakan pemain video</string> <string name="show_crash_the_player_summary">Menampilkan opsi penghentian ketika menggunakan pemain video</string>
<string name="crash_the_player">Hentikan pemain video</string> <string name="crash_the_player">Hentikan pemain video</string>
<string name="error_report_channel_description">Notifikasi untuk melaporkan kegalatan</string> <string name="error_report_channel_description">Notifikasi untuk melaporkan kegalatan</string>

View File

@ -316,7 +316,7 @@
<string name="search_history_deleted">Usunięto historię wyszukiwania</string> <string name="search_history_deleted">Usunięto historię wyszukiwania</string>
<string name="one_item_deleted">Usunięto jedną pozycję.</string> <string name="one_item_deleted">Usunięto jedną pozycję.</string>
<string name="toast_no_player">Brak zainstalowanej aplikacji do odtworzenia tego pliku</string> <string name="toast_no_player">Brak zainstalowanej aplikacji do odtworzenia tego pliku</string>
<string name="app_license">NewPipe jest wolnym i bezpłatnym oprogramowaniem: Możesz używać, udostępniać i ulepszać je do woli. W szczególności możesz je redystrybuować i/lub modyfikować zgodnie z warunkami GNU General Public License opublikowanej przez Free Software Fundation w wersji 3 albo (według Twojego wyboru) jakąkolwiek późniejszą wersją.</string> <string name="app_license">NewPipe jest wolnym i bezpłatnym oprogramowaniem: Możesz używać, udostępniać i ulepszać je do woli. W szczególności możesz je redystrybuować i/lub modyfikować zgodnie z warunkami GNU General Public License, opublikowanej przez Free Software Fundation, w wersji 3 albo (według Twojego wyboru) jakiejkolwiek późniejszej wersji.</string>
<string name="import_settings">Czy chcesz zaimportować również ustawienia?</string> <string name="import_settings">Czy chcesz zaimportować również ustawienia?</string>
<string name="privacy_policy_title">Polityka prywatności NewPipe</string> <string name="privacy_policy_title">Polityka prywatności NewPipe</string>
<string name="privacy_policy_encouragement">Projekt NewPipe bardzo poważnie traktuje Twoją prywatność, dlatego aplikacja nie gromadzi żadnych danych bez Twojej zgody. <string name="privacy_policy_encouragement">Projekt NewPipe bardzo poważnie traktuje Twoją prywatność, dlatego aplikacja nie gromadzi żadnych danych bez Twojej zgody.
@ -377,11 +377,11 @@
<string name="overwrite_finished_warning">Pobrany plik o tej nazwie już istnieje</string> <string name="overwrite_finished_warning">Pobrany plik o tej nazwie już istnieje</string>
<string name="download_already_running">Trwa już pobieranie pliku o tej samej nazwie</string> <string name="download_already_running">Trwa już pobieranie pliku o tej samej nazwie</string>
<string name="show_error">Pokaż błąd</string> <string name="show_error">Pokaż błąd</string>
<string name="error_file_creation">Nie można utworzyć pliku</string> <string name="error_file_creation">Nie udało się utworzyć pliku</string>
<string name="error_path_creation">Nie można utworzyć folderu docelowego</string> <string name="error_path_creation">Nie udało się utworzyć folderu docelowego</string>
<string name="error_ssl_exception">Nie udało się nawiązać bezpiecznego połączenia</string> <string name="error_ssl_exception">Nie udało się nawiązać bezpiecznego połączenia</string>
<string name="error_unknown_host">Nie udało się znaleźć serwera</string> <string name="error_unknown_host">Nie udało się znaleźć serwera</string>
<string name="error_connect_host">Nie można połączyć się z serwerem</string> <string name="error_connect_host">Nie udało się połączyć z serwerem</string>
<string name="error_http_no_content">Serwer nie wysyła danych</string> <string name="error_http_no_content">Serwer nie wysyła danych</string>
<string name="error_http_unsupported_range">Serwer nie akceptuje pobierania wielowątkowego, spróbuj ponownie za pomocą @string/msg_threads = 1</string> <string name="error_http_unsupported_range">Serwer nie akceptuje pobierania wielowątkowego, spróbuj ponownie za pomocą @string/msg_threads = 1</string>
<string name="error_http_not_found">Nie znaleziono</string> <string name="error_http_not_found">Nie znaleziono</string>
@ -408,7 +408,7 @@
<string name="watch_history_states_deleted">Usunięto pozycje odtwarzania</string> <string name="watch_history_states_deleted">Usunięto pozycje odtwarzania</string>
<string name="missing_file">Plik usunięty albo przeniesiony</string> <string name="missing_file">Plik usunięty albo przeniesiony</string>
<string name="overwrite_unrelated_warning">Plik z tą nazwą już istnieje</string> <string name="overwrite_unrelated_warning">Plik z tą nazwą już istnieje</string>
<string name="overwrite_failed">nie można nadpisać pliku</string> <string name="overwrite_failed">Nie udało się nadpisać pliku</string>
<string name="download_already_pending">Plik o tej samej nazwie oczekuje na pobranie</string> <string name="download_already_pending">Plik o tej samej nazwie oczekuje na pobranie</string>
<string name="error_postprocessing_stopped">NewPipe został zamknięty podczas pracy nad plikiem</string> <string name="error_postprocessing_stopped">NewPipe został zamknięty podczas pracy nad plikiem</string>
<string name="error_insufficient_storage">Brak miejsca na urządzeniu</string> <string name="error_insufficient_storage">Brak miejsca na urządzeniu</string>
@ -457,7 +457,7 @@
<string name="most_liked">Najbardziej lubiane</string> <string name="most_liked">Najbardziej lubiane</string>
<string name="playlist_no_uploader">Wygenerowana automatycznie (nie znaleziono przesyłającego)</string> <string name="playlist_no_uploader">Wygenerowana automatycznie (nie znaleziono przesyłającego)</string>
<string name="recovering">odzyskiwanie</string> <string name="recovering">odzyskiwanie</string>
<string name="error_download_resource_gone">Nie można odzyskać tego pobrania</string> <string name="error_download_resource_gone">Nie udało się odzyskać tego pobrania</string>
<string name="choose_instance_prompt">Wybierz serwer</string> <string name="choose_instance_prompt">Wybierz serwer</string>
<string name="clear_download_history">Wyczyść historię pobierania</string> <string name="clear_download_history">Wyczyść historię pobierania</string>
<string name="delete_downloaded_files">Usuń pobrane pliki</string> <string name="delete_downloaded_files">Usuń pobrane pliki</string>
@ -481,7 +481,7 @@
\n• Pobieranie całego kanału subskrypcji, co jest powolne, ale kompletne. \n• Pobieranie całego kanału subskrypcji, co jest powolne, ale kompletne.
\n• Korzystanie z dedykowanego punktu końcowego usługi, co jest szybkie, ale zwykle nie jest kompletne. \n• Korzystanie z dedykowanego punktu końcowego usługi, co jest szybkie, ale zwykle nie jest kompletne.
\n \n
\nRóżnica między nimi polega na tym, że w szybkim zwykle brakuje pewnych informacji, takich jak czas trwania lub typ pozycji (nie można odróżnić wideo na żywo od zwykłych) i może zwrócić mniej pozycji. \nRóżnica między nimi polega na tym, że w szybkim zwykle brakuje pewnych informacji, takich jak czas trwania lub typ pozycji (nie można odróżnić wideo na żywo od zwykłych), i może zwrócić mniej pozycji.
\n \n
\nYouTube jest przykładem usługi, która oferuje tę szybką metodę z kanałem RSS. \nYouTube jest przykładem usługi, która oferuje tę szybką metodę z kanałem RSS.
\n \n
@ -639,7 +639,7 @@
<string name="metadata_tags">Tagi</string> <string name="metadata_tags">Tagi</string>
<string name="metadata_category">Kategoria</string> <string name="metadata_category">Kategoria</string>
<string name="open_website_license">Otwórz stronę</string> <string name="open_website_license">Otwórz stronę</string>
<string name="description_select_note">Teraz możesz zaznaczyć tekst wewnątrz opisu. Pamiętaj, że strona może migotać, a łącza mogą nie być klikalne w trybie zaznaczania.</string> <string name="description_select_note">Teraz możesz zaznaczyć tekst wewnątrz opisu. Pamiętaj, że w trybie zaznaczania strona może migotać i linki nie będą klikalne.</string>
<string name="service_provides_reason">%s podaje ten powód:</string> <string name="service_provides_reason">%s podaje ten powód:</string>
<string name="account_terminated">Konto zamknięte</string> <string name="account_terminated">Konto zamknięte</string>
<string name="feed_load_error_fast_unknown">Tryb szybki dla ładowania kanału nie dostarcza więcej informacji na ten temat.</string> <string name="feed_load_error_fast_unknown">Tryb szybki dla ładowania kanału nie dostarcza więcej informacji na ten temat.</string>

View File

@ -410,7 +410,7 @@
<string name="error_timeout">Tempo limite de conexão</string> <string name="error_timeout">Tempo limite de conexão</string>
<string name="confirm_prompt">Excluir todo o histórico de downloads ou excluir todos os arquivos baixados\?</string> <string name="confirm_prompt">Excluir todo o histórico de downloads ou excluir todos os arquivos baixados\?</string>
<string name="enable_queue_limit">Limitar fila de downloads</string> <string name="enable_queue_limit">Limitar fila de downloads</string>
<string name="enable_queue_limit_desc">Um download será feito por vez</string> <string name="enable_queue_limit_desc">Faz downloads um de cada vez</string>
<string name="start_downloads">Iniciar downloads</string> <string name="start_downloads">Iniciar downloads</string>
<string name="pause_downloads">Pausar downloads</string> <string name="pause_downloads">Pausar downloads</string>
<string name="downloads_storage_ask_title">Perguntar onde salvar o arquivo</string> <string name="downloads_storage_ask_title">Perguntar onde salvar o arquivo</string>

View File

@ -323,7 +323,7 @@
<string name="skip_silence_checkbox">Snabbspola vid frånvaro av ljud</string> <string name="skip_silence_checkbox">Snabbspola vid frånvaro av ljud</string>
<string name="playback_step">Steg</string> <string name="playback_step">Steg</string>
<string name="playback_reset">Återställ</string> <string name="playback_reset">Återställ</string>
<string name="start_accept_privacy_policy">För att uppfylla den Europeiska dataskyddsförordningen (GDPR) uppmärksammar vi er härmed NewPipes sekretesspolicy. Var god läs den noggrant. <string name="start_accept_privacy_policy">För att uppfylla den Europeiska dataskyddsförordningen (GDPR), uppmärksammar vi härmed NewPipes sekretesspolicy. Var god och läs den noggrant.
\nDu måste acceptera den för att kunna skicka felrapporten.</string> \nDu måste acceptera den för att kunna skicka felrapporten.</string>
<string name="accept">Acceptera</string> <string name="accept">Acceptera</string>
<string name="decline">Avböj</string> <string name="decline">Avböj</string>
@ -673,7 +673,7 @@
<string name="manual_update_description">Kolla manuellt efter nya versioner</string> <string name="manual_update_description">Kolla manuellt efter nya versioner</string>
<string name="checking_updates_toast">Söker efter uppdateringar…</string> <string name="checking_updates_toast">Söker efter uppdateringar…</string>
<string name="feed_new_items">Nya flödes objekt</string> <string name="feed_new_items">Nya flödes objekt</string>
<string name="show_crash_the_player_title">Visa \"krascha spelaren\"</string> <string name="show_crash_the_player_title">Visa \"Krascha spelaren\"</string>
<string name="crash_the_player">Krascha spelaren</string> <string name="crash_the_player">Krascha spelaren</string>
<string name="show_crash_the_player_summary">Visar ett kraschalternativ vid användning av spelaren</string> <string name="show_crash_the_player_summary">Visar ett kraschalternativ vid användning av spelaren</string>
<string name="error_report_channel_name">Felrapport-avisering</string> <string name="error_report_channel_name">Felrapport-avisering</string>

View File

@ -29,7 +29,7 @@
<string name="content_language_title">內容預設語言</string> <string name="content_language_title">內容預設語言</string>
<string name="settings_category_video_audio_title">影音</string> <string name="settings_category_video_audio_title">影音</string>
<string name="settings_category_appearance_title">外觀</string> <string name="settings_category_appearance_title">外觀</string>
<string name="background_player_playing_toast">背景播放</string> <string name="background_player_playing_toast">幕後播緊</string>
<string name="network_error">網絡問題</string> <string name="network_error">網絡問題</string>
<string name="detail_thumbnail_view_description">播放影片,片長:</string> <string name="detail_thumbnail_view_description">播放影片,片長:</string>
<string name="detail_uploader_thumbnail_view_description">上載者嘅頭像縮圖</string> <string name="detail_uploader_thumbnail_view_description">上載者嘅頭像縮圖</string>
@ -95,8 +95,8 @@
<string name="msg_popup_permission">畫中畫模式需要此權限</string> <string name="msg_popup_permission">畫中畫模式需要此權限</string>
<string name="recaptcha_request_toast">需完成 reCAPTCHA 挑戰</string> <string name="recaptcha_request_toast">需完成 reCAPTCHA 挑戰</string>
<string name="use_external_video_player_summary">某啲解像度可能會冇聲</string> <string name="use_external_video_player_summary">某啲解像度可能會冇聲</string>
<string name="controls_background_title">背景播放</string> <string name="controls_background_title">幕後播</string>
<string name="controls_popup_title">畫中畫播放</string> <string name="controls_popup_title">浮面播</string>
<string name="popup_remember_size_pos_title">記住畫中畫大小及位置</string> <string name="popup_remember_size_pos_title">記住畫中畫大小及位置</string>
<string name="popup_remember_size_pos_summary">記住最近設定的畫中畫大小及位置</string> <string name="popup_remember_size_pos_summary">記住最近設定的畫中畫大小及位置</string>
<string name="show_search_suggestions_title">搜尋建議</string> <string name="show_search_suggestions_title">搜尋建議</string>
@ -126,7 +126,7 @@
<string name="subscription_change_failed">轉唔到訂閱</string> <string name="subscription_change_failed">轉唔到訂閱</string>
<string name="subscription_update_failed">更新唔到訂閱</string> <string name="subscription_update_failed">更新唔到訂閱</string>
<string name="show_info">顯示資訊</string> <string name="show_info">顯示資訊</string>
<string name="tab_subscriptions">訂閱項目</string> <string name="tab_subscriptions">訂閱</string>
<string name="tab_bookmarks">已收藏播放清單</string> <string name="tab_bookmarks">已收藏播放清單</string>
<string name="use_inexact_seek_title">用粗略快轉</string> <string name="use_inexact_seek_title">用粗略快轉</string>
<string name="controls_add_to_playlist_title">加入去</string> <string name="controls_add_to_playlist_title">加入去</string>
@ -259,7 +259,7 @@
\n您係咪要繼續</string> \n您係咪要繼續</string>
<string name="never">幾時都唔使</string> <string name="never">幾時都唔使</string>
<string name="auto">自動</string> <string name="auto">自動</string>
<string name="low_quality_smaller">低畫質 (細)</string> <string name="low_quality_smaller">低畫質 (細格啲)</string>
<string name="dont_show">唔顯示</string> <string name="dont_show">唔顯示</string>
<string name="app_update_notification_content_text">撳一下去下載</string> <string name="app_update_notification_content_text">撳一下去下載</string>
<string name="no_views">無觀看次數</string> <string name="no_views">無觀看次數</string>
@ -309,7 +309,7 @@
<string name="no_videos">無影片</string> <string name="no_videos">無影片</string>
<string name="video_player">影片播放器</string> <string name="video_player">影片播放器</string>
<string name="wifi_only">僅限用 Wi-Fi 嘅時候</string> <string name="wifi_only">僅限用 Wi-Fi 嘅時候</string>
<string name="high_quality_larger">高畫質 (大)</string> <string name="high_quality_larger">高畫質 (大格啲)</string>
<string name="no_subscribers">無訂閱者</string> <string name="no_subscribers">無訂閱者</string>
<plurals name="subscribers"> <plurals name="subscribers">
<item quantity="other">%s 位訂閱者</item> <item quantity="other">%s 位訂閱者</item>
@ -334,7 +334,7 @@
<string name="title_most_played">最常播放</string> <string name="title_most_played">最常播放</string>
<string name="main_page_content">頭版內容</string> <string name="main_page_content">頭版內容</string>
<string name="main_page_content_summary">頭版要擺放邊啲分頁</string> <string name="main_page_content_summary">頭版要擺放邊啲分頁</string>
<string name="main_page_content_swipe_remove">走啲項目去剷走佢</string> <string name="main_page_content_swipe_remove">打橫掃走啲項目去剷走佢</string>
<string name="blank_page_summary">空白頁</string> <string name="blank_page_summary">空白頁</string>
<string name="localization_changes_requires_app_restart">重新開過個 app 之後就會轉新語言</string> <string name="localization_changes_requires_app_restart">重新開過個 app 之後就會轉新語言</string>
<string name="trending">時興</string> <string name="trending">時興</string>
@ -422,4 +422,113 @@
<string name="error_report_notification_toast">發生問題,詳見通知</string> <string name="error_report_notification_toast">發生問題,詳見通知</string>
<string name="detail_drag_description">拖拉執排位</string> <string name="detail_drag_description">拖拉執排位</string>
<string name="drawer_header_description">轉換服務,而家揀選咗嘅係:</string> <string name="drawer_header_description">轉換服務,而家揀選咗嘅係:</string>
<string name="list_view_mode">清單檢視模式</string>
<string name="error_progress_lost">做噉一半冇咗,因為個檔案刪除咗</string>
<string name="error_timeout">連線等太耐</string>
<string name="start_downloads">開始晒所有下載</string>
<string name="enable_queue_limit_desc">下載排隊逐個嚟,唔要一次過</string>
<string name="recent">近期</string>
<string name="account_terminated">帳戶已被終止</string>
<string name="metadata_language">語言</string>
<string name="metadata_support">支援</string>
<string name="overwrite_failed">覆寫唔到個檔案</string>
<string name="pause_downloads">暫停晒所有下載</string>
<string name="on"></string>
<string name="tablet_mode_title">平板電腦模式</string>
<string name="error_file_creation">個檔案建立唔到</string>
<string name="delete_item_search_history">您係咪想喺搜尋紀錄度刪除呢個項目?</string>
<string name="show_error">睇下咩問題</string>
<string name="download_already_running">有個整緊嘅下載撞名</string>
<string name="download_already_pending">有個等緊嘅下載撞名</string>
<string name="max_retry_desc">試盡幾多次就取消個下載算數</string>
<string name="show_thumbnail_summary">喺鎖定畫面背景同埋通知都擺放縮圖</string>
<string name="download_has_started">開始咗下載</string>
<string name="metadata_age_limit">年齡限制</string>
<string name="no_app_to_open_intent">您部機冇 app 開到佢</string>
<string name="youtube_music_premium_content">呢部影片係 YouTube Music Premium 會員限定,因此 NewPipe 未能串流或下載。</string>
<string name="night_theme_summary">揀選啱您心水嘅夜色主題 — %s</string>
<string name="paid_content">呢部內容係付費使用者限定,因此 NewPipe 未能串流或下載。</string>
<string name="select_night_theme_toast">您可以喺下面揀選啱您心水嘅夜色主題</string>
<string name="description_select_disable">停用揀選描述入面嘅文字</string>
<string name="grid">一格格</string>
<string name="list">一行行</string>
<string name="add_to_playlist">加入去播放清單</string>
<string name="create_playlist">新嘅播放清單</string>
<string name="show_channel_details">顯示頻道詳情</string>
<string name="error_http_not_found">唔見影</string>
<string name="select_a_playlist">揀選一個播放清單</string>
<string name="error_http_unsupported_range">伺服器唔接受多執行緒下載,請改用 @string/msg_threads = 1 再試下啦</string>
<string name="error_connect_host">連接唔到伺服器</string>
<string name="playlist_page_summary">播放清單頁面</string>
<string name="loading_channel_details">載入緊頻道詳情…</string>
<string name="hold_to_append">撳住就輪候</string>
<string name="error_path_creation">目的地資料夾建立唔到</string>
<string name="error_ssl_exception">建立唔到安全連線</string>
<string name="start_here_on_background">喺幕後開始播放</string>
<string name="error_insufficient_storage">部機冇晒位</string>
<string name="max_retry_msg">頂櫳重試幾多次</string>
<string name="pause_downloads_on_mobile_desc">若然有機會用到流動數據嘅時候,或者用得著,雖則有啲下載或者冇得暫停</string>
<string name="enable_queue_limit">輪住下載</string>
<string name="metadata_privacy_internal">內部</string>
<string name="metadata_privacy_private">私人</string>
<string name="stop">停止</string>
<string name="pause_downloads_on_mobile">按用量收費嘅網絡就閘住</string>
<string name="clear_download_history">抹走下載紀錄</string>
<string name="confirm_prompt">您想抹走您嘅下載紀錄,定係想剷走晒所有下載咗嘅檔案?</string>
<string name="delete_downloaded_files">剷走下載咗嘅檔案</string>
<plurals name="deleted_downloads_toast">
<item quantity="other">刪除咗 %1$s 個下載</item>
</plurals>
<string name="downloads_storage_ask_title">問我要下載去邊</string>
<string name="enqueue">排隊尾</string>
<string name="error_unknown_host">搵唔到伺服器</string>
<string name="error_http_no_content">伺服器冇傳回資料</string>
<string name="error_postprocessing_failed">後期處理失敗</string>
<string name="error_postprocessing_stopped">NewPipe 未搞掂個檔案就關閉咗</string>
<string name="error_download_resource_gone">呢個下載恢復唔到</string>
<string name="overwrite_finished_warning">同個下載咗嘅檔案撞名</string>
<string name="overwrite_unrelated_warning">同個現有嘅檔案撞名</string>
<plurals name="feed_group_dialog_selection_count">
<item quantity="other">揀選咗 %d 個</item>
</plurals>
<string name="feed_group_dialog_select_subscriptions">揀選訂閱</string>
<string name="feed_group_dialog_empty_selection">未有揀選訂閱</string>
<string name="show_thumbnail_title">顯示縮圖</string>
<string name="detail_sub_channel_thumbnail_view_description">頻道嘅頭像縮圖</string>
<string name="channel_created_by">由 %s 建立</string>
<string name="video_detail_by">出自 %s</string>
<string name="chapters">章節</string>
<string name="content_not_supported">呢部內容 NewPipe 仲未支援。
\n
\n希望未來會喺日後嘅版本支援啦。</string>
<string name="feed_toggle_show_played_items">顯示睇過嘅項目</string>
<string name="service_provides_reason">%s 話理由如下:</string>
<string name="no_appropriate_file_manager_message">搵唔到合適嘅檔案總管進行呢個動作。
\n請安裝一個檔案管理程式又或者試下喺下載設定度停用「%s」。</string>
<string name="no_appropriate_file_manager_message_android_10">搵唔到合適嘅檔案總管進行呢個動作。
\n請安裝一個與儲存空間存取框架兼容嘅檔案管理程式。</string>
<string name="georestricted_content">呢部內容限區,喺您所在國家未有提供。</string>
<string name="soundcloud_go_plus_content">呢首 (至少喺您所在國家而言) 係 SoundCloud Go+ 單曲,因此 NewPipe 未能串流或下載。</string>
<string name="private_content">呢部內容屬於私人,因此 NewPipe 未能串流或下載。</string>
<string name="auto_device_theme_title">自動 (跟返部機嘅主題色系)</string>
<string name="featured">精選</string>
<string name="radio">廣播</string>
<string name="description_select_note">您而家可以揀選喺描述入面嘅文字喇。不過要單聲,喺揀選模式嘅時候,個頁面可能眨眨下,同埋啲連結會撳唔到。</string>
<string name="description_select_enable">啟用揀選描述入面嘅文字</string>
<string name="metadata_licence">版權協議</string>
<string name="metadata_category">分類</string>
<string name="metadata_tags">標籤</string>
<string name="metadata_privacy">公開設定</string>
<string name="metadata_thumbnail_url">縮圖 URL</string>
<string name="metadata_privacy_public">公開</string>
<string name="metadata_privacy_unlisted">憑網址瀏覽</string>
<string name="detail_pinned_comment_view_description">置頂留言</string>
<string name="detail_heart_img_view_description">創作者畀咗心心</string>
<string name="open_website_license">開啟網站</string>
<string name="off"></string>
<string name="error_show_channel_details">顯示頻道詳情嘅時候有問題</string>
<string name="metadata_host">主機</string>
<string name="show_hold_to_append_summary">喺影片「詳情:」度撳一下「幕後播」或者「浮面播」個掣嘅時候顯示提示</string>
<string name="title_activity_history">紀錄</string>
<string name="action_history">紀錄</string>
</resources> </resources>

View File

@ -150,7 +150,8 @@
<string name="youtube_restricted_mode_enabled_title">Turn on YouTube\'s \"Restricted Mode\"</string> <string name="youtube_restricted_mode_enabled_title">Turn on YouTube\'s \"Restricted Mode\"</string>
<string name="youtube_restricted_mode_enabled_summary">YouTube provides a \"Restricted Mode\" which hides potentially mature content</string> <string name="youtube_restricted_mode_enabled_summary">YouTube provides a \"Restricted Mode\" which hides potentially mature content</string>
<string name="restricted_video">This video is age restricted.\n\nTurn on \"%1$s\" in the settings if you want to see it.</string> <string name="restricted_video">This video is age restricted.\n\nTurn on \"%1$s\" in the settings if you want to see it.</string>
<string name="restricted_video_no_stream">This video is age-restricted.\nDue to new YouTube policies with age-restricted videos, NewPipe cannot access any of its video streams and thus is unable to play it.</string> <string name="restricted_video_no_stream">This video is age-restricted.
\nDue to new YouTube policies with age-restricted videos, NewPipe cannot access any of its video streams and thus is unable to play it.</string>
<string name="duration_live">Live</string> <string name="duration_live">Live</string>
<string name="downloads">Downloads</string> <string name="downloads">Downloads</string>
<string name="downloads_title">Downloads</string> <string name="downloads_title">Downloads</string>
@ -488,7 +489,8 @@
<string name="playback_step">Step</string> <string name="playback_step">Step</string>
<string name="playback_reset">Reset</string> <string name="playback_reset">Reset</string>
<!-- GDPR dialog --> <!-- GDPR dialog -->
<string name="start_accept_privacy_policy">In order to comply with the European General Data Protection Regulation (GDPR), we herby draw your attention to NewPipe\'s privacy policy. Please read it carefully.\nYou must accept it to send us the bug report.</string> <string name="start_accept_privacy_policy">In order to comply with the European General Data Protection Regulation (GDPR), we hereby draw your attention to NewPipe\'s privacy policy. Please read it carefully.
\nYou must accept it to send us the bug report.</string>
<string name="accept">Accept</string> <string name="accept">Accept</string>
<string name="decline">Decline</string> <string name="decline">Decline</string>
<!-- Limit mobile data usage --> <!-- Limit mobile data usage -->
@ -557,11 +559,11 @@
<string name="download_already_pending">There is a pending download with this name</string> <string name="download_already_pending">There is a pending download with this name</string>
<!-- message dialog about download error --> <!-- message dialog about download error -->
<string name="show_error">Show error</string> <string name="show_error">Show error</string>
<string name="error_file_creation">The file can not be created</string> <string name="error_file_creation">The file cannot be created</string>
<string name="error_path_creation">The destination folder can not be created</string> <string name="error_path_creation">The destination folder cannot be created</string>
<string name="error_ssl_exception">Could not establish a secure connection</string> <string name="error_ssl_exception">Could not establish a secure connection</string>
<string name="error_unknown_host">Could not find the server</string> <string name="error_unknown_host">Could not find the server</string>
<string name="error_connect_host">Can not connect to the server</string> <string name="error_connect_host">Cannot connect to the server</string>
<string name="error_http_no_content">The server does not send data</string> <string name="error_http_no_content">The server does not send data</string>
<string name="error_http_unsupported_range">The server does not accept multi-threaded downloads, retry with @string/msg_threads = 1</string> <string name="error_http_unsupported_range">The server does not accept multi-threaded downloads, retry with @string/msg_threads = 1</string>
<string name="error_http_not_found">Not found</string> <string name="error_http_not_found">Not found</string>
@ -600,7 +602,8 @@
<string name="systems_language">System default</string> <string name="systems_language">System default</string>
<string name="remove_watched">Remove watched</string> <string name="remove_watched">Remove watched</string>
<string name="remove_watched_popup_title">Remove watched videos?</string> <string name="remove_watched_popup_title">Remove watched videos?</string>
<string name="remove_watched_popup_warning">Videos that have been watched before and after being added to the playlist will be removed.\nAre you sure? This cannot be undone!</string> <string name="remove_watched_popup_warning">Videos that have been watched before and after being added to the playlist will be removed.
\nAre you sure\? This cannot be undone!</string>
<string name="remove_watched_popup_yes_and_partially_watched_videos">Yes, and partially watched videos</string> <string name="remove_watched_popup_yes_and_partially_watched_videos">Yes, and partially watched videos</string>
<string name="new_seek_duration_toast">Due to ExoPlayer constraints the seek duration was set to %d seconds</string> <string name="new_seek_duration_toast">Due to ExoPlayer constraints the seek duration was set to %d seconds</string>
<!-- Time duration plurals --> <!-- Time duration plurals -->
@ -650,7 +653,17 @@
<string name="feed_use_dedicated_fetch_method_summary">Available in some services, it is usually much faster but may return a limited amount of items and often incomplete information (e.g. no duration, item type, no live status)</string> <string name="feed_use_dedicated_fetch_method_summary">Available in some services, it is usually much faster but may return a limited amount of items and often incomplete information (e.g. no duration, item type, no live status)</string>
<string name="feed_use_dedicated_fetch_method_enable_button">Enable fast mode</string> <string name="feed_use_dedicated_fetch_method_enable_button">Enable fast mode</string>
<string name="feed_use_dedicated_fetch_method_disable_button">Disable fast mode</string> <string name="feed_use_dedicated_fetch_method_disable_button">Disable fast mode</string>
<string name="feed_use_dedicated_fetch_method_help_text">Do you think feed loading is too slow? If so, try enabling fast loading (you can change it in settings or by pressing the button below).\n\nNewPipe offers two feed loading strategies:\n• Fetching the whole subscription channel, which is slow but complete.\n• Using a dedicated service endpoint, which is fast but usually not complete.\n\nThe difference between the two is that the fast one usually lacks some information, like the item\'s duration or type (can\'t distinguish between live videos and normal ones) and it may return less items.\n\nYouTube is an example of a service that offers this fast method with its RSS feed.\n\nSo the choice boils down to what you prefer: speed or precise information.</string> <string name="feed_use_dedicated_fetch_method_help_text">Do you think feed loading is too slow\? If so, try enabling fast loading (you can change it in settings or by pressing the button below).
\n
\nNewPipe offers two feed loading strategies:
\n• Fetching the whole subscription channel, which is slow but complete.
\n• Using a dedicated service endpoint, which is fast but usually not complete.
\n
\nThe difference between the two is that the fast one usually lacks some information, like the item\'s duration or type (can\'t distinguish between live videos and normal ones) and it may return less items.
\n
\nYouTube is an example of a service that offers this fast method with its RSS feed.
\n
\nSo the choice boils down to what you prefer: speed or precise information.</string>
<string name="feed_toggle_show_played_items">Show watched items</string> <string name="feed_toggle_show_played_items">Show watched items</string>
<string name="content_not_supported">This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version.</string> <string name="content_not_supported">This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version.</string>
<string name="detail_sub_channel_thumbnail_view_description">Channel\'s avatar thumbnail</string> <string name="detail_sub_channel_thumbnail_view_description">Channel\'s avatar thumbnail</string>

View File

@ -7,10 +7,6 @@
files="LocalItemListAdapter.java" files="LocalItemListAdapter.java"
lines="232,304"/> lines="232,304"/>
<suppress checks="FinalParameters"
files="InfoListAdapter.java"
lines="253,325"/>
<suppress checks="FinalParameters" <suppress checks="FinalParameters"
files="ListHelper.java" files="ListHelper.java"
lines="280,312"/> lines="280,312"/>

View File

@ -0,0 +1,8 @@
### Təkmilləşdirmələr
-İdxal/ixrac parametrləri #1333
-Həddindən artıq çəkilişi azaldın (performansın yaxşılaşdırılması) #1371
- Kiçik kod təkmilləşdirmələri #1375
- GDPR #1420 haqqında hər şeyi əlavə edin
### Sabit
- Yükləyici: .giga fayllarından bitməmiş endirmələrin yüklənməsi zamanı yaranan nasazlığı aradan qaldırın #1407

View File

@ -0,0 +1,7 @@
### Təkmilləşdirmələr
- Mobil datadan istifadə edərkən video keyfiyyətini məhdudlaşdırmaq imkanı əlavə edildi. #1339
- Sessiya üçün parlaqlığı yadda saxla #1442
- Daha zəif CPU-lar üçün yükləmə performansını yaxşılaşdırın #1431
- media sessiyası üçün (işləyən) dəstək əlavə edin #1433
### Düzəliş
- Yükləmələrin açılması zamanı qəzanı düzəldin (indi buraxılış quruluşları üçün əlçatandır) #1441

View File

@ -0,0 +1 @@
### Təkmilləşdirmələr - Burgermenyu ikona animasiyasını deaktiv edin #1486 - Yükləmələrin silinməsini geri qaytarın #1472 - Paylaşım menyusunda yükləmə seçimi #1498 - Uzun toxunma menyusuna paylaşma seçimi əlavə edildi #1454 - Çıxışda əsas oyunçunu minimuma endirin #1354 - Kitabxana versiyasının yenilənməsi və verilənlər bazası backup fix #1510 - ExoPlayer 2.8.2 Yeniləmə #1392 - Daha sürətli sürət dəyişikliyi üçün müxtəlif addım ölçülərini dəstəkləmək üçün oxutma sürətinə nəzarət.

View File

@ -0,0 +1 @@
# V0.13.7 Dəyişikliklər Qrupu ### Düzəltildi - v0.13.6-nın çeşidləmə filtri problemlərini düzəldin # v0.13.6-nın Dəyişikliklər Qrupu ###Təkmilləşdirmələr - Burgermenu ikona animasiyasını söndürün #1486.- ExoPlayer 2.8.2 Yeniləmə #1392 - Sürətin daha sürətli dəyişməsi üçün müxtəlif addım ölçülərini dəstəkləmək üçün oxutma sürətinə nəzarət dialoqu yenidən işlənmişdir. - Oynatma sətrinə nəzarətdə səssizliklər zamanı sürətli irəliləməyə keçid əlavə edildi.

View File

@ -0,0 +1,2 @@
# Behoden
- erneuter Hotfix des Entschlüsselungsfunktionsfehlers.

View File

@ -0,0 +1,14 @@
Neu
- Abonnementgruppen und sortierte Feeds
- Stummschalttaste in Playern
Verbessert
- Das Öffnen von music.youtube.com und media.ccc.de Links in NewPipe erlaubt
- Zwei Einstellungen wurden von "Erscheinungsbild" zu "Inhalt" verschoben
- Ausblenden der Suchoptionen 5, 15 und 25 Sekunden, wenn die ungenaue Suche aktiviert ist
Behoben
- einige WebM-Videos sind nicht suchbar
- Datenbank-Backup auf Android P
- Absturz beim Teilen einer heruntergeladenen Datei
- YouTube-Extraktionsprobleme, ...

View File

@ -0,0 +1 @@
• [YouTube] Fortsetzung des Kanals korrigiert

View File

@ -0,0 +1,6 @@
Absturz behoben, der beim Neuordnen von Kanalgruppen auftrat.
Das Abrufen weiterer YouTube-Videos aus Kanälen und Wiedergabelisten wurde behoben.
Das Abrufen von YouTube-Kommentaren wurde behoben.
Unterstützung für /watch/, /v/ und /w/ Unterpfade in YouTube URLs hinzugefügt.
Die Extraktion der SoundCloud-Client-ID und geografisch eingeschränkter Inhalte wurde korrigiert.
Nordkurdische Lokalisierung wurde hinzugefügt.

View File

@ -0,0 +1,4 @@
Hotfix
- Thumbnails und Titel werden im Grid-Layout nicht mehr abgeschnitten, da falsch berechnet wurde, wie viele Videos in eine Reihe passen
- Der Download-Dialog verschwindet nicht mehr, wenn er über das Freigabemenü geöffnet wird
- Aktualisierung einer Bibliothek im Zusammenhang mit dem Öffnen von externen Aktivitäten wie dem Storage Access Framework File Picker

View File

@ -0,0 +1,5 @@
Hotfix
- Behebung von Pufferproblemen, die durch YouTube-Drosselung verursacht werden
- Behebt die Extraktion von YouTube-Kommentaren und Abstürze bei deaktivierten Kommentaren
- Behebung der YouTube-Musiksuche
- Behebung von PeerTube-Livestreams

View File

@ -0,0 +1,2 @@
- Wiederaufnahme der Wiedergabe behoben
- Verbesserungen, um sicherzustellen, dass der Dienst, der bestimmt, ob NewPipe nach einer neuen Version suchen soll, nicht im Hintergrund gestartet wird

View File

@ -0,0 +1,13 @@
Neu
- Option "Zur Wiedergabeliste hinzufügen" zum Freigabemenü hinzugefügt
- Unterstützung für y2u.be und PeerTube Kurzlinks hinzugefügt
Verbessert
- Playback-Speed-Controls kompakter gemacht
- Feed hebt jetzt neue Elemente hervor
- "Beobachtete Artikel anzeigen" Option im Feed wird nun gespeichert
Behoben
- Extraktion von YouTube Likes und Dislikes behoben
- Automatische Wiederholung nach Rückkehr aus dem Hintergrund behoben
Und vieles mehr

View File

@ -0,0 +1,2 @@
Die MediaParser-Unterstützung wurde entfernt, um Probleme bei der Wiederaufnahme der Wiedergabe nach der Pufferung unter Android 11+ zu beheben.
Media Tunneling auf Philips QM16XE deaktiviert, um Wiedergabeprobleme zu beheben.

View File

@ -0,0 +1 @@
Behoben, dass YouTube keinen Stream abspielte.

View File

@ -0,0 +1,9 @@
Neue UI und Verhalten beim doppelten Antippen zum Suchen hinzufügen
Einstellungen durchsuchbar machen
Angepinnte Kommentare als solche markieren
Open-With-App Unterstützung für FSFEs PeerTube-Instanz hinzufügen
Hinzufügen von Fehlerbenachrichtigungen
Replay des ersten Warteschlangenelements bei Spielerwechsel korrigieren
Längeres Warten beim Puffern während Livestreams, bevor ein Fehler auftritt
Reihenfolge der lokalen Suchergebnisse korrigieren
Leere Felder in der Warteschlange beheben

View File

@ -0,0 +1,7 @@
Scrollen in Listen auf Tablets und TVs behoben
Zufällige Abstürze beim Scrollen durch Listen behoben
Das Overlay zum schnellen Vor- und Zurückspringen liegt jetzt unter der System-UI
Änderungen für bessere Unterstützung von Cutouts wurden rückgängig gemacht, da diese auf einigen Geräten die Oberfläche des Players verschiebt
compileSDK wurde von 30auf 31 erhöht
Die Bibliothek zum Melden von Fehlern wurde aktualisiert
Kleine Teile des Player Codes wurden umstrukturiert

View File

@ -0,0 +1,9 @@
Ajoute de nouveaux interface et comportement pour la recherche par double-touche
Rend les paramètres recherchables
Surligne les commentaires épinglés comme tels
Ajoute louverture avec app pour linstance PeerTube de la FSFE
Ajoute les notifications derreur
Corrige la relecture du premier item de la file lorsque le lecteur change
Attend plus longtemps lors des directs avant déchouer
Corrige lordre des résultats dune recherche locale
Corrige les champs ditem vides dans la liste de lecture

View File

@ -0,0 +1,6 @@
Charge assez ditems dans les listes pour remplir lécran et corriger le défilement sur les tablettes et les télés
Corrige les plantages lors du défilement des listes
Larc de superposition de lavance rapide est désormais sous linterface du système
Revient sur les modifications des découpes lors de la lecture en multi-fenêtres, qui causent la régression du lecteur mal positionné sur certains appareils
Met à jour compileSdk à la version 31
Met à jour la bibliothèque de rapports derreur

View File

@ -0,0 +1,7 @@
מספיק פריטים נטענים באופן ראשוני ברשימות כדי למלא את כל המסך ולתקן גלילה במחשבי לוח ובטלוויזיות
תוקנו קריסות אקראיות בעת גלילה ברשימות
קשת הקפיצה קדימה שמופיעה על הסרטון יורדת אל מתחת לשכבת מנשק המשתמש במערכת
שוחזרו השינויים לחיתוכים בעת נגינה במספר חלונות, מה שגרם לנסיגה בנגן שהוזז בחלק מהטלפונים
compileSdk שודרג מ־30 ל־31
ספריית דיווח השגיאות עודכנה
חלק מהקוד בנגן שופץ

View File

@ -0,0 +1,7 @@
Ora nelle liste vengono caricati abbastanza elementi per riempire l'intero schermo, evitando caricamenti infiniti su tablet e TV
Sistemati crash a caso nello scorrere le liste
L'arco dell'avanzamento rapido ora va anche sotto l'interfaccia di sistema
Annullati i cambiamenti alla gestione dei bordi dello schermo in modalità multi-finestra: il player era talvolta fuori posto
Incrementato compileSdk da 30 a 31
Aggiornata la libreria di segnalazione degli errori
Ristrutturato del codice nel player

View File

@ -0,0 +1,8 @@
### Verbeteringen
- Instellingen importeren/exporteren #1333
- Overdraw verminderen (prestatieverbetering) #1371
- Kleine code verbeteringen #1375
- Alles toevoegen over GDPR #1420
### Opgelost
- Downloader: Crash bij laden van onafgemaakte downloads van .giga bestanden verhelpen #1407

View File

@ -0,0 +1,9 @@
- nieuwe applicatie-workflow: video's afspelen op detailpagina, omlaag vegen om speler te minimaliseren
- MediaStyle meldingen: aanpasbare acties in meldingen, prestaties verbeterd
- basisgrootte aanpassen bij NewPipe als desktop-app
- dialoog met open opties tonen bij een niet-ondersteunde URL-toast
- Verbeterde zoeksuggestie-ervaring als externe niet kunnen worden opgehaald
- Verhoogde standaard videokwaliteit naar 720p60 (in-app speler) en 480p (pop-up speler)
- veel bug fixes en meer

View File

@ -0,0 +1,8 @@
• Installatie op externe opslag toestaan
• [Bandcamp] Ondersteuning voor het tonen van de eerste drie commentaren op een stream
• Toon alleen 'download is gestart' toast wanneer download is gestart
• Stel reCaptcha-cookie niet in wanneer er geen cookie is opgeslagen
• [Speler] Verbeter cache prestatie
• [Speler] Fix: speler die niet automatisch speelt
• Vorige Snackbalken verwijderen bij het verwijderen van downloads
• Hersteld dat objecten die niet in de lijst staan, verwijderd moeten worden

View File

@ -0,0 +1,11 @@
Nieuw
• Toon inhoud metadata (tags, categorieën, licentie, ...) onder de beschrijving
• "Toon kanaal details" optie in afspeellijsten op afstand (niet-lokaal)
• "Open in browser" optie toegevoegd aan lange-druk menu
Fix
• Rotatie crash op video detail pagina opgelost
• "Play with Kodi" knop in speler vraagt altijd om Kore te installeren
• Im- en export paden hersteld en verbeterd
• [YouTube] Aantal reacties als opgelost
En nog veel meer

View File

@ -0,0 +1,3 @@
Hotfix
- Vergroot buffer voor afspelen na rebuffer
- Crash op tablets en TV's verholpen bij het klikken op het play-queue icoon in de speler

View File

@ -0,0 +1,14 @@
Nieuw
Herken tijdstempels en hashtags in beschrijving
Handmatige tablet-modus instelling
Mogelijkheid afgespeelde items in een feed te verbergen
Verbeterd
Ondersteuning van Storage Access Framework
Foutafhandeling van niet-beschikbare en beëindigde kanalen
De Android share sheet voor Android 10+ gebruikers toont nu de titel van de inhoud
Invidious instanties. Ondersteuning voor Piped links
Bugfix
[YouTube] Leeftijdsbeperkte inhoud
Voorkom uitgelekt venster Uitzondering bij openen keuzedialoog

View File

@ -0,0 +1,7 @@
Ładowanie wystarczającej liczby początkowych pozycji na listach, aby wypełnić cały ekran, oraz naprawiono przewijanie na tabletach i telewizorach
Naprawiono losowe awarie podczas przewijania list
Przesunięto nakładkę szybkiego przewijania odtwarzacza pod interfejs systemu
Cofnięto zmiany przy odtwarzaniu w trybie wielu okien powodujące błędy na niektórych telefonach
Podwyższono compileSdk z 30 do 31
Zaktualizowano bibliotekę raportowania błędów
Refaktoryzacja kodu odtwarzacza

View File

@ -0,0 +1 @@
Fixade att YouTube inte spelade någon stream.

View File

@ -0,0 +1,7 @@
Ladda in tillräckligt många inledande objekt i listor för att fylla hela skärmen och för att åtgärda rullning på surfplattor och TV-apparater
Fixa slumpmässiga krascher vid rullning i listor
Lät spelarens snabbsöks funktion gå under systemets användargränssnitt
Tog bort ändringar av utskärningar när man spelar i flera fönster, vilket orsakade en felplacerad spelare på vissa telefoner
Öka compileSdk från 30 till 31
Uppdatera biblioteket för felrapportering
Refaktorisering av viss kod i spelaren

View File

@ -0,0 +1,7 @@
Завантаження достатньої кількості початкових елементів у списках, щоб заповнити весь екран і виправлено гортання на планшетах і телевізорах
Усунуто збої під час гортання списків
Виправлено проблему перемотування у програвачі
Скасовано зміни для пристроїв з вирізами під час програвання в багатовіконному режимі
compileSdk оновлено з 30 до 31 версії
Оновлено бібліотеку звітів про помилки
Рефакторинг коду програвача

View File

@ -0,0 +1,7 @@
在清單中載入足夠初始項目以填滿整個螢幕並藉以修正平板電腦和電視上的捲動
修正捲動清單時無常當機
播放器快速搜索的覆蓋弧形置於系統介面之下
還原多重視窗播放時的瀏海變更,免致部分手機出現播放器錯置迴歸
compileSdk 由 30 增至 31
更新錯誤報告程式庫
重構播放器中的部分程式碼

View File

@ -0,0 +1,7 @@
喺清單度載入足夠多初始項目去填滿成個螢幕並修正喺平板電腦同電視上面嘅捲動問題
修正捲動清單時偶發閃退
播放器快轉嘅覆蓋弧形擺喺系統介面後面
撤回多視窗播放時嘅 M 字額變動,以免部份手機出現播放器錯位嘅倒退
將 compileSdk 由 30 升至 31
更新問題報告程式庫
執整播放器部份程式碼