From 4effcad4366787d0f7ce121192e436b4c5176cd4 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Thu, 16 Apr 2026 15:56:46 +0800 Subject: [PATCH 01/11] libs: Update checkstyle to latest release and fix violations Javadoc comment at column 46 has parse error. Details: no viable alternative at input ' --- .../fragments/list/kiosk/KioskFragment.java | 29 ++++--------------- .../player/playqueue/PlayQueueAdapter.java | 29 ++++--------------- .../player/playqueue/PlayQueueItemHolder.java | 29 ++++--------------- .../settings/SelectChannelFragment.java | 26 ++++------------- .../settings/SelectFeedGroupFragment.java | 26 ++++------------- .../newpipe/settings/SelectKioskFragment.java | 26 ++++------------- .../org/schabi/newpipe/util/ListHelper.java | 2 +- .../org/schabi/newpipe/util/ZipHelper.java | 25 ++++------------ gradle/libs.versions.toml | 2 +- 9 files changed, 37 insertions(+), 157 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java index 6823e13d38b..d3427f8dba2 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2017-2024 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.fragments.list.kiosk; import android.os.Bundle; @@ -33,30 +38,6 @@ import io.reactivex.rxjava3.core.Single; -/** - * Created by Christian Schabesberger on 23.09.17. - *

- * Copyright (C) Christian Schabesberger 2017 - * KioskFragment.java is part of NewPipe. - *

- *

- * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- *

- * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- *

- * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - *

- */ - public class KioskFragment extends BaseListInfoFragment { @State String kioskId = ""; diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java index 2e19672e56d..b647e801dc2 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2016-2026 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.player.playqueue; import android.content.Context; @@ -22,30 +27,6 @@ import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; -/** - * Created by Christian Schabesberger on 01.08.16. - *

- * Copyright (C) Christian Schabesberger 2016 - * InfoListAdapter.java is part of NewPipe. - *

- *

- * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- *

- * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- *

- * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - *

- */ - public class PlayQueueAdapter extends RecyclerView.Adapter { private static final String TAG = PlayQueueAdapter.class.toString(); diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java index 1f2537baa50..23fc4bf1872 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2016-2021 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.player.playqueue; import android.view.View; @@ -8,30 +13,6 @@ import org.schabi.newpipe.R; -/** - * Created by Christian Schabesberger on 01.08.16. - *

- * Copyright (C) Christian Schabesberger 2016 - * StreamInfoItemHolder.java is part of NewPipe. - *

- *

- * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- *

- * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- *

- * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - *

- */ - public class PlayQueueItemHolder extends RecyclerView.ViewHolder { public final TextView itemVideoTitleView; public final TextView itemDurationView; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java index 25d6b3a0f6e..f1af8c66d48 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2017-2025 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.settings; import android.content.DialogInterface; @@ -30,27 +35,6 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.schedulers.Schedulers; -/** - * Created by Christian Schabesberger on 26.09.17. - * SelectChannelFragment.java is part of NewPipe. - *

- * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- *

- * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- *

- * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - *

- */ - public class SelectChannelFragment extends DialogFragment { private OnSelectedListener onSelectedListener = null; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java index c106f599809..79838bb3cbe 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2017-2025 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.settings; import android.content.DialogInterface; @@ -30,27 +35,6 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.schedulers.Schedulers; -/** - * Created by Christian Schabesberger on 26.09.17. - * SelectChannelFragment.java is part of NewPipe. - *

- * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- *

- * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- *

- * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - *

- */ - public class SelectFeedGroupFragment extends DialogFragment { private OnSelectedListener onSelectedListener = null; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java index 38339050665..d7e72821f06 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2017-2022 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.settings; import android.os.Bundle; @@ -25,27 +30,6 @@ import java.util.List; import java.util.Vector; -/** - * Created by Christian Schabesberger on 09.10.17. - * SelectKioskFragment.java is part of NewPipe. - *

- * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- *

- * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- *

- * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - *

- */ - public class SelectKioskFragment extends DialogFragment { private SelectKioskAdapter selectKioskAdapter = null; diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java index 409fcb30cbd..634302b96c3 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java @@ -58,7 +58,7 @@ public final class ListHelper { /** * List of supported YouTube Itag ids. * The original order is kept. - * @see {@link org.schabi.newpipe.extractor.services.youtube.ItagItem#ITAG_LIST} + * @see org.schabi.newpipe.extractor.services.youtube.ItagItem */ private static final List SUPPORTED_ITAG_IDS = List.of( diff --git a/app/src/main/java/org/schabi/newpipe/util/ZipHelper.java b/app/src/main/java/org/schabi/newpipe/util/ZipHelper.java index bccfc7f3874..fefd50e3c5c 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ZipHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ZipHelper.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2018-2026 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + package org.schabi.newpipe.util; import org.schabi.newpipe.streams.io.SharpInputStream; @@ -16,26 +21,6 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -/** - * Created by Christian Schabesberger on 28.01.18. - * Copyright 2018 Christian Schabesberger - * ZipHelper.java is part of NewPipe - *

- * License: GPL-3.0+ - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - public final class ZipHelper { @FunctionalInterface public interface InputStreamConsumer { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 15ae57bd0b1..ec723a4e50d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ autoservice-google = "1.1.1" autoservice-zacsweers = "1.2.0" bridge = "v2.0.2" cardview = "1.0.0" -checkstyle = "13.3.0" +checkstyle = "13.4.0" coil = "3.4.0" constraintlayout = "2.2.1" core = "1.17.0" # Newer versions require minSdk >= 23 From 2682f233a001f6f4d6a7a967b1658d0445907317 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Thu, 16 Apr 2026 16:13:59 +0800 Subject: [PATCH 02/11] libs: Update kotlinx.serialization to latest release Signed-off-by: Aayush Gupta --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec723a4e50d..a3c2541cbf5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ junit = "4.13.2" junit-ext = "1.3.0" kotlin = "2.3.20" kotlinx-coroutines-rx3 = "1.10.2" -kotlinx-serialization-json = "1.10.0" +kotlinx-serialization-json = "1.11.0" ksp = "2.3.6" ktlint = "1.8.0" leakcanary = "2.14" From 7a3d1d9b5febe08a28f65d09ec6ac6d259807732 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Thu, 16 Apr 2026 16:14:46 +0800 Subject: [PATCH 03/11] libs: Bump minSdk to API 23 androidx framework has bumped minSdk requirement to API 23. Most libs dependening upon the framework as a result require us to bump API level or keep using outdated versions. Signed-off-by: Aayush Gupta --- .github/workflows/ci.yml | 2 +- app/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb8fbc12a36..0fa1ca84ccb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: strategy: matrix: include: - - api-level: 21 + - api-level: 23 target: default arch: x86 - api-level: 35 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 063eeb95c26..724b131a263 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -42,7 +42,7 @@ configure { defaultConfig { applicationId = "org.schabi.newpipe" resValue("string", "app_name", "NewPipe") - minSdk = 21 + minSdk = 23 targetSdk = 35 versionCode = System.getProperty("versionCodeOverride")?.toInt() ?: 1010 From aa094bc78233a41b088532a9fa9288d867e96530 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Thu, 16 Apr 2026 16:22:20 +0800 Subject: [PATCH 04/11] libs: Bump all libs stuck due to minSdk to latest release Signed-off-by: Aayush Gupta --- gradle/libs.versions.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a3c2541cbf5..f1ef610ccea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ cardview = "1.0.0" checkstyle = "13.4.0" coil = "3.4.0" constraintlayout = "2.2.1" -core = "1.17.0" # Newer versions require minSdk >= 23 +core = "1.18.0" desugar = "2.1.5" documentfile = "1.1.0" exoplayer = "2.19.1" @@ -30,7 +30,7 @@ kotlinx-serialization-json = "1.11.0" ksp = "2.3.6" ktlint = "1.8.0" leakcanary = "2.14" -lifecycle = "2.9.4" # Newer versions require minSdk >= 23 +lifecycle = "2.10.0" localbroadcastmanager = "1.1.0" markwon = "4.6.2" material = "1.11.0" # TODO: update to newer version after bug is fixed. See https://github.com/TeamNewPipe/NewPipe/pull/13018 @@ -41,7 +41,7 @@ phoenix = "3.0.0" preference = "1.2.1" prettytime = "5.0.8.Final" recyclerview = "1.4.0" -room = "2.7.2" # Newer versions require minSdk >= 23 +room = "2.8.4" runner = "1.7.0" rxandroid = "3.0.2" rxbinding = "4.0.0" @@ -62,8 +62,8 @@ teamnewpipe-nanojson = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996" # to cause jitpack to regenerate the artifact. teamnewpipe-newpipe-extractor = "v0.26.1" viewpager2 = "1.1.0" -webkit = "1.14.0" # Newer versions require minSdk >= 23 -work = "2.10.5" # Newer versions require minSdk >= 23 +webkit = "1.15.0" +work = "2.11.2" [libraries] acra-core = { module = "ch.acra:acra-core", version.ref = "acra" } From c4a6bdd7d45f4d6941aef5dccd43e9b6d59b7d11 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Mon, 19 Jan 2026 14:39:33 +0800 Subject: [PATCH 05/11] Remove non-required API M version checks Signed-off-by: Aayush Gupta --- .../newpipe/player/ui/VideoPlayerUi.java | 24 +++++++------------ .../settings/VideoAudioSettingsFragment.java | 4 +--- .../schabi/newpipe/util/PermissionHelper.java | 5 +--- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index b68d3d94dbd..f020852cfa2 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -23,7 +23,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.net.Uri; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.Log; @@ -1584,19 +1583,15 @@ public void setupVideoSurfaceIfNeeded() { // make sure there is nothing left over from previous calls clearVideoSurface(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // >=API23 - surfaceHolderCallback = new SurfaceHolderCallback(context, player.getExoPlayer()); - binding.surfaceView.getHolder().addCallback(surfaceHolderCallback); + surfaceHolderCallback = new SurfaceHolderCallback(context, player.getExoPlayer()); + binding.surfaceView.getHolder().addCallback(surfaceHolderCallback); - // ensure player is using an unreleased surface, which the surfaceView might not be - // when starting playback on background or during player switching - if (binding.surfaceView.getHolder().getSurface().isValid()) { - // initially set the surface manually otherwise - // onRenderedFirstFrame() will not be called - player.getExoPlayer().setVideoSurfaceHolder(binding.surfaceView.getHolder()); - } - } else { - player.getExoPlayer().setVideoSurfaceView(binding.surfaceView); + // ensure player is using an unreleased surface, which the surfaceView might not be + // when starting playback on background or during player switching + if (binding.surfaceView.getHolder().getSurface().isValid()) { + // initially set the surface manually otherwise + // onRenderedFirstFrame() will not be called + player.getExoPlayer().setVideoSurfaceHolder(binding.surfaceView.getHolder()); } surfaceIsSetup = true; @@ -1604,8 +1599,7 @@ public void setupVideoSurfaceIfNeeded() { } private void clearVideoSurface() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M // >=API23 - && surfaceHolderCallback != null) { + if (surfaceHolderCallback != null) { binding.surfaceView.getHolder().removeCallback(surfaceHolderCallback); surfaceHolderCallback.release(); surfaceHolderCallback = null; diff --git a/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java index c5c4c480c2d..a4d52592f8a 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java @@ -2,7 +2,6 @@ import android.content.SharedPreferences; import android.content.res.Resources; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.format.DateUtils; @@ -33,8 +32,7 @@ public void onCreatePreferences(final Bundle savedInstanceState, final String ro // on M and above, if user chooses to minimise to popup player on exit // and the app doesn't have display over other apps permission, // show a snackbar to let the user give permission - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && getString(R.string.minimize_on_exit_key).equals(key)) { + if (getString(R.string.minimize_on_exit_key).equals(key)) { final String newSetting = sharedPreferences.getString(key, null); if (newSetting != null && newSetting.equals(getString(R.string.minimize_on_exit_popup_key)) diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java index 2defbdc5b24..77dc472f7d3 100644 --- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java @@ -12,7 +12,6 @@ import android.text.Html; import android.widget.Toast; -import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -116,7 +115,6 @@ public static boolean checkPostNotificationsPermission(final Activity activity, * @param context {@link Context} * @return {@link Settings#canDrawOverlays(Context)} **/ - @RequiresApi(api = Build.VERSION_CODES.M) public static boolean checkSystemAlertWindowPermission(final Context context) { if (!Settings.canDrawOverlays(context)) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { @@ -174,8 +172,7 @@ public static boolean checkSystemAlertWindowPermission(final Context context) { * @return whether the popup is enabled */ public static boolean isPopupEnabledElseAsk(final Context context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M - || checkSystemAlertWindowPermission(context)) { + if (checkSystemAlertWindowPermission(context)) { return true; } else { Toast.makeText(context, R.string.msg_popup_permission, Toast.LENGTH_LONG).show(); From a719b898a17074944d66f2e6a99ae5b307f35948 Mon Sep 17 00:00:00 2001 From: Shafqat Bhuiyan Date: Thu, 2 Apr 2026 04:46:45 +1100 Subject: [PATCH 06/11] Fix playback not working after player enters idle state On some phones (e.g. Oppo and Oneplus) the video player enters the STATE_IDLE 10 minutes after being paused. This causes the play button to stop working. This happens because once a player has become idle, we need to call prepare() before playback can happen again. But after I added prepare(), it would just skip to the end of the video. So now I'm executing the same code that happens when ERROR_CODE_UNSPECIFIED is done. This causes playback to resume normally. --- app/src/main/java/org/schabi/newpipe/player/Player.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 159ecbd6efc..e458b707e2d 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1752,6 +1752,13 @@ public void play() { } } + if (isStopped()) { + // Some phones suspend a paused player after 10 minutes. This causes the player to + // enter STATE_IDLE, causing playback to fail. So we try to recover from that here. + setRecovery(); + reloadPlayQueueManager(); + } + simpleExoPlayer.play(); saveStreamProgressState(); } From bdebc926a81290db315afa109af87d47e2109b68 Mon Sep 17 00:00:00 2001 From: tobigr Date: Mon, 20 Apr 2026 15:35:08 +0200 Subject: [PATCH 07/11] Update extractor --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f1ef610ccea..9ca4443d695 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -60,7 +60,7 @@ teamnewpipe-nanojson = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996" # the corresponding commit hash, since JitPack sometimes deletes artifacts. # If there’s already a git hash, just add more of it to the end (or remove a letter) # to cause jitpack to regenerate the artifact. -teamnewpipe-newpipe-extractor = "v0.26.1" +teamnewpipe-newpipe-extractor = "1512cf3222b0c5d87a249e6ac231b98090c42623" viewpager2 = "1.1.0" webkit = "1.15.0" work = "2.11.2" From ec81b6bb624fd8b98040fe90022f23c6b799f5ac Mon Sep 17 00:00:00 2001 From: tobigr Date: Mon, 20 Apr 2026 15:38:39 +0200 Subject: [PATCH 08/11] Remove proguard rules for optional jsoup classes The underlying problem is fixed with jsoup 1.12.2. See https://github.com/TeamNewPipe/NewPipeExtractor/pull/1480. Revert 6c5d58bed3a4e7945580c644a875aa1addf3a89b / #13038. --- app/proguard-rules.pro | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index df4f78d8c38..61c0d06d0e4 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -16,11 +16,6 @@ -dontwarn javax.script.** -keep class jdk.dynalink.** { *; } -dontwarn jdk.dynalink.** -# Rules for jsoup -# Ignore intended-to-be-optional re2j classes - only needed if using re2j for jsoup regex -# jsoup safely falls back to JDK regex if re2j not on classpath, but has concrete re2j refs -# See https://github.com/jhy/jsoup/issues/2459 - may be resolved in future, then this may be removed --dontwarn com.google.re2j.** ## Rules for ExoPlayer -keep class com.google.android.exoplayer2.** { *; } From 49354a3c04734dabc9d78cbc71915111e9dab0fe Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Thu, 16 Apr 2026 15:25:45 +0800 Subject: [PATCH 09/11] fixup! Relocate toml lint task to buildSrc and extend against default task Signed-off-by: Aayush Gupta --- app/check-dependencies.gradle | 48 ----------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 app/check-dependencies.gradle diff --git a/app/check-dependencies.gradle b/app/check-dependencies.gradle deleted file mode 100644 index 7646bc584bf..00000000000 --- a/app/check-dependencies.gradle +++ /dev/null @@ -1,48 +0,0 @@ -tasks.register('checkDependenciesOrder') { - group = 'verification' - description = 'Checks that each section in libs.versions.toml is sorted alphabetically' - - def tomlFile = file('../gradle/libs.versions.toml') - - doLast { - if (!tomlFile.exists()) { - throw new GradleException('TOML file not found') - } - - def lines = tomlFile.readLines() - def nonSortedBlocks = [] - def currentBlock = [] - def prevLine = '' - def prevIndex = 0 - - lines.eachWithIndex { line, lineIndex -> - if (line.trim() && !line.startsWith('#')) { - if (line.startsWith('[')) { - prevLine = '' - } else { - def currIndex = lineIndex + 1 - if (prevLine > line) { - if (currentBlock && currentBlock[-1] == "${prevIndex}: ${prevLine}") { - currentBlock.add("${currIndex}: ${line}") - } else { - if (!currentBlock.isEmpty()) { - nonSortedBlocks.add(currentBlock) - currentBlock = [] - } - currentBlock.add("${prevIndex}: ${prevLine}") - currentBlock.add("${currIndex}: ${line}") - } - } - prevLine = line - prevIndex = lineIndex + 1 - } - } - } - - if (!currentBlock.isEmpty()) { - nonSortedBlocks.add(currentBlock) - throw new GradleException("The following lines were not sorted:\n" + - nonSortedBlocks.collect { it.join("\n") }.join("\n\n")) - } - } -} \ No newline at end of file From c992b85b25bc1defb6e7324e662dfc10adb3a8a8 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Tue, 21 Apr 2026 10:43:43 +0800 Subject: [PATCH 10/11] libs: Update compose-related libraries to latest release The about libraries gradle plugin does merge of duplicate by defaults. Signed-off-by: Aayush Gupta --- app/build.gradle.kts | 1 - .../newpipe/ui/components/about/Library.kt | 12 +++++------- .../ui/components/about/LibraryDefinitions.kt | 19 ++++++++----------- gradle/libs.versions.toml | 10 +++++----- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 18963343d8f..4054ffab188 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -220,7 +220,6 @@ aboutLibraries { // note: offline mode prevents the plugin from fetching licenses at build time, which would be // harmful for reproducible builds offlineMode = true - duplicationMode = DuplicateMode.MERGE } dependencies { diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/about/Library.kt b/app/src/main/java/org/schabi/newpipe/ui/components/about/Library.kt index a5277dca0ae..cb51c3190ee 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/about/Library.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/about/Library.kt @@ -29,9 +29,7 @@ import com.mikepenz.aboutlibraries.entity.Library import com.mikepenz.aboutlibraries.entity.License import com.mikepenz.aboutlibraries.entity.Organization import com.mikepenz.aboutlibraries.entity.Scm -import com.mikepenz.aboutlibraries.ui.compose.m3.util.author -import kotlinx.collections.immutable.toImmutableList -import kotlinx.collections.immutable.toImmutableSet +import com.mikepenz.aboutlibraries.ui.compose.util.author import org.schabi.newpipe.ui.theme.AppTheme import org.schabi.newpipe.util.external_communication.ShareUtils @@ -140,7 +138,7 @@ private class LibraryProvider : CollectionPreviewParameterProvider( name = "NewPipeExtractor", description = "NewPipe Extractor is a library for extracting things from streaming sites. It is a core component of NewPipe, but could be used independently.", website = "https://newpipe.net", - developers = listOf(Developer("TeamNewPipe", "https://newpipe.net")).toImmutableList(), + developers = listOf(Developer("TeamNewPipe", "https://newpipe.net")), organization = Organization("TeamNewPipe", "https://newpipe.net"), scm = Scm(null, null, "https://github.com/TeamNewPipe/NewPipeExtractor"), licenses = setOf( @@ -160,7 +158,7 @@ private class LibraryProvider : CollectionPreviewParameterProvider( licenseContent = LoremIpsum().values.first(), hash = "4321" ) - ).toImmutableSet() + ) ), Library( uniqueId = "org.schabi.newpipe.extractor", @@ -168,7 +166,7 @@ private class LibraryProvider : CollectionPreviewParameterProvider( name = "NewPipeExtractor", description = "NewPipe Extractor is a library for extracting things from streaming sites. It is a core component of NewPipe, but could be used independently.", website = null, - developers = listOf().toImmutableList(), + developers = listOf(), organization = null, scm = null, licenses = setOf( @@ -180,7 +178,7 @@ private class LibraryProvider : CollectionPreviewParameterProvider( licenseContent = LoremIpsum().values.first(), hash = "1234" ) - ).toImmutableSet() + ) ) ) ) diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/about/LibraryDefinitions.kt b/app/src/main/java/org/schabi/newpipe/ui/components/about/LibraryDefinitions.kt index 9a6bfb7a055..32eff2fbe11 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/about/LibraryDefinitions.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/about/LibraryDefinitions.kt @@ -10,9 +10,6 @@ import com.mikepenz.aboutlibraries.entity.Developer import com.mikepenz.aboutlibraries.entity.Library import com.mikepenz.aboutlibraries.entity.License import com.mikepenz.aboutlibraries.entity.Scm -import kotlinx.collections.immutable.ImmutableSet -import kotlinx.collections.immutable.toImmutableList -import kotlinx.collections.immutable.toImmutableSet import org.schabi.newpipe.BuildConfig import org.schabi.newpipe.R @@ -38,7 +35,7 @@ fun getFirstPartyLibraries( licenseContent = null, hash = "GPL-3.0-or-later" ) - ).toImmutableSet() + ) val npeId = "com.github.TeamNewPipe:NewPipeExtractor" val npe = teamNewPipeLibraries.firstOrNull { it.uniqueId == npeId } @@ -55,7 +52,7 @@ fun getFirstPartyLibraries( name = context.getString(R.string.team_newpipe), organisationUrl = context.getString(R.string.website_url) ) - ).toImmutableList(), + ), organization = null, scm = Scm(null, null, context.getString(R.string.github_url)), licenses = gpl3 @@ -71,7 +68,7 @@ fun getFirstPartyLibraries( name = context.getString(R.string.team_newpipe), organisationUrl = context.getString(R.string.website_url) ) - ).toImmutableList(), + ), organization = null, scm = Scm(null, null, context.getString(R.string.newpipe_extractor_github_url)), licenses = gpl3 @@ -82,7 +79,7 @@ fun getFirstPartyLibraries( fun getAdditionalThirdPartyLibraries( context: Context, teamNewPipeLibraries: List, - licenses: ImmutableSet + licenses: Set ): List { val apache2 = licenses.firstOrNull { it.spdxId == "Apache-2.0" } val mit = licenses.firstOrNull { it.spdxId == "MIT" } @@ -109,10 +106,10 @@ fun getAdditionalThirdPartyLibraries( name = context.getString(R.string.team_newpipe), organisationUrl = context.getString(R.string.website_url) ) - ).toImmutableList(), + ), organization = null, scm = Scm(null, null, "https://github.com/TeamNewPipe/NoNonsense-FilePicker"), - licenses = listOfNotNull(mpl2).toImmutableSet() + licenses = setOfNotNull(mpl2) ), Library( uniqueId = nanojsonId, @@ -129,10 +126,10 @@ fun getAdditionalThirdPartyLibraries( name = context.getString(R.string.team_newpipe), organisationUrl = context.getString(R.string.website_url) ) - ).toImmutableList(), + ), organization = null, scm = Scm(null, null, "https://github.com/TeamNewPipe/nanojson"), - licenses = listOfNotNull(mit, apache2).toImmutableSet() + licenses = setOfNotNull(mit, apache2) ) ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2305feab8c8..777459e64e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ # [versions] -about-libraries = "11.2.3" +about-libraries = "14.0.1" acra = "5.13.1" agp = "8.13.2" appcompat = "1.7.1" @@ -15,7 +15,7 @@ bridge = "v2.0.2" cardview = "1.0.0" checkstyle = "13.4.0" coil = "3.4.0" -compose-bom = "2024.10.01" +compose-bom = "2026.04.01" constraintlayout = "2.2.1" core = "1.18.0" desugar = "2.1.5" @@ -25,7 +25,7 @@ fragment-compose = "1.8.9" groupie = "2.10.1" hilt = "2.58" # Newer version requires AGP 9 hilt-navigation-compose = "1.3.0" -jsoup = "1.21.2" +jsoup = "1.22.2" junit = "4.13.2" junit-ext = "1.3.0" kotlin = "2.3.20" @@ -40,9 +40,9 @@ markwon = "4.6.2" material = "1.11.0" # TODO: update to newer version after bug is fixed. See https://github.com/TeamNewPipe/NewPipe/pull/13018 media = "1.7.1" mockitoCore = "5.23.0" -nav3Core = "1.0.1" +nav3Core = "1.1.1" okhttp = "5.3.2" -paging-compose = "3.3.2" +paging-compose = "3.4.2" phoenix = "3.0.0" preference = "1.2.1" prettytime = "5.0.8.Final" From 43f40c485d55d89637472a8e3bbf09cbd1555647 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Tue, 21 Apr 2026 11:17:26 +0800 Subject: [PATCH 11/11] gradle: Build with JDK 21 Checkstyle was already requiring JDK 21 and now about libraries need it too Use the kotlin extension method as it will also configure it for java code Ref: https://kotlinlang.org/docs/gradle-configure-project.html#gradle-java-toolchains-support Signed-off-by: Aayush Gupta --- app/build.gradle.kts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4054ffab188..18449a97523 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,13 +24,8 @@ val gitWorkingBranch = providers.exec { commandLine("git", "rev-parse", "--abbrev-ref", "HEAD") }.standardOutput.asText.map { it.trim() } -java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } -} - kotlin { + jvmToolchain(21) compilerOptions { // TODO: Drop annotation default target when it is stable freeCompilerArgs.addAll( @@ -142,13 +137,6 @@ ksp { // Custom dependency configuration for ktlint val ktlint by configurations.creating -// https://checkstyle.org/#JRE_and_JDK -tasks.withType().configureEach { - javaLauncher = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(21) - } -} - checkstyle { configDirectory = rootProject.file("checkstyle") isIgnoreFailures = false