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 0a0b5b43821367e05f670cf2ad15a463fc8501bf 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..6747faa54c5 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.03.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.0" 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 dc6bc39a8c1ad1c0f36c65b3009b64ccecc16e01 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 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