straw/rust
Cobb ad4341543c chore: write emoji and button glyphs in code comments as words
Comments named on-screen buttons by a glyph; they now say the button's
name: the fullscreen button (5 places), the down-arrow overlay button,
the close button on the minibar (4 places, plus "the X button" for the
downloads row), the background-audio (headphones) button and the
picture-in-picture overlay button. The changelog in ProjectConfig.kt
is history and keeps its meaning.

Also: no crab in hello_from_rust's returned text (nothing in the app
calls it), plain names in the GitHub issue-template links ("Question",
"Matrix chat", "IRC chat"), "Warning:" in place of the warning sign in
the pull request template, and no kaomoji at the end of the en-US store
changelog 70.

Not touched: punctuation (em dashes, arrows in prose, bullets, the
folder trees), the multiplication sign where it means "times", the
copyright sign in the vendored gradlew, and the symbols straw draws on
screen, which the next commit replaces with Material icons.
2026-11-04 21:42:57 -08:00
..
strawcore chore: write emoji and button glyphs in code comments as words 2026-11-04 21:42:57 -08:00
Cargo.lock diag: expand dogfood logging — lighter scrub + always-log failures + wrapper catch-all 2026-08-06 08:17:15 -07:00
Cargo.toml speed(wrapper): opt-level=2 for the JS-interpreter crates (S5) 2026-07-29 08:25:47 -07:00
README.md Public-flip audit: scrub audit-ticket prefixes + internal references + tighten README 2026-05-27 13:29:53 -07:00

rust/ — strawcore: Rust YouTube core for Straw

Phase U- of the Straw build. Goal: replace the Java NewPipeExtractor dependency with a Rust core (rustypipe + tokio + reqwest), exposed to the Kotlin/Compose UI via UniFFI. Compose UI stays in Kotlin — only the YouTube/Innertube fetching layer moves to Rust.

Phases

Phase What
U-1 Toolchain + UniFFI smoke test (hello_from_rust) round-tripping through JNA. No real APIs yet.
U-2 rustypipe search. SearchViewModel calls the Rust core.
U-3 rustypipe streamInfo + streams. VideoDetailViewModel + PlayerViewModel use it.
U-4 rustypipe channel + tabs. ChannelViewModel + SubscriptionFeedViewModel.
U-5 Rip NewPipeExtractor Java dep. Measure APK + cold-fetch latency before/after.
U-6 (stretch) SponsorBlock + RYD HTTP through reqwest + tokio in the same lib.

Build chain

Build container (Sulkta uses one; any toolchain matching this layout works)
├── rustup stable (target add: aarch64-linux-android, armv7-linux-androideabi,
│                  x86_64-linux-android, i686-linux-android)
├── cargo-ndk      (cross-compile helper)
├── android-sdk    (ANDROID_HOME, sdkmanager, build-tools, platforms)
└── android-ndk    (ANDROID_NDK_HOME, r27c LTS)

Gradle (strawApp/build.gradle.kts)
├── cargoBuild         Exec task → cargo ndk -t <abi>... -o jniLibs/ build --release
├── uniffiBindgen      Exec task → cargo run --bin uniffi-bindgen ... --library libstrawcore.so
└── source-set wiring  generated Kotlin lands in strawApp/src/main/java/uniffi/strawcore/

Runtime (StrawApp.onCreate)
├── System.loadLibrary("strawcore")
└── uniffi.strawcore.initLogging()

Why UniFFI (and not raw JNI / JNA bindings)

  • Hand-written JNI: tedious, error-prone, every type change is two files (Kotlin + Rust) that must stay in sync.
  • Raw JNA: better, but you still hand-write the Kotlin side and worry about string ownership.
  • UniFFI: write Rust, annotate with #[uniffi::export], get a Kotlin shim generated. Strings, structs, enums, Result types, async functions all cross the boundary transparently. The runtime is JNA under the hood.

When in doubt

  • cargo check -p strawcore --target aarch64-linux-android — fast iteration.
  • cargo run --bin uniffi-bindgen -- generate ... — regenerate Kotlin bindings.
  • adb logcat -s strawcore — Rust log::info!() lands here.
  • aapt dump badging strawApp/build/outputs/apk/debug/strawApp-debug.apk — inspect what ABIs/native-libs the APK carries.