210834fbe9
Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
312 lines
11 KiB
Groovy
312 lines
11 KiB
Groovy
plugins {
|
|
id "com.android.application"
|
|
id "kotlin-android"
|
|
id "kotlin-kapt"
|
|
id "kotlin-parcelize"
|
|
id "checkstyle"
|
|
id "org.sonarqube" version "3.3"
|
|
}
|
|
|
|
android {
|
|
compileSdk 31
|
|
buildToolsVersion '31.0.0'
|
|
|
|
defaultConfig {
|
|
applicationId "org.schabi.newpipe"
|
|
resValue "string", "app_name", "NewPipe"
|
|
minSdk 19
|
|
targetSdk 29
|
|
versionCode 986
|
|
versionName "0.23.0"
|
|
|
|
multiDexEnabled true
|
|
|
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
vectorDrawables.useSupportLibrary = true
|
|
|
|
javaCompileOptions {
|
|
annotationProcessorOptions {
|
|
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
|
|
}
|
|
}
|
|
}
|
|
|
|
buildTypes {
|
|
debug {
|
|
debuggable true
|
|
|
|
// suffix the app id and the app name with git branch name
|
|
def workingBranch = getGitWorkingBranch()
|
|
def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "")
|
|
if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
|
|
// default values when branch name could not be determined or is master or dev
|
|
applicationIdSuffix ".debug"
|
|
resValue "string", "app_name", "NewPipe Debug"
|
|
} else {
|
|
applicationIdSuffix ".debug." + normalizedWorkingBranch
|
|
resValue "string", "app_name", "NewPipe " + workingBranch
|
|
archivesBaseName = 'NewPipe_' + normalizedWorkingBranch
|
|
}
|
|
}
|
|
|
|
// Keep the release build type at the end of the list to override 'archivesBaseName' of
|
|
// debug build. This seems to be a Gradle bug, therefore
|
|
// TODO: update Gradle version
|
|
release {
|
|
if (System.properties.containsKey('packageSuffix')) {
|
|
applicationIdSuffix System.getProperty('packageSuffix')
|
|
resValue "string", "app_name", "NewPipe " + System.getProperty('packageSuffix')
|
|
archivesBaseName = 'NewPipe_' + System.getProperty('packageSuffix')
|
|
}
|
|
minifyEnabled true
|
|
shrinkResources false // disabled to fix F-Droid's reproducible build
|
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
archivesBaseName = 'app'
|
|
}
|
|
}
|
|
|
|
lint {
|
|
checkReleaseBuilds false
|
|
// Or, if you prefer, you can continue to check for errors in release builds,
|
|
// but continue the build even when errors are found:
|
|
abortOnError false
|
|
// suppress false warning ("Resource IDs will be non-final in Android Gradle Plugin version
|
|
// 5.0, avoid using them in switch case statements"), which affects only library projects
|
|
disable 'NonConstantResourceId'
|
|
}
|
|
|
|
compileOptions {
|
|
// Flag to enable support for the new language APIs
|
|
coreLibraryDesugaringEnabled true
|
|
|
|
sourceCompatibility JavaVersion.VERSION_11
|
|
targetCompatibility JavaVersion.VERSION_11
|
|
encoding 'utf-8'
|
|
}
|
|
|
|
kotlinOptions {
|
|
jvmTarget = JavaVersion.VERSION_11
|
|
}
|
|
|
|
sourceSets {
|
|
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
|
|
}
|
|
|
|
buildFeatures {
|
|
viewBinding true
|
|
}
|
|
}
|
|
|
|
ext {
|
|
checkstyleVersion = '10.0'
|
|
|
|
androidxLifecycleVersion = '2.3.1'
|
|
androidxRoomVersion = '2.4.2'
|
|
androidxWorkVersion = '2.7.1'
|
|
|
|
icepickVersion = '3.2.0'
|
|
exoPlayerVersion = '2.17.1'
|
|
googleAutoServiceVersion = '1.0.1'
|
|
groupieVersion = '2.10.1'
|
|
markwonVersion = '4.6.2'
|
|
|
|
leakCanaryVersion = '2.5'
|
|
stethoVersion = '1.6.0'
|
|
mockitoVersion = '4.0.0'
|
|
assertJVersion = '3.22.0'
|
|
}
|
|
|
|
configurations {
|
|
checkstyle
|
|
ktlint
|
|
}
|
|
|
|
checkstyle {
|
|
getConfigDirectory().set(rootProject.file("checkstyle"))
|
|
ignoreFailures false
|
|
showViolations true
|
|
toolVersion = checkstyleVersion
|
|
}
|
|
|
|
task runCheckstyle(type: Checkstyle) {
|
|
source 'src'
|
|
include '**/*.java'
|
|
exclude '**/gen/**'
|
|
exclude '**/R.java'
|
|
exclude '**/BuildConfig.java'
|
|
exclude 'main/java/us/shandian/giga/**'
|
|
|
|
classpath = configurations.checkstyle
|
|
|
|
showViolations true
|
|
|
|
reports {
|
|
xml.getRequired().set(true)
|
|
html.getRequired().set(true)
|
|
}
|
|
}
|
|
|
|
def outputDir = "${project.buildDir}/reports/ktlint/"
|
|
def inputFiles = project.fileTree(dir: "src", include: "**/*.kt")
|
|
|
|
task runKtlint(type: JavaExec) {
|
|
inputs.files(inputFiles)
|
|
outputs.dir(outputDir)
|
|
getMainClass().set("com.pinterest.ktlint.Main")
|
|
classpath = configurations.ktlint
|
|
args "src/**/*.kt"
|
|
}
|
|
|
|
task formatKtlint(type: JavaExec) {
|
|
inputs.files(inputFiles)
|
|
outputs.dir(outputDir)
|
|
getMainClass().set("com.pinterest.ktlint.Main")
|
|
classpath = configurations.ktlint
|
|
args "-F", "src/**/*.kt"
|
|
}
|
|
|
|
afterEvaluate {
|
|
if (!System.properties.containsKey('skipFormatKtlint')) {
|
|
preDebugBuild.dependsOn formatKtlint
|
|
}
|
|
preDebugBuild.dependsOn runCheckstyle, runKtlint
|
|
}
|
|
|
|
sonarqube {
|
|
properties {
|
|
property "sonar.projectKey", "TeamNewPipe_NewPipe"
|
|
property "sonar.organization", "teamnewpipe"
|
|
property "sonar.host.url", "https://sonarcloud.io"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
/** Desugaring **/
|
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
|
|
|
/** NewPipe libraries **/
|
|
// You can use a local version by uncommenting a few lines in settings.gradle
|
|
// Or you can use a commit you pushed to GitHub by just replacing TeamNewPipe with your GitHub
|
|
// name and the commit hash with the commit hash of the (pushed) commit you want to test
|
|
// This works thanks to JitPack: https://jitpack.io/
|
|
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
|
|
implementation 'com.github.TeamNewPipe:NewPipeExtractor:1b51eab664ec7cbd2295c96d8b43000379cd1b7b'
|
|
|
|
/** Checkstyle **/
|
|
checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
|
|
ktlint 'com.pinterest:ktlint:0.44.0'
|
|
|
|
/** Kotlin **/
|
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlin_version}"
|
|
|
|
/** AndroidX **/
|
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
|
implementation 'androidx.cardview:cardview:1.0.0'
|
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
|
implementation 'androidx.core:core-ktx:1.6.0'
|
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
|
implementation 'androidx.fragment:fragment-ktx:1.3.6'
|
|
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
|
|
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
|
|
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
|
|
implementation 'androidx.media:media:1.5.0'
|
|
implementation 'androidx.multidex:multidex:2.0.1'
|
|
implementation 'androidx.preference:preference:1.2.0'
|
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
|
implementation "androidx.room:room-runtime:${androidxRoomVersion}"
|
|
implementation "androidx.room:room-rxjava3:${androidxRoomVersion}"
|
|
kapt "androidx.room:room-compiler:${androidxRoomVersion}"
|
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
|
// Newer version specified to prevent accessibility regressions with RecyclerView, see:
|
|
// https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-alpha01
|
|
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
|
implementation 'androidx.webkit:webkit:1.4.0'
|
|
implementation "androidx.work:work-runtime-ktx:${androidxWorkVersion}"
|
|
implementation "androidx.work:work-rxjava3:${androidxWorkVersion}"
|
|
implementation 'com.google.android.material:material:1.5.0'
|
|
|
|
/** Third-party libraries **/
|
|
// Instance state boilerplate elimination
|
|
implementation "frankiesardo:icepick:${icepickVersion}"
|
|
kapt "frankiesardo:icepick-processor:${icepickVersion}"
|
|
|
|
// HTML parser
|
|
implementation "org.jsoup:jsoup:1.14.3"
|
|
|
|
// HTTP client
|
|
//noinspection GradleDependency --> do not update okhttp to keep supporting Android 4.4 users
|
|
implementation "com.squareup.okhttp3:okhttp:3.12.13"
|
|
|
|
// Media player
|
|
implementation "com.google.android.exoplayer:exoplayer:${exoPlayerVersion}"
|
|
implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerVersion}"
|
|
|
|
// Metadata generator for service descriptors
|
|
compileOnly "com.google.auto.service:auto-service-annotations:${googleAutoServiceVersion}"
|
|
kapt "com.google.auto.service:auto-service:${googleAutoServiceVersion}"
|
|
|
|
// Manager for complex RecyclerView layouts
|
|
implementation "com.github.lisawray.groupie:groupie:${groupieVersion}"
|
|
implementation "com.github.lisawray.groupie:groupie-viewbinding:${groupieVersion}"
|
|
|
|
// Image loading
|
|
//noinspection GradleDependency --> 2.8 is the last version, not 2.71828!
|
|
implementation "com.squareup.picasso:picasso:2.8"
|
|
|
|
// Markdown library for Android
|
|
implementation "io.noties.markwon:core:${markwonVersion}"
|
|
implementation "io.noties.markwon:linkify:${markwonVersion}"
|
|
|
|
// File picker
|
|
implementation "com.nononsenseapps:filepicker:4.2.1"
|
|
|
|
// Crash reporting
|
|
implementation "ch.acra:acra-core:5.9.3"
|
|
|
|
// Properly restarting
|
|
implementation 'com.jakewharton:process-phoenix:2.1.2'
|
|
|
|
// Reactive extensions for Java VM
|
|
implementation "io.reactivex.rxjava3:rxjava:3.0.13"
|
|
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
|
|
// RxJava binding APIs for Android UI widgets
|
|
implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0"
|
|
|
|
// Date and time formatting
|
|
implementation "org.ocpsoft.prettytime:prettytime:5.0.2.Final"
|
|
|
|
/** Debugging **/
|
|
// Memory leak detection
|
|
implementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}"
|
|
implementation "com.squareup.leakcanary:plumber-android:${leakCanaryVersion}"
|
|
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}"
|
|
// Debug bridge for Android
|
|
debugImplementation "com.facebook.stetho:stetho:${stethoVersion}"
|
|
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}"
|
|
|
|
/** Testing **/
|
|
testImplementation 'junit:junit:4.13.2'
|
|
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
|
|
testImplementation "org.mockito:mockito-inline:${mockitoVersion}"
|
|
|
|
androidTestImplementation "androidx.test.ext:junit:1.1.3"
|
|
androidTestImplementation "androidx.test:runner:1.4.0"
|
|
androidTestImplementation "androidx.room:room-testing:${androidxRoomVersion}"
|
|
androidTestImplementation "org.assertj:assertj-core:${assertJVersion}"
|
|
}
|
|
|
|
static String getGitWorkingBranch() {
|
|
try {
|
|
def gitProcess = "git rev-parse --abbrev-ref HEAD".execute()
|
|
gitProcess.waitFor()
|
|
if (gitProcess.exitValue() == 0) {
|
|
return gitProcess.text.trim()
|
|
} else {
|
|
// not a git repository
|
|
return ""
|
|
}
|
|
} catch (IOException ignored) {
|
|
// git was not found
|
|
return ""
|
|
}
|
|
}
|