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.
5.9 KiB
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'sNavDisplay, butentryProvider { }block is empty. No screens registered.navigation/Screen.kt— sealed interface with zero subclasses.di/KoinApp.kt— bare@KoinApplication object KoinAppwith 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 (separatecommonMaininterface +androidMain/jvmMain/iosMainimpls).
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
commonMainfor KMP. Lives in:appand would needandroidMain/jvmMainsource 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-rx3show 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()ononPositionDiscontinuity/period-update callbacks. API: SHA-256 prefix lookup atsponsor.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":
- Compose-native from day 1 (vs. PipePipe/Tubular which are still on Fragment+XML legacy). Smaller, faster, easier to maintain.
- Media3 ExoPlayer (vs. NewPipe's legacy ExoPlayer 2).
- Ktor-based clients for SB/RYD in
commonMain— KMP-ready for the day someone ports the extractor. - First-class settings sync via our existing Sulkta auth (Authentik OIDC) for cross-device subscriptions/history. None of the existing forks do this.
- Sulkta-Coop signing cert — joins the rest of our app family with consistent signature.