diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index d08ae9051..088707b6e 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,3 +1,5 @@
+### Please do **not** open pull requests for *new features* now, as we are planning to rewrite large chunks of the code. Only bugfix PRs will be accepted. More details will be announced soon!
+
NewPipe contribution guidelines
===============================
@@ -22,6 +24,7 @@ You'll see *exactly* what is sent, be able to add **your comments**, and then se
* NewPipe is translated via [Weblate](https://hosted.weblate.org/projects/newpipe/strings/). Log in there with your GitHub account, or register.
* Add the language you want to translate if it is not there already: see [How to add a new language](https://github.com/TeamNewPipe/NewPipe/wiki/How-to-add-a-new-language-to-NewPipe) in the wiki.
+* NewPipe uses the [PrettyTime](https://github.com/ocpsoft/prettytime) library to display localized versions of dates and times. It needs to be translated, too. Read [these instructions to add a new language](https://www.ocpsoft.org/prettytime/#section-14) and [this issue](https://github.com/TeamNewPipe/NewPipe/issues/9134) for more info.
## Code contribution
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/DISCUSSION_TEMPLATE/questions.yml
similarity index 72%
rename from .github/ISSUE_TEMPLATE/question.yml
rename to .github/DISCUSSION_TEMPLATE/questions.yml
index 4c42ab26a..2d467d5e5 100644
--- a/.github/ISSUE_TEMPLATE/question.yml
+++ b/.github/DISCUSSION_TEMPLATE/questions.yml
@@ -1,11 +1,8 @@
-name: Question
-description: Ask about anything NewPipe-related
-labels: [question]
body:
- type: markdown
attributes:
value: |
- Thanks for taking the time to fill out this issue! :hugs:
+ Thanks for taking the time to fill out this form! :hugs:
Note that you can also ask questions on our [IRC channel](https://web.libera.chat/#newpipe).
@@ -14,7 +11,9 @@ body:
attributes:
label: "Checklist"
options:
- - label: "I made sure that there are *no existing issues* - [open](https://github.com/TeamNewPipe/NewPipe/issues) or [closed](https://github.com/TeamNewPipe/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
+ - label: "I made sure that there are *no existing issues or discussions* - [open](https://github.com/TeamNewPipe/NewPipe/issues) or [closed](https://github.com/TeamNewPipe/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
+ required: true
+ - label: "I have read the [FAQ](https://newpipe.net/FAQ/) and my question isn't listed."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the question will be dismissed otherwise."
required: true
@@ -27,7 +26,7 @@ body:
label: What is/are your question(s)?
validations:
required: true
-
+
- type: textarea
id: additional-information
attributes:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index a0a9f9ef5..52897f1ac 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,6 +1,6 @@
name: Bug report
description: Create a bug report to help us improve
-labels: [bug]
+labels: [bug, needs triage]
body:
- type: markdown
attributes:
@@ -14,10 +14,12 @@ body:
attributes:
label: "Checklist"
options:
- - label: "I am able to reproduce the bug with the [latest version](https://github.com/TeamNewPipe/NewPipe/releases/latest)."
+ - label: "I am able to reproduce the bug with the latest version given here: [CLICK THIS LINK](https://github.com/TeamNewPipe/NewPipe/releases/latest)."
required: true
- label: "I made sure that there are *no existing issues* - [open](https://github.com/TeamNewPipe/NewPipe/issues) or [closed](https://github.com/TeamNewPipe/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
+ - label: "I have read the [FAQ](https://newpipe.net/FAQ/) and my problem isn't listed."
+ required: true
- label: "I have taken the time to fill in all the required details. I understand that the bug report will be dismissed otherwise."
required: true
- label: "This issue contains only one bug."
@@ -40,7 +42,7 @@ body:
label: Steps to reproduce the bug
description: |
What did you do for the bug to show up?
-
+
If you can't cause the bug to show up again reliably (and hence don't have a proper set of steps to give us), please still try to give as many details as possible on how you think you encountered the bug.
placeholder: |
1. Go to '...'
@@ -69,11 +71,11 @@ body:
label: Screenshots/Screen recordings
description: |
A picture or video is worth a thousand words.
-
+
If applicable, add screenshots or a screen recording to help explain your problem.
GitHub supports uploading them directly in the text box.
If your file is too big for Github to accept, try to compress it (ZIP-file) or feel free to paste a link to an image/video hoster here instead.
-
+
:heavy_exclamation_mark: DON'T POST SCREENSHOTS OF THE ERROR PAGE.
Instead, follow the instructions in the "Logs" section below.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index b0fdb56db..4721637bf 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
+ - name: ❓ Question
+ url: https://github.com/TeamNewPipe/NewPipe/discussions/new?category=questions
+ about: Ask about anything NewPipe-related
- name: 💬 IRC
url: https://web.libera.chat/#newpipe
about: Chat with us via IRC for quick Q/A
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 83d6f0299..31ef92c44 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,6 +1,6 @@
name: Feature request
description: Suggest an idea for this project
-labels: [enhancement]
+labels: [feature request, needs triage]
body:
- type: markdown
attributes:
@@ -8,7 +8,6 @@ body:
Thank you for helping to make NewPipe better by suggesting a feature. :hugs:
Your ideas are highly welcome! The app is made for you, the users, after all.
-
- type: checkboxes
id: checklist
attributes:
@@ -16,6 +15,8 @@ body:
options:
- label: "I made sure that there are *no existing issues* - [open](https://github.com/TeamNewPipe/NewPipe/issues) or [closed](https://github.com/TeamNewPipe/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
+ - label: "I have read the [FAQ](https://newpipe.net/FAQ/) and my problem isn't listed."
+ required: true
- label: "I'm aware that this is a request for NewPipe itself and that requests for adding a new service need to be made at [NewPipeExtractor](https://github.com/TeamNewPipe/NewPipeExtractor/issues)."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the feature request will be dismissed otherwise."
@@ -43,7 +44,7 @@ body:
Describe any problem or limitation you come across while using the app which would be solved by this feature.
validations:
required: true
-
+
- type: textarea
id: additional-information
attributes:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 10e40af2a..407c00a39 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -25,10 +25,10 @@
-
-#### APK testing
+#### APK testing
-The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR.
+The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR. You can find more info and a video demonstration [on this wiki page](https://github.com/TeamNewPipe/NewPipe/wiki/Download-APK-for-PR).
#### Due diligence
- [ ] I read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md).
diff --git a/.github/changed-lines-count-labeler.yml b/.github/changed-lines-count-labeler.yml
new file mode 100644
index 000000000..902f376c0
--- /dev/null
+++ b/.github/changed-lines-count-labeler.yml
@@ -0,0 +1,17 @@
+# Add 'size/small' label to any changes with less than 50 lines
+size/small:
+ max: 49
+
+# Add 'size/medium' label to any changes between 50 and 249 lines
+size/medium:
+ min: 50
+ max: 249
+
+# Add 'size/large' label to any changes between 250 and 749 lines
+size/large:
+ min: 250
+ max: 749
+
+# Add 'size/giant' label to any changes for more than 749 lines
+size/giant:
+ min: 750
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7dbfadc0b..0d76e1645 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,6 +6,7 @@ on:
branches:
- dev
- master
+ - release**
paths-ignore:
- 'README.md'
- 'doc/**'
@@ -30,19 +31,25 @@ on:
jobs:
build-and-test-jvm:
runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+
steps:
- - uses: actions/checkout@v2
- - uses: gradle/wrapper-validation-action@v1
+ - uses: actions/checkout@v4
+ - uses: gradle/wrapper-validation-action@v2
- name: create and checkout branch
# push events already checked out the branch
if: github.event_name == 'pull_request'
- run: git checkout -B ${{ github.head_ref }}
+ env:
+ BRANCH: ${{ github.head_ref }}
+ run: git checkout -B "$BRANCH"
- - name: set up JDK 11
- uses: actions/setup-java@v2
+ - name: set up JDK 17
+ uses: actions/setup-java@v4
with:
- java-version: 11
+ java-version: 17
distribution: "temurin"
cache: 'gradle'
@@ -50,7 +57,7 @@ jobs:
run: ./gradlew assembleDebug lintDebug testDebugUnitTest --stacktrace -DskipFormatKtlint
- name: Upload APK
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: app
path: app/build/outputs/apk/debug/*.apk
@@ -61,15 +68,24 @@ jobs:
timeout-minutes: 20
strategy:
matrix:
- # api-level 19 is min sdk, but throws errors related to desugaring
- api-level: [ 21, 29 ]
- steps:
- - uses: actions/checkout@v2
+ include:
+ - api-level: 21
+ target: default
+ arch: x86
+ - api-level: 33
+ target: google_apis # emulator API 33 only exists with Google APIs
+ arch: x86_64
- - name: set up JDK 11
- uses: actions/setup-java@v2
+ permissions:
+ contents: read
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: set up JDK 17
+ uses: actions/setup-java@v4
with:
- java-version: 11
+ java-version: 17
distribution: "temurin"
cache: 'gradle'
@@ -77,12 +93,12 @@ jobs:
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
- # workaround to emulator bug: https://github.com/ReactiveCircus/android-emulator-runner/issues/160
- emulator-build: 7425822
+ target: ${{ matrix.target }}
+ arch: ${{ matrix.arch }}
script: ./gradlew connectedCheck --stacktrace
-
+
- name: Upload test report when tests fail # because the printed out stacktrace (console) is too short, see also #7553
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: android-test-report-api${{ matrix.api-level }}
@@ -90,20 +106,24 @@ jobs:
sonar:
runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Set up JDK 11
- uses: actions/setup-java@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
with:
- java-version: 11 # Sonar requires JDK 11
+ java-version: 17
distribution: "temurin"
cache: 'gradle'
- name: Cache SonarCloud packages
- uses: actions/cache@v2
+ uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
@@ -113,4 +133,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- run: ./gradlew build sonarqube --info
+ run: ./gradlew build sonar --info
diff --git a/.github/workflows/image-minimizer.js b/.github/workflows/image-minimizer.js
index 80cc5294c..d099068ba 100644
--- a/.github/workflows/image-minimizer.js
+++ b/.github/workflows/image-minimizer.js
@@ -17,6 +17,8 @@ module.exports = async ({github, context}) => {
initialBody = context.payload.comment.body;
} else if (context.eventName == 'issues') {
initialBody = context.payload.issue.body;
+ } else if (context.eventName == 'pull_request') {
+ initialBody = context.payload.pull_request.body;
} else {
console.log('Aborting: No body found');
return;
@@ -30,10 +32,12 @@ module.exports = async ({github, context}) => {
}
// Regex for finding images (simple variant) ;
- return match;
- });
+ let newBody = await replaceAsync(initialBody, REGEX_USER_CONTENT_IMAGE_LOOKUP, minimizeAsync);
+ newBody = await replaceAsync(newBody, REGEX_ASSETS_IMAGE_LOCKUP, minimizeAsync);
if (!wasMatchModified) {
console.log('Nothing was modified. Skipping update');
@@ -115,9 +76,17 @@ module.exports = async ({github, context}) => {
repo: context.repo.repo,
body: newBody
});
+ } else if (context.eventName == 'pull_request') {
+ console.log('Updating pull request', context.payload.pull_request.number);
+ await github.rest.pulls.update({
+ pull_number: context.payload.pull_request.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: newBody
+ });
}
- // Asnyc replace function from https://stackoverflow.com/a/48032528
+ // Async replace function from https://stackoverflow.com/a/48032528
async function replaceAsync(str, regex, asyncFn) {
const promises = [];
str.replace(regex, (match, ...args) => {
@@ -127,4 +96,52 @@ module.exports = async ({github, context}) => {
const data = await Promise.all(promises);
return str.replace(regex, () => data.shift());
}
+
+ async function minimizeAsync(match, g1, g2) {
+ console.log(`Found match '${match}'`);
+
+ if (g1.endsWith(IGNORE_ALT_NAME_END)) {
+ console.log(`Ignoring match '${match}': IGNORE_ALT_NAME_END`);
+ return match;
+ }
+
+ let probeAspectRatio = 0;
+ let shouldModify = false;
+ try {
+ console.log(`Probing ${g2}`);
+ let probeResult = await probe(g2);
+ if (probeResult == null) {
+ throw 'No probeResult';
+ }
+ if (probeResult.hUnits != 'px') {
+ 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`);
+
+ probeAspectRatio = probeResult.width / probeResult.height;
+ shouldModify = probeResult.height > IMG_MAX_HEIGHT_PX && probeAspectRatio < MIN_ASPECT_RATIO;
+ } catch(e) {
+ console.log('Probing failed:', e);
+ // Immediately abort
+ return match;
+ }
+
+ if (shouldModify) {
+ wasMatchModified = true;
+ console.log(`Modifying match '${match}'`);
+ return `
`;
+ }
+
+ console.log(`Match '${match}' is ok/will not be modified`);
+ return match;
+ }
}
diff --git a/.github/workflows/image-minimizer.yml b/.github/workflows/image-minimizer.yml
index 77b1faecf..d9241c33b 100644
--- a/.github/workflows/image-minimizer.yml
+++ b/.github/workflows/image-minimizer.yml
@@ -5,15 +5,21 @@ on:
types: [created, edited]
issues:
types: [opened, edited]
+ pull_request:
+ types: [opened, edited]
+
+permissions:
+ issues: write
+ pull-requests: write
jobs:
try-minimize:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- - uses: actions/setup-node@v2
+ - uses: actions/setup-node@v4
with:
node-version: 16
@@ -21,7 +27,7 @@ jobs:
run: npm i probe-image-size@7.2.3 --ignore-scripts
- name: Minimize simple images
- uses: actions/github-script@v5
+ uses: actions/github-script@v7
timeout-minutes: 3
with:
script: |
diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml
index 54e749dc0..b3495135f 100644
--- a/.github/workflows/no-response.yml
+++ b/.github/workflows/no-response.yml
@@ -9,6 +9,10 @@ on:
# Run daily at midnight.
- cron: '0 0 * * *'
+permissions:
+ issues: write
+ pull-requests: write
+
jobs:
noResponse:
runs-on: ubuntu-latest
@@ -17,4 +21,4 @@ jobs:
with:
token: ${{ github.token }}
daysUntilClose: 14
- responseRequiredLabel: waiting-for-author
+ responseRequiredLabel: waiting for author
diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml
new file mode 100644
index 000000000..a18daca3a
--- /dev/null
+++ b/.github/workflows/pr-labeler.yml
@@ -0,0 +1,18 @@
+name: "PR size labeler"
+on: [pull_request_target]
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ changed-lines-count-labeler:
+ runs-on: ubuntu-latest
+ name: Automatically labelling pull requests based on the changed lines count
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Set a label
+ uses: TeamNewPipe/changed-lines-count-labeler@main
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ configuration-path: .github/changed-lines-count-labeler.yml
diff --git a/README.md b/README.md
index 28be82192..4e22f9260 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,9 @@
+
We are planning to rewrite large chunks of the codebase, to bring about a new, modern and stable NewPipe!
+Please do not open pull requests for new features now, only bugfix PRs will be accepted.
+
NewPipe
-A libre lightweight streaming frontend for Android.
+A libre lightweight streaming front-end for Android.
@@ -10,90 +13,95 @@
-
+
Screenshots • Description • Features • Installation and updates • Contribution • Donate • License
+Screenshots • Supported Services • Description • Features • Installation and updates • Contribution • Donate • License
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
-[
](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
-[
](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
-[
](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
-
-## Description
-
-NewPipe does not use any Google framework libraries, nor the YouTube API. Websites are only parsed to fetch required info, so this app can be used on devices without Google services installed. Also, you don't need a YouTube account to use NewPipe, which is copylefted libre software.
-
-### Features
-
-* Search videos
-* No Login Required
-* Display general info about videos
-* Watch YouTube videos
-* Listen to YouTube videos
-* Popup mode (floating player)
-* Select streaming player to watch video with
-* Download videos
-* Download audio only
-* Open a video in Kodi
-* Show next/related videos
-* Search YouTube in a specific language
-* Watch/Block age restricted material
-* Display general info about channels
-* Search channels
-* Watch videos from a channel
-* Orbot/Tor support (not yet directly)
-* 1080p/2K/4K support
-* View history
-* Subscribe to channels
-* Search history
-* Search/watch playlists
-* Watch as enqueued playlists
-* Enqueue videos
-* Local playlists
-* Subtitles
-* Livestream support
-* Show comments
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/00.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/01.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/02.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/03.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/04.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/05.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/06.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/07.png)
+[
](fastlane/metadata/android/en-US/images/phoneScreenshots/08.png)
+
](fastlane/metadata/android/en-US/images/tenInchScreenshots/09.png)
+[
](fastlane/metadata/android/en-US/images/tenInchScreenshots/10.png)
### Supported Services
-NewPipe supports multiple services. Our [docs](https://teamnewpipe.github.io/documentation/) provide more info on how a new service can be added to the app and the extractor. Please get in touch with us if you intend to add a new one. Currently supported services are:
+NewPipe currently supports these services:
-* YouTube
-* SoundCloud \[beta\]
-* media.ccc.de \[beta\]
-* PeerTube instances \[beta\]
-* Bandcamp \[beta\]
+
+* YouTube ([website](https://www.youtube.com/)) and YouTube Music ([website](https://music.youtube.com/)) ([wiki](https://en.wikipedia.org/wiki/YouTube))
+* PeerTube ([website](https://joinpeertube.org/)) and all its instances (open the website to know what that means!) ([wiki](https://en.wikipedia.org/wiki/PeerTube))
+* Bandcamp ([website](https://bandcamp.com/)) ([wiki](https://en.wikipedia.org/wiki/Bandcamp))
+* SoundCloud ([website](https://soundcloud.com/)) ([wiki](https://en.wikipedia.org/wiki/SoundCloud))
+* media.ccc.de ([website](https://media.ccc.de/)) ([wiki](https://en.wikipedia.org/wiki/Chaos_Computer_Club))
-
+As you can see, NewPipe supports multiple video and audio services. Though it started off with YouTube, other people have added more services over the years, making NewPipe more and more versatile!
+
+Partially due to circumstance, and partially due to its popularity, YouTube is the best supported out of these services. If you use or are familiar with any of these other services, please help us improve support for them! We're looking for maintainers for SoundCloud and PeerTube.
+
+If you intend to add a new service, please get in touch with us first! Our [docs](https://teamnewpipe.github.io/documentation/) provide more information on how a new service can be added to the app and to the [NewPipe Extractor](https://github.com/TeamNewPipe/NewPipeExtractor).
+
+## Description
+
+NewPipe works by fetching the required data from the official API (e.g. PeerTube) of the service you're using. If the official API is restricted (e.g. YouTube) for our purposes, or is proprietary, the app parses the website or uses an internal API instead. This means that you don't need an account on any service to use NewPipe.
+
+Also, since they are free and open source software, neither the app nor the Extractor use any proprietary libraries or frameworks, such as Google Play Services. This means you can use NewPipe on devices or custom ROMs that do not have Google apps installed.
+
+### Features
+
+* Watch videos at resolutions up to 4K
+* Listen to audio in the background, only loading the audio stream to save data
+* Popup mode (floating player, aka Picture-in-Picture)
+* Watch live streams
+* Show/hide subtitles/closed captions
+* Search videos and audios (on YouTube, you can specify the content language as well)
+* Enqueue videos (and optionally save them as local playlists)
+* Show/hide general information about videos (such as description and tags)
+* Show/hide next/related videos
+* Show/hide comments
+* Search videos, audios, channels, playlists and albums
+* Browse videos and audios within a channel
+* Subscribe to channels (yes, without logging into any account!)
+* Get notifications about new videos from channels you're subscribed to
+* Create and edit channel groups (for easier browsing and management)
+* Browse video feeds generated from your channel groups
+* View and search your watch history
+* Search and watch playlists (these are remote playlists, which means they're fetched from the service you're browsing)
+* Create and edit local playlists (these are created and saved within the app, and have nothing to do with any service)
+* Download videos/audios/subtitles (closed captions)
+* Open in Kodi
+* Watch/Block age-restricted material
+
+
## Installation and updates
You can install NewPipe using one of the following methods:
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/
2. Download the APK from [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) and install it.
- 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, then push the update to users.
+ 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.
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.
+ 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.
-We recommend method 1 for most users. APKs installed using method 1 or 2 are compatible with each other, but not with those installed using method 3. This is due to the same signing key (ours) being used for 1 and 2, but a different signing key (F-Droid's) being used for 3. Building a debug APK using method 4 excludes a key entirely. Signing keys help ensure that a user isn't tricked into installing a malicious update to an app.
+We recommend method 1 for most users. APKs installed using method 1 or 2 are compatible with each other (meaning that if you installed NewPipe using either method 1 or 2, you can also update NewPipe using the other), but not with those installed using method 3. This is due to the same signing key (ours) being used for 1 and 2, but a different signing key (F-Droid's) being used for 3. Building a debug APK using method 4 excludes a key entirely. Signing keys help ensure that a user isn't tricked into installing a malicious update to an app. When using method 5, each APK is signed with a different random key supplied by GitHub Actions, so you cannot even update it. You will have to backup and restore the app data each time you wish to use a new APK.
In the meanwhile, if you want to switch sources for some reason (e.g. NewPipe's core functionality breaks and F-Droid doesn't have the latest update yet), we recommend following this procedure:
1. Back up your data via Settings > Content > Export Database so you keep your history, subscriptions, and playlists
@@ -101,47 +109,31 @@ In the meanwhile, if you want to switch sources for some reason (e.g. NewPipe's
3. Download the APK from the new source and install it
4. Import the data from step 1 via Settings > Content > Import Database
-## Contribution
-Whether you have ideas, translations, design changes, code cleaning, or real heavy code changes, help is always welcome.
-The more is done the better it gets!
+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.
-If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).
+## Contribution
+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).
## Donate
-If you like NewPipe we'd be happy about a donation. You can either send bitcoin or donate via Bountysource or Liberapay. For further info on donating to NewPipe, please visit our [website](https://newpipe.net/donate).
+If you like NewPipe, you're welcome to send a donation. We prefer Liberapay, as it is both open-source and non-profit. For further info on donating to NewPipe, please visit our [website](https://newpipe.net/donate).
![]() |
- 16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh | -|
![]() |
||
![]() |
-
+ * {@link #initListeners()} is called after this method to initialize the corresponding + * listeners. + *
+ * @param rootView The inflated view for this fragment + * (provided by {@link #onViewCreated(View, Bundle)}) + * @param savedInstanceState The saved state of this fragment + * (provided by {@link #onViewCreated(View, Bundle)}) + */ protected void initViews(final View rootView, final Bundle savedInstanceState) { } + /** + * Initialize the listeners for this fragment. + * + *+ * This method is called after {@link #initViews(View, Bundle)} + * in {@link #onViewCreated(View, Bundle)}. + *
+ */ protected void initListeners() { } @@ -108,9 +120,20 @@ public abstract class BaseFragment extends Fragment { } } + /** + * Finds the root fragment by looping through all of the parent fragments. The root fragment + * is supposed to be {@link org.schabi.newpipe.fragments.MainFragment}, and is the fragment that + * handles keeping the backstack of opened fragments in NewPipe, and also the player bottom + * sheet. This function therefore returns the fragment manager of said fragment. + * + * @return the fragment manager of the root fragment, i.e. + * {@link org.schabi.newpipe.fragments.MainFragment} + */ protected FragmentManager getFM() { - return getParentFragment() == null - ? getFragmentManager() - : getParentFragment().getFragmentManager(); + Fragment current = this; + while (current.getParentFragment() != null) { + current = current.getParentFragment(); + } + return current.getFragmentManager(); } } diff --git a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java index fde991655..9ddbe96df 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java +++ b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java @@ -1,7 +1,6 @@ package org.schabi.newpipe; import android.content.Context; -import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -12,40 +11,27 @@ import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Request; import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; -import org.schabi.newpipe.util.CookieUtils; import org.schabi.newpipe.util.InfoCache; -import org.schabi.newpipe.util.TLSSocketFactoryCompat; import java.io.IOException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import okhttp3.CipherSuite; -import okhttp3.ConnectionSpec; import okhttp3.OkHttpClient; import okhttp3.RequestBody; import okhttp3.ResponseBody; -import static org.schabi.newpipe.MainActivity.DEBUG; - public final class DownloaderImpl extends Downloader { - public static final String USER_AGENT - = "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"; - public static final String YOUTUBE_RESTRICTED_MODE_COOKIE_KEY - = "youtube_restricted_mode_key"; + public static final String USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"; + public static final String YOUTUBE_RESTRICTED_MODE_COOKIE_KEY = + "youtube_restricted_mode_key"; public static final String YOUTUBE_RESTRICTED_MODE_COOKIE = "PREF=f2=8000000"; public static final String YOUTUBE_DOMAIN = "youtube.com"; @@ -54,9 +40,6 @@ public final class DownloaderImpl extends Downloader { private final OkHttpClient client; private DownloaderImpl(final OkHttpClient.Builder builder) { - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { - enableModernTLS(builder); - } this.client = builder .readTimeout(30, TimeUnit.SECONDS) // .cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), @@ -81,69 +64,16 @@ public final class DownloaderImpl extends Downloader { return instance; } - /** - * Enable TLS 1.2 and 1.1 on Android Kitkat. This function is mostly taken - * from the documentation of OkHttpClient.Builder.sslSocketFactory(_,_). - *- * If there is an error, the function will safely fall back to doing nothing - * and printing the error to the console. - *
- * - * @param builder The HTTPClient Builder on which TLS is enabled on (will be modified in-place) - */ - private static void enableModernTLS(final OkHttpClient.Builder builder) { - try { - // get the default TrustManager - final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init((KeyStore) null); - final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { - throw new IllegalStateException("Unexpected default trust managers:" - + Arrays.toString(trustManagers)); - } - final X509TrustManager trustManager = (X509TrustManager) trustManagers[0]; - - // insert our own TLSSocketFactory - final SSLSocketFactory sslSocketFactory = TLSSocketFactoryCompat.getInstance(); - - builder.sslSocketFactory(sslSocketFactory, trustManager); - - // This will try to enable all modern CipherSuites(+2 more) - // that are supported on the device. - // Necessary because some servers (e.g. Framatube.org) - // don't support the old cipher suites. - // https://github.com/square/okhttp/issues/4053#issuecomment-402579554 - final List
+ * The dialog contains a loading indicator and has a customizable title.
+ *
+ * Use {@code show()} to display the dialog to the user.
+ *