From b9ff445268b5d9bd064609260b83cc493c300548 Mon Sep 17 00:00:00 2001 From: Damontecres Date: Mon, 27 Jul 2026 18:42:58 -0400 Subject: [PATCH] Add mpv-stub --- .github/workflows/pr.yml | 3 --- DEVELOPMENT.md | 10 +++++++ app/build.gradle.kts | 1 + app/mpv-stub/.gitignore | 1 + app/mpv-stub/README.md | 5 ++++ app/mpv-stub/build.gradle.kts | 25 +++++++++++++++++ app/mpv-stub/consumer-rules.keep | 0 app/mpv-stub/src/main/AndroidManifest.xml | 4 +++ .../damontecres/wholphin/mpv/MpvPlayer.kt | 27 +++++++++++++++++++ app/mpv-stub/src/main/keepRules/rules.keep | 12 +++++++++ build.gradle.kts | 1 + gradle/libs.versions.toml | 4 +++ settings.gradle.kts | 1 + 13 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 app/mpv-stub/.gitignore create mode 100644 app/mpv-stub/README.md create mode 100644 app/mpv-stub/build.gradle.kts create mode 100644 app/mpv-stub/consumer-rules.keep create mode 100644 app/mpv-stub/src/main/AndroidManifest.xml create mode 100644 app/mpv-stub/src/main/java/com/github/damontecres/wholphin/mpv/MpvPlayer.kt create mode 100644 app/mpv-stub/src/main/keepRules/rules.keep diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e04fb7699..0bbf773d4 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -44,9 +44,6 @@ jobs: ./gradlew clean assembleDebug testDebugUnitTest --no-daemon apks=$(find app/build/outputs/apk -name '*.apk' -print0 | tr '\0' ',' | sed 's/,$//') echo "apks=$apks" >> "$GITHUB_OUTPUT" - env: - ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}" - ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}" - name: Tar build dirs run: | tar -czf build.tgz ./app/. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index ee1cffef9..934642e85 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -78,6 +78,16 @@ The app uses [media3's `ExoPlayer`](https://github.com/androidx/media) for playb In the legacy UI, the `PlaybackFragment` abstract class handles most of the playback logic. +#### Extensions + +There are several native components for extra playback compatibility. This includes Media3 ffmpeg/av1 decoders and `libmpv`. These extensions are not required to build the app, but without them some functionality will not work. + +If you want to include these in a local build, see the [instructions here](https://github.com/damontecres/wholphin-extensions?tab=readme-ov-file#usage) for configuring the repository. + +You can also build the extensions locally from https://github.com/damontecres/wholphin-extensions and include them in `app/libs`. The gradle build dependency resolution prefers these local files over fetching from the remote maven registry. + +Finally, if no `wholphin-mpv` implementation is found, `:app:mpv-stub` will be used. This allows the app to compile, but any runtime usage of MPV will throw an exception. + ### Image loading The app uses [Coil](https://coil-kt.github.io/coil/) for image loading for composables. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6a0e8f5dc..a2ef1fb91 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -345,6 +345,7 @@ dependencies { implementation(libs.wholphin.extensions.mpv) } else { logger.warn("libMPV was NOT found") + implementation(project(":app:mpv-stub")) } testImplementation(libs.androidx.test.core.ktx) diff --git a/app/mpv-stub/.gitignore b/app/mpv-stub/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/app/mpv-stub/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/mpv-stub/README.md b/app/mpv-stub/README.md new file mode 100644 index 000000000..e09d87908 --- /dev/null +++ b/app/mpv-stub/README.md @@ -0,0 +1,5 @@ +# mpv-stub + +This is a stub library for [`wholphin-mpv`](https://github.com/damontecres/wholphin-extensions/tree/main/wholphin-mpv). This allows for compiling the app without including the full MPV implementation, but any runtime usage will throw an exception. + +See [DEVELOPMENT.md](../../DEVELOPMENT.md) for details on how to include the full implementation in local builds. diff --git a/app/mpv-stub/build.gradle.kts b/app/mpv-stub/build.gradle.kts new file mode 100644 index 000000000..0efef3fcb --- /dev/null +++ b/app/mpv-stub/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + alias(libs.plugins.android.library) +} + +android { + namespace = "com.github.damontecres.stashapp.mpvstub" + compileSdk { + version = release(36) + } + + defaultConfig { + minSdk = 23 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.media3.common) +} diff --git a/app/mpv-stub/consumer-rules.keep b/app/mpv-stub/consumer-rules.keep new file mode 100644 index 000000000..e69de29bb diff --git a/app/mpv-stub/src/main/AndroidManifest.xml b/app/mpv-stub/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8bdb7e14b --- /dev/null +++ b/app/mpv-stub/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/mpv-stub/src/main/java/com/github/damontecres/wholphin/mpv/MpvPlayer.kt b/app/mpv-stub/src/main/java/com/github/damontecres/wholphin/mpv/MpvPlayer.kt new file mode 100644 index 000000000..4d2d8bfbf --- /dev/null +++ b/app/mpv-stub/src/main/java/com/github/damontecres/wholphin/mpv/MpvPlayer.kt @@ -0,0 +1,27 @@ +package com.github.damontecres.wholphin.mpv + +import android.content.Context +import android.os.Looper +import androidx.annotation.OptIn +import androidx.media3.common.SimpleBasePlayer +import androidx.media3.common.util.UnstableApi + +/** + * Stub implementation to allow for compiling + * + * See DEVELOPMENT.md for instructions on including the actual implementation in a build + */ +@OptIn(UnstableApi::class) +class MpvPlayer( + private val context: Context, + private val enableHardwareDecoding: Boolean, + private val useGpuNext: Boolean, +) : SimpleBasePlayer(Looper.getMainLooper()) { + init { + throw UnsupportedOperationException("mpv-stub has no runtime functionality!") + } + + val isReleased: Boolean get() = throw UnsupportedOperationException("mpv-stub has no runtime functionality!") + + override fun getState(): State = throw UnsupportedOperationException("mpv-stub has no runtime functionality!") +} diff --git a/app/mpv-stub/src/main/keepRules/rules.keep b/app/mpv-stub/src/main/keepRules/rules.keep new file mode 100644 index 000000000..58c9e5014 --- /dev/null +++ b/app/mpv-stub/src/main/keepRules/rules.keep @@ -0,0 +1,12 @@ +# Add project specific R8 rules here. +# AGP will combine all keep rule files in src/main/keepRules to pass to R8 +# +# For more details, see +# https://d.android.com/r/tools/r8/keep-rules + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/build.gradle.kts b/build.gradle.kts index 0097d47db..c8898e2e6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,4 +4,5 @@ plugins { alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.android.library) apply false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8fcb58402..0311db2e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,6 +54,8 @@ zoomlayout = "1.9.0" slf4j2Timber = "1.2" timber = "5.0.1" wholphin-extensions = "0.2.1" +espressoCore = "3.7.0" +appcompat = "1.7.1" [libraries] acra-dialog = { module = "ch.acra:acra-dialog", version.ref = "acra" } @@ -82,6 +84,7 @@ androidx-leanback-tab = { module = "androidx.leanback:leanback-tab", version.ref androidx-leanback-grid = { module = "androidx.leanback:leanback-grid", version.ref = "leanback-grid" } androidx-media3-effect = { module = "androidx.media3:media3-effect", version.ref = "androidx-media3" } androidx-media3-datasource-okhttp = { module = "androidx.media3:media3-datasource-okhttp", version.ref = "androidx-media3" } +androidx-media3-common = { module = "androidx.media3:media3-common", version.ref = "androidx-media3" } androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "androidx-media3" } androidx-media3-exoplayer-dash = { module = "androidx.media3:media3-exoplayer-dash", version.ref = "androidx-media3" } androidx-media3-exoplayer-hls = { module = "androidx.media3:media3-exoplayer-hls", version.ref = "androidx-media3" } @@ -156,3 +159,4 @@ kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization" ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } room = { id = "androidx.room", version.ref = "room" } protobuf = { id = "com.google.protobuf", version.ref = "protobuf" } +android-library = { id = "com.android.library", version.ref = "android-application" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 031f0939c..02c51fca9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,3 +28,4 @@ include(":app") gradle.startParameter.excludedTaskNames.addAll(listOf(":buildSrc:testClasses")) include(":apollo-compiler") +include(":app:mpv-stub")