Skip to content

Commit d4ed18b

Browse files
Merge branch 'dev' into Merge-dev
# Conflicts: # app/build.gradle # app/src/main/java/org/schabi/newpipe/App.java # app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt # app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java # app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java # app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.java # app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java # app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java # app/src/main/res/values-bg/strings.xml # app/src/main/res/values-da/strings.xml # app/src/main/res/values-is/strings.xml # app/src/main/res/values-lv/strings.xml # app/src/main/res/values-zh-rTW/strings.xml # build.gradle
2 parents fbafdeb + 3fc0147 commit d4ed18b

442 files changed

Lines changed: 5756 additions & 1313 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ NewPipe contribution guidelines
66
## Crash reporting
77

88
Report crashes through the **automated crash report system** of NewPipe.
9-
This way all the data needed for debugging is included in your bugreport for GitHub.
9+
This way all the data needed for debugging is included in your bug report for GitHub.
1010
You'll see *exactly* what is sent, be able to add **your comments**, and then send it.
1111

1212
## Issue reporting/feature requests
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: "Build unsigned release APK on master"
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
release:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
with:
12+
ref: 'master'
13+
14+
- uses: actions/setup-java@v4
15+
with:
16+
distribution: 'temurin'
17+
java-version: '21'
18+
cache: 'gradle'
19+
20+
- name: "Build release APK"
21+
run: ./gradlew assembleRelease --stacktrace
22+
23+
- name: "Rename APK"
24+
run: |
25+
VERSION_NAME="$(jq -r ".elements[0].versionName" "app/build/outputs/apk/release/output-metadata.json")"
26+
echo "Version name: $VERSION_NAME" >> "$GITHUB_STEP_SUMMARY"
27+
echo '```json' >> "$GITHUB_STEP_SUMMARY"
28+
cat "app/build/outputs/apk/release/output-metadata.json" >> "$GITHUB_STEP_SUMMARY"
29+
echo >> "$GITHUB_STEP_SUMMARY"
30+
echo '```' >> "$GITHUB_STEP_SUMMARY"
31+
# assume there is only one APK in that folder
32+
mv app/build/outputs/apk/release/*.apk "app/build/outputs/apk/release/NewPipe_v$VERSION_NAME.apk"
33+
34+
- name: "Upload APK"
35+
uses: actions/upload-artifact@v4
36+
with:
37+
name: app
38+
path: app/build/outputs/apk/release/*.apk

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<p align="center"><a href="https://newpipe.net">Website</a> &bull; <a href="https://newpipe.net/blog/">Blog</a> &bull; <a href="https://newpipe.net/FAQ/">FAQ</a> &bull; <a href="https://newpipe.net/press/">Press</a></p>
2121
<hr>
2222

23-
*Read this document in other languages: [Deutsch](doc/README.de.md), [English](README.md), [Español](doc/README.es.md), [Français](doc/README.fr.md), [हिन्दी](doc/README.hi.md), [Italiano](doc/README.it.md), [한국어](doc/README.ko.md), [Português Brasil](doc/README.pt_BR.md), [Polski](doc/README.pl.md), [ਪੰਜਾਬੀ ](doc/README.pa.md), [日本語](doc/README.ja.md), [Română](doc/README.ro.md), [Soomaali](doc/README.so.md), [Türkçe](doc/README.tr.md), [正體中文](doc/README.zh_TW.md), [অসমীয়া](doc/README.asm.md), [Српски](doc/README.sr.md)*
23+
*Read this document in other languages: [Deutsch](doc/README.de.md), [English](README.md), [Español](doc/README.es.md), [Français](doc/README.fr.md), [हिन्दी](doc/README.hi.md), [Italiano](doc/README.it.md), [한국어](doc/README.ko.md), [Português Brasil](doc/README.pt_BR.md), [Polski](doc/README.pl.md), [ਪੰਜਾਬੀ ](doc/README.pa.md), [日本語](doc/README.ja.md), [Română](doc/README.ro.md), [Soomaali](doc/README.so.md), [Türkçe](doc/README.tr.md), [正體中文](doc/README.zh_TW.md), [অসমীয়া](doc/README.asm.md), [Српски](doc/README.sr.md), [العربية](README.ar.md)*
2424

2525
> [!warning]
2626
> <b>THIS APP IS IN BETA, SO YOU MAY ENCOUNTER BUGS. IF YOU DO, OPEN AN ISSUE IN OUR GITHUB REPOSITORY BY FILLING OUT THE ISSUE TEMPLATE.</b>
@@ -96,7 +96,7 @@ Also, since they are free and open source software, neither the app nor the Extr
9696
## Installation and updates
9797
You can install NewPipe using one of the following methods:
9898
1. Add our custom repo to F-Droid and install it from there. The instructions are here: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
99-
2. Download the APK from [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) and install it.
99+
2. Download the APK from [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases), [compare the signing key](#apk-info) and install it.
100100
3. Update via F-Droid. This is the slowest method of getting updates, as F-Droid must recognize changes, build the APK itself, sign it, and then push the update to users.
101101
4. Build a debug APK yourself. This is the fastest way to get new features on your device, but is much more complicated, so we recommend using one of the other methods.
102102
5. If you're interested in a specific feature or bugfix provided in a Pull Request in this repo, you can also download its APK from within the PR. Read the PR description for instructions. The great thing about PR-specific APKs is that they're installed side-by-side the official app, so you don't have to worry about losing your data or messing anything up.
@@ -109,7 +109,15 @@ In the meanwhile, if you want to switch sources for some reason (e.g. NewPipe's
109109
3. Download the APK from the new source and install it
110110
4. Import the data from step 1 via Settings > Backup and Restore > Import Database
111111

112-
<b>Note: when you're importing a database into the official app, always make sure that it is the one you exported _from_ the official app. If you import a database exported from an APK other than the official app, it may break things. Such an action is unsupported, and you should only do so when you're absolutely certain you know what you're doing.</b>
112+
> [!Note]
113+
> When you're importing a database into the official app, always make sure that it is the one you exported _from_ the official app. If you import a database exported from an APK other than the official app, it may break things. Such an action is unsupported, and you should only do so when you're absolutely certain you know what you're doing.
114+
115+
### APK Info
116+
117+
This is the SHA fingerprint of NewPipe's signing key to verify downloaded APKs which are signed by us. The fingerprint is also available on [NewPipe's website](https://newpipe.net#download). This is relevant for method 2.
118+
```
119+
CB:84:06:9B:D6:81:16:BA:FA:E5:EE:4E:E5:B0:8A:56:7A:A6:D8:98:40:4E:7C:B1:2F:9E:75:6D:F5:CF:5C:AB
120+
```
113121

114122
## Contribution
115123
Whether you have ideas, translations, design changes, code cleaning, or even major code changes, help is always welcome. The app gets better and better with each contribution, no matter how big or small! If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).

app/build.gradle

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,15 @@ android {
2424
resValue "string", "app_name", "NewPipe"
2525
minSdk 21
2626
targetSdk 33
27-
versionCode 999
28-
versionName "0.27.2"
27+
if (System.properties.containsKey('versionCodeOverride')) {
28+
versionCode System.getProperty('versionCodeOverride') as Integer
29+
} else {
30+
versionCode 1001
31+
}
32+
versionName "0.27.4"
33+
if (System.properties.containsKey('versionNameSuffix')) {
34+
versionNameSuffix System.getProperty('versionNameSuffix')
35+
}
2936

3037
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
3138

app/src/main/java/org/schabi/newpipe/DownloaderImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
public final class DownloaderImpl extends Downloader {
3131
public static final String USER_AGENT =
32-
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
32+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
3333
public static final String YOUTUBE_RESTRICTED_MODE_COOKIE_KEY =
3434
"youtube_restricted_mode_key";
3535
public static final String YOUTUBE_RESTRICTED_MODE_COOKIE = "PREF=f2=8000000";

app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,6 @@ default Flowable<List<PlaylistStreamEntity>> listByService(final int serviceId)
154154
+ " AND :streamUrl = :streamUrl"
155155

156156
+ " GROUP BY " + JOIN_PLAYLIST_ID
157-
+ " ORDER BY " + PLAYLIST_DISPLAY_INDEX)
157+
+ " ORDER BY " + PLAYLIST_DISPLAY_INDEX + ", " + PLAYLIST_NAME)
158158
Flowable<List<PlaylistDuplicatesEntry>> getPlaylistDuplicatesMetadata(String streamUrl);
159159
}

app/src/main/java/org/schabi/newpipe/info_list/dialog/StreamDialogDefaultEntry.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,10 @@ public enum StreamDialogDefaultEntry {
114114
DOWNLOAD(R.string.download, (fragment, item) ->
115115
fetchStreamInfoAndSaveToDatabase(fragment.requireContext(), item.getServiceId(),
116116
item.getUrl(), info -> {
117-
if (fragment.getContext() != null) {
117+
// Ensure the fragment is attached and its state hasn't been saved to avoid
118+
// showing dialog during lifecycle changes or when the activity is paused,
119+
// e.g. by selecting the download option and opening a different fragment.
120+
if (fragment.isAdded() && !fragment.isStateSaved()) {
118121
final DownloadDialog downloadDialog =
119122
new DownloadDialog(fragment.requireContext(), info);
120123
downloadDialog.show(fragment.getChildFragmentManager(),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.schabi.newpipe.ktx
2+
3+
import android.content.SharedPreferences
4+
5+
fun SharedPreferences.getStringSafe(key: String, defValue: String): String {
6+
return getString(key, null) ?: defValue
7+
}

app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ private void onPlaylistSelected(@NonNull final LocalPlaylistManager manager,
160160
.subscribe(ignored -> {
161161
successToast.show();
162162

163-
if (playlist.thumbnailUrl.equals(PlaylistEntity.DEFAULT_THUMBNAIL)) {
163+
if (playlist.thumbnailUrl != null
164+
&& playlist.thumbnailUrl.equals(PlaylistEntity.DEFAULT_THUMBNAIL)) {
164165
playlistDisposables.add(manager
165166
.changePlaylistThumbnail(playlist.getUid(), streams.get(0).getUid(),
166167
false)

app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadManager.kt

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import org.schabi.newpipe.database.subscription.NotificationMode
1717
import org.schabi.newpipe.database.subscription.SubscriptionEntity
1818
import org.schabi.newpipe.extractor.Info
1919
import org.schabi.newpipe.extractor.NewPipe
20+
import org.schabi.newpipe.extractor.ServiceList
2021
import org.schabi.newpipe.extractor.feed.FeedInfo
2122
import org.schabi.newpipe.extractor.stream.StreamInfoItem
23+
import org.schabi.newpipe.ktx.getStringSafe
2224
import org.schabi.newpipe.local.feed.FeedDatabaseManager
2325
import org.schabi.newpipe.local.subscription.SubscriptionManager
2426
import org.schabi.newpipe.util.ChannelTabHelper
@@ -69,12 +71,10 @@ class FeedLoadManager(private val context: Context) {
6971
val outdatedThreshold = if (ignoreOutdatedThreshold) {
7072
OffsetDateTime.now(ZoneOffset.UTC)
7173
} else {
72-
val thresholdOutdatedSeconds = (
73-
defaultSharedPreferences.getString(
74-
context.getString(R.string.feed_update_threshold_key),
75-
context.getString(R.string.feed_update_threshold_default_value)
76-
) ?: context.getString(R.string.feed_update_threshold_default_value)
77-
).toInt()
74+
val thresholdOutdatedSeconds = defaultSharedPreferences.getStringSafe(
75+
context.getString(R.string.feed_update_threshold_key),
76+
context.getString(R.string.feed_update_threshold_default_value)
77+
).toInt()
7878
OffsetDateTime.now(ZoneOffset.UTC).minusSeconds(thresholdOutdatedSeconds.toLong())
7979
}
8080

@@ -91,6 +91,10 @@ class FeedLoadManager(private val context: Context) {
9191
else -> feedDatabaseManager.outdatedSubscriptionsForGroup(groupId, outdatedThreshold)
9292
}
9393

94+
// like `currentProgress`, but counts the number of YouTube extractions that have begun, so
95+
// they can be properly throttled every once in a while (see doOnNext below)
96+
val youtubeExtractionCount = AtomicInteger()
97+
9498
return outdatedSubscriptions
9599
.take(1)
96100
.doOnNext {
@@ -106,6 +110,15 @@ class FeedLoadManager(private val context: Context) {
106110
.observeOn(Schedulers.io())
107111
.flatMap { Flowable.fromIterable(it) }
108112
.takeWhile { !cancelSignal.get() }
113+
.doOnNext { subscriptionEntity ->
114+
// throttle YouTube extractions once every BATCH_SIZE to avoid being rate limited
115+
if (subscriptionEntity.serviceId == ServiceList.YouTube.serviceId) {
116+
val previousCount = youtubeExtractionCount.getAndIncrement()
117+
if (previousCount != 0 && previousCount % BATCH_SIZE == 0) {
118+
Thread.sleep(DELAY_BETWEEN_BATCHES_MILLIS.random())
119+
}
120+
}
121+
}
109122
.parallel(PARALLEL_EXTRACTIONS, PARALLEL_EXTRACTIONS * 2)
110123
.runOn(Schedulers.io(), PARALLEL_EXTRACTIONS * 2)
111124
.filter { !cancelSignal.get() }
@@ -329,7 +342,19 @@ class FeedLoadManager(private val context: Context) {
329342
/**
330343
* How many extractions will be running in parallel.
331344
*/
332-
private const val PARALLEL_EXTRACTIONS = 6
345+
private const val PARALLEL_EXTRACTIONS = 3
346+
347+
/**
348+
* How many YouTube extractions to perform before waiting [DELAY_BETWEEN_BATCHES_MILLIS]
349+
* to avoid being rate limited
350+
*/
351+
private const val BATCH_SIZE = 50
352+
353+
/**
354+
* Wait a random delay in this range once every [BATCH_SIZE] YouTube extractions to avoid
355+
* being rate limited
356+
*/
357+
private val DELAY_BETWEEN_BATCHES_MILLIS = (6000L..12000L)
333358

334359
/**
335360
* Number of items to buffer to mass-insert in the database.

0 commit comments

Comments
 (0)