v0.1.0-X (vc=12): revert to NewPipeExtractor for working playback

Phase U (rustypipe Rust extractor) rolled back. Symptom: black screen
on play, root cause: rustypipe 0.11.4's JS deobfuscator can't parse
current YouTube player.js (YT changed the obfuscation pattern, no
upstream rustypipe release since June 2025). Switching clients
(Web → TV → Android/Ios) didn't help — the deobfuscator init fires
universally.

Kept in place for the future:
- rust/strawcore/ Cargo workspace + UniFFI scaffolding
- build-host runtime install (rustup + 4 Android targets +
  cargo-ndk + NDK r27c)
- The U-2..U-5 commits in history (re-runnable when rustypipe is
  fixed or we fork it).

Restored from commit 9c4b3f831 (v0.1.0-T):
- NewPipe.init() in StrawApp.onCreate
- libs.newpipe.extractor + libs.squareup.okhttp deps
- NewPipeDownloader.kt + Thumbnails.kt
- ViewModels (Search/VideoDetail/Player/Channel/SubscriptionFeed) on
  NewPipeExtractor calls
- VideoDetailScreen Download dialog using NewPipe's StreamInfo

Future-direction memo: openclaw-workspace/memory/project_rustypipe_fork.md
— fork plan + revival path for the Rust extractor when we're ready
to maintain it.

Verified working in the Android emulator: dQw4w9WgXcQ plays, ExoPlayer
reports state=PLAYING(3), position advancing, video surface rendering.
This commit is contained in:
Sulkta 2026-05-24 09:54:59 -07:00
parent 04b0a8dbe9
commit cc3585549a
17 changed files with 356 additions and 304 deletions

View file

@ -94,8 +94,8 @@ dependencies {
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
// Phase U-5: NewPipeExtractor (Java) torn out — strawcore handles
// all YT extraction. OkHttp stays for RYD + SponsorBlock JSON clients.
// NewPipeExtractor (JVM/Android-only) + its OkHttp dep
implementation(libs.newpipe.extractor)
implementation(libs.squareup.okhttp)
// JSON for SponsorBlock + Return YouTube Dislike clients
@ -110,98 +110,4 @@ dependencies {
implementation("androidx.media3:media3-session:1.4.1")
// Guava ListenableFuture support for awaiting MediaController connect.
implementation("androidx.concurrent:concurrent-futures-ktx:1.2.0")
// strawcore — Rust YouTube extractor via UniFFI/JNA. Built by the
// cargoBuild + uniffiBindgen tasks below; phase U-2+ exposes search /
// streamInfo / channelInfo to replace NewPipeExtractor.
implementation("net.java.dev.jna:jna:5.14.0@aar")
}
// =============================================================================
// Phase U-1 — Rust core build glue.
//
// Two tasks chain into the Android build:
// cargoBuild — cross-compiles rust/strawcore for the four Android ABIs
// via cargo-ndk and drops the .so files in strawApp/src/main/jniLibs/.
// uniffiBindgen — generates the Kotlin bindings from the freshly-built lib
// into strawApp/src/main/java/uniffi/strawcore/.
//
// Both depend on:
// - cargo + rustup with the four Android targets installed
// - cargo-ndk on PATH
// - ANDROID_NDK_HOME pointing at an NDK with the right toolchains
// All of that lives in the build-host container (see internal-infra
// containers/build-host/Dockerfile + ad-hoc install notes 2026-05-24).
// =============================================================================
val rustRoot = file("../rust").absolutePath
val jniLibsDir = file("src/main/jniLibs").absolutePath
val bindingsDir = file("src/main/java").absolutePath
// Resolve cargo + the NDK by absolute path so the Gradle Exec tasks don't
// depend on whatever PATH the user invoked gradle with. Fall back to env
// var (CARGO_HOME) if set, else the build-host default.
val cargoHome: String = System.getenv("CARGO_HOME") ?: "/caches/cargo"
val cargoBin: String = "$cargoHome/bin/cargo"
val ndkHome: String = System.getenv("ANDROID_NDK_HOME")
?: System.getenv("ANDROID_NDK_ROOT")
?: "/caches/android-sdk/ndk/27.2.12479018"
val cargoBuild by tasks.registering(Exec::class) {
group = "rust"
description = "Cross-compile strawcore for all Android ABIs via cargo-ndk."
workingDir = file(rustRoot)
environment("ANDROID_NDK_HOME", ndkHome)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(
cargoBin, "ndk",
"-t", "arm64-v8a",
"-t", "armeabi-v7a",
"-t", "x86",
"-t", "x86_64",
"-o", jniLibsDir,
"build", "--release", "-p", "strawcore",
)
standardOutput = System.out
errorOutput = System.err
}
// Build a host-arch debug .so for uniffi-bindgen to read metadata from.
// Cross-compiled Android .so files have the same UniFFI metadata symbols,
// but the release profile's strip+LTO can strip the sections in a way that
// trips bindgen's library-mode reader. Build host debug separately.
val cargoBuildHost by tasks.registering(Exec::class) {
group = "rust"
description = "Build host-arch debug strawcore so bindgen can read its UniFFI metadata."
workingDir = file(rustRoot)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(cargoBin, "build", "-p", "strawcore")
standardOutput = System.out
errorOutput = System.err
}
val uniffiBindgen by tasks.registering(Exec::class) {
group = "rust"
description = "Generate Kotlin bindings for strawcore via uniffi-bindgen."
dependsOn(cargoBuildHost)
workingDir = file(rustRoot)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(
cargoBin, "run", "--quiet", "--bin", "uniffi-bindgen", "--",
"generate",
"--library", "target/debug/libstrawcore.so",
"--crate", "strawcore",
"--language", "kotlin",
"--no-format",
"--out-dir", bindingsDir,
)
standardOutput = System.out
errorOutput = System.err
}
// Make sure Android's JNI-libs merge picks up the freshly built .so files,
// and Kotlin compilation can resolve the generated bindings.
tasks.matching { it.name.startsWith("merge") && it.name.endsWith("JniLibFolders") }
.configureEach { dependsOn(cargoBuild) }
tasks.matching { it.name.startsWith("compile") && it.name.endsWith("Kotlin") }
.configureEach { dependsOn(uniffiBindgen) }