Sulkta day-2: search → detail → player → SponsorBlock + RYD

Phase A: NewPipeExtractor + OkHttp Downloader wired in. Search bar +
LazyColumn results. Tap = navigate to detail.

Phase B: VideoDetail screen — StreamInfo metadata + Return YouTube
Dislike chips + description.

Phase C: Media3 ExoPlayer in Compose. Resolves StreamInfo to best
playable: DASH MPD → HLS → combined progressive → merged
videoOnly+audio.

Phase D: SponsorBlock SHA-256 prefix lookup. 250ms position-poll loop
inside PlayerScreen — exoPlayer.seekTo(segment.end) when entering
a sponsor segment. Toast on skip.

Phase E: Verified live on Android 14 emulator. linus tech tips search
returns real results with thumbnails; tapped result opens detail;
hit Play → video plays through ExoPlayer.

Architecture: everything in :strawApp for now (not pushed into :shared
yet — KMP refactor is day-3). Pure-state nav (sealed Screen + stack,
no nav library).

Known polish gaps (day-3): RYD chips render empty on some videos,
description has raw HTML (markdown render needed), no Koin DI yet,
no persistence.

GPL-3.0-or-later per upstream NewPipe.
This commit is contained in:
Sulkta 2026-05-23 19:22:52 -07:00
parent c8f6c0fe21
commit c30c171c91
15 changed files with 1046 additions and 6 deletions

View file

@ -2,8 +2,11 @@
* SPDX-FileCopyrightText: 2026 Sulkta
* SPDX-License-Identifier: GPL-3.0-or-later
*
* :strawApp — thin Android application shell around :shared (the KMP Compose
* code). Lives alongside the legacy :app module so we don't break it.
* :strawApp — thin Android application shell. Day-2: pulls NewPipeExtractor,
* Media3, Ktor-style HTTP-via-OkHttp + kotlinx-serialization JSON for the
* search → detail → player → SponsorBlock + RYD flow. We keep our deps in
* this module, NOT in the shared libs.versions.toml, so upstream NewPipe
* stays cleanly mergeable.
*/
import com.android.build.api.dsl.ApplicationExtension
@ -56,13 +59,50 @@ configure<ApplicationExtension> {
buildConfig = true
resValues = true
}
packaging {
resources {
excludes += setOf(
"META-INF/README.md",
"META-INF/CHANGES",
"META-INF/COPYRIGHT",
"META-INF/INDEX.LIST",
"META-INF/io.netty.versions.properties",
)
}
}
}
dependencies {
// Compose + AndroidX core
implementation(libs.androidx.activity)
implementation(libs.androidx.core)
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.foundation)
implementation(libs.jetbrains.compose.material3)
implementation(libs.jetbrains.compose.ui)
// Lifecycle + ViewModel for Compose
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.10.0")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0")
// Image loading
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
// NewPipeExtractor (JVM/Android-only) + its OkHttp dep
implementation(libs.newpipe.extractor)
implementation(libs.squareup.okhttp)
// JSON for SponsorBlock + Return YouTube Dislike clients
implementation(libs.kotlinx.serialization.json)
// Media3 ExoPlayer
implementation("androidx.media3:media3-exoplayer:1.4.1")
implementation("androidx.media3:media3-exoplayer-dash:1.4.1")
implementation("androidx.media3:media3-exoplayer-hls:1.4.1")
implementation("androidx.media3:media3-ui:1.4.1")
}