Initial Sulkta fork of NewPipe with a new :strawApp module that ships a clean Compose-based Android APK at applicationId com.sulkta.straw. What's here: - :strawApp — thin Android application shell, MaterialTheme + StrawHome Composable. Lives alongside legacy :app so we don't break upstream. - buildSrc — STRAW_APPLICATION_ID/VERSION constants alongside the existing NEWPIPE_APPLICATION_ID_OLD/NEW. - docs/sulkta — RECON.md (NewPipe codebase breakdown) + DECISIONS.md (stack + scope decisions). NewPipe's :shared KMP scaffold is at 892 LOC and renders nothing; this fork picks up there and races ahead. Day-1 ships a hello APK; day-2 wires NewPipeExtractor + Media3 player + SponsorBlock + Return YouTube Dislike. GPL-3.0-or-later per upstream.
130 lines
5.9 KiB
Markdown
130 lines
5.9 KiB
Markdown
# NewPipe recon — 2026-05-23
|
|
|
|
Clone: `/root/build/newpipe-recon/` (shallow clone of upstream master 94005cf).
|
|
|
|
## TL;DR
|
|
|
|
NewPipe is **mid-migration to Kotlin Multiplatform + Compose Multiplatform**, but
|
|
the new app is at literal day-zero. Of 4 modules, only `:app` (the legacy
|
|
Android app) actually works. `:shared` has 892 LOC of scaffolding but zero
|
|
screens. `:desktopApp` is an 18-line stub. `:iosApp` has 0 lines of Kotlin.
|
|
|
|
The "fork the legacy app and modernize it" angle is dead — they're modernizing.
|
|
The actual opening is: **pick up the abandoned-looking KMP scaffold and execute
|
|
the next year of work in a day's worth of vertical-slice ambition.** Bake in
|
|
SponsorBlock + RYD as first-class while we're at it.
|
|
|
|
## Module breakdown
|
|
|
|
| Module | LOC | Kt files | Java files | Status |
|
|
|---|---:|---:|---:|---|
|
|
| `:app` (legacy `NEWPIPE_APPLICATION_ID_OLD`) | 82,427 | 173 | 295 | What users run as v0.28.6 |
|
|
| `:shared` (KMP, `NEWPIPE_APPLICATION_ID_NEW`) | 892 | 21 | 0 | **Hello-world stage, zero screens** |
|
|
| `:desktopApp` | 18 | 1 | 0 | `Main.kt` stub only |
|
|
| `:iosApp` | 0 | 0 | 0 | Xcode shell only |
|
|
|
|
### `:shared` current state
|
|
|
|
`shared/src/commonMain/kotlin/net/newpipe/app/` contains:
|
|
|
|
- `App.kt` — `@Composable fun App(...)` that sets up Koin + `AppTheme {}` with
|
|
an **empty body**. The KMP app literally renders nothing.
|
|
- `Constants.kt` — empty file-level constants.
|
|
- `navigation/NavDisplay.kt` — wraps androidx-nav3's `NavDisplay`, but
|
|
`entryProvider { }` block is empty. **No screens registered.**
|
|
- `navigation/Screen.kt` — sealed interface with **zero subclasses**.
|
|
- `di/KoinApp.kt` — bare `@KoinApplication object KoinApp` with no modules.
|
|
- `composable/TopAppBar.kt` — basic top bar.
|
|
- `theme/` — Color, ServiceTheme, Theme. Solid Material 3 scaffolding.
|
|
- `preview/ThemePreviewProvider.kt` — Compose preview helper.
|
|
- `di/settings/SettingsModule.kt` — multiplatform settings DI (separate
|
|
`commonMain` interface + `androidMain`/`jvmMain`/`iosMain` impls).
|
|
|
|
That's it. The entire new app is theme + navigation primitive + Koin stub.
|
|
|
|
### `:shared/androidMain`
|
|
|
|
- `ComposeActivity.kt` — Android entry that hosts the Compose UI.
|
|
- `Constants.kt` — Android-specific constants.
|
|
- `extensions/Context.kt` — extension utilities.
|
|
|
|
## Stack (already chosen by NewPipe, modern as of 2026)
|
|
|
|
| Layer | Pick | Version | Notes |
|
|
|---|---|---|---|
|
|
| Language | Kotlin | 2.3.21 | Bleeding edge |
|
|
| UI | Jetpack Compose + Compose Multiplatform | 1.11.1 | Material3 1.11.0-alpha07 |
|
|
| Build | AGP | 9.2.1 | Latest |
|
|
| Nav | androidx-navigation3 | 1.1.1 | Type-safe, KMP-friendly |
|
|
| DI | Koin | 4.2.1 | Annotation-driven via koin-plugin |
|
|
| Async | kotlinx.coroutines | 1.11.0 | Plus kotlinx-coroutines-rx3 bridge to legacy |
|
|
| Serialization | kotlinx.serialization | 1.11.0 | JSON, parcelable replacement |
|
|
| Image loading | Coil 3 | 3.4.0 | KMP-native via coil-network-okhttp |
|
|
| HTTP | OkHttp | 5.3.2 | Android, used by extractor |
|
|
| DB | Room | 2.8.4 | Android-only, KMP-incompatible (legacy app) |
|
|
| Player | ExoPlayer 2.19.1 | — | **Stale.** Should be `androidx.media3` ≥ 1.4 |
|
|
| Crash | ACRA | 5.13.1 | Send-to-self crash reporter |
|
|
| Leak detection | LeakCanary | 2.14 | Debug builds only |
|
|
|
|
## Critical dependency: `NewPipeExtractor`
|
|
|
|
- `teamnewpipe-newpipe-extractor = "v0.26.2"` pulled from JitPack
|
|
- **JVM-only.** Uses Jsoup + nanojson + Java HTTP.
|
|
- Cannot live in `commonMain` for KMP. Lives in `:app` and would need
|
|
`androidMain` / `jvmMain` source sets in `:shared`.
|
|
- **This is why their KMP migration is slow** — porting the extractor to KMP
|
|
is the actual big yak. They haven't started it.
|
|
|
|
For our fork: same constraint applies. Android-only target for day-1; KMP
|
|
extractor port is a separate (multi-week) project.
|
|
|
|
## What's actively being deprecated
|
|
|
|
NewPipe's own codebase has TODOs and migrations in flight:
|
|
- RxJava 3 → coroutines (bridges via `kotlinx-coroutines-rx3` show partial)
|
|
- ExoPlayer 2 → Media3 (still on legacy)
|
|
- Fragment + ViewBinding → Compose (the LeakScope findings live in this layer)
|
|
- Material 1 → Material 3 (mid-migration; `material = "1.11.0" # TODO: update`)
|
|
- KSP2 incompatibility flagged on `statesaver`
|
|
- Apache commons in `app/src/main/java/org/apache/commons/` — vendored, would
|
|
go away in KMP world
|
|
|
|
## Where to hook SponsorBlock + Return YouTube Dislike
|
|
|
|
For a from-scratch new app:
|
|
|
|
- **SponsorBlock**: ExoPlayer/Media3 player listener that consumes a list of
|
|
segments fetched at video resolution time. Skip via `player.seekTo()` on
|
|
`onPositionDiscontinuity`/period-update callbacks. API: SHA-256 prefix
|
|
lookup at `sponsor.ajay.app/api/skipSegments/<prefix>`.
|
|
- **Return YouTube Dislike**: HTTP GET to
|
|
`returnyoutubedislike.com/votes?videoId=<id>`. Render in video detail screen
|
|
next to the like count. No player integration needed.
|
|
|
|
Both clients can live in `:shared/commonMain` using **Ktor client** (KMP HTTP).
|
|
That makes them iOS/desktop-ready once an extractor port exists.
|
|
|
|
## Existing forks doing the same thing
|
|
|
|
Surfaced from NewPipe issue thread #13512:
|
|
- **PipePipe** — fork with SponsorBlock + RYD. Active.
|
|
- **Tubular** — fork with SponsorBlock + RYD. Active.
|
|
- **YouPipe** — fork with extra features.
|
|
- **SkyTube** — separate Android YouTube app, not NewPipe-based.
|
|
|
|
So this isn't novel territory. We're doing it for the build experience
|
|
(element-x energy), not to fill a market gap.
|
|
|
|
## Differentiators we could pursue
|
|
|
|
If we want to be more than "another fork":
|
|
|
|
1. **Compose-native from day 1** (vs. PipePipe/Tubular which are still on
|
|
Fragment+XML legacy). Smaller, faster, easier to maintain.
|
|
2. **Media3 ExoPlayer** (vs. NewPipe's legacy ExoPlayer 2).
|
|
3. **Ktor-based clients** for SB/RYD in `commonMain` — KMP-ready for the day
|
|
someone ports the extractor.
|
|
4. **First-class settings sync** via our existing Sulkta auth (Authentik OIDC)
|
|
for cross-device subscriptions/history. None of the existing forks do this.
|
|
5. **Sulkta-Coop signing cert** — joins the rest of our app family with
|
|
consistent signature.
|