Phase P — bottom navigation:
- StrawHome restructured as a Scaffold with Material3 NavigationBar.
- Three tabs: Home (search + last 10 watches), Library (full watch
history with count), Subs (channel chips + aggregated feed).
Phase Q — subscription feed:
- New SubscriptionFeedViewModel fans out per-channel ChannelInfo +
ChannelTabs.VIDEOS fetches in parallel via async/awaitAll.
- Each channel contributes top 5; merged across all subs, capped at
200, sorted by view count as a soft-recency proxy (extractor doesn't
reliably surface upload timestamps).
- 10-minute cache TTL avoids hammering YT on tab re-entry.
- Subs tab renders the feed below the avatar row with a Refresh button.
Phase R — download:
- Download button on VideoDetail (next to Play / Share). Pops a tiny
dialog: Audio (best audioStream) or Video (best videoStream/
videoOnly fallback).
- Uses Android's DownloadManager — saves into app-private external
files dir (Android/data/com.sulkta.straw.debug/files/Movies/<kind>/).
Notification + progress for free. No WRITE_EXTERNAL_STORAGE needed.
- Filenames sanitized (no /:*?\"<>| chars), capped at 120 chars.
Phase S — background audio:
- New "Background" overlay button (🎧) on the player. Tap to pause the
activity player and start PlaybackService with the audio URL.
- PlaybackService is a Media3 MediaSessionService with its own ExoPlayer
configured with our custom DataSource.Factory (User-Agent set, cross-
protocol redirects). Foreground service + media notification.
- Audio survives activity death — swipe the app out of recents, audio
keeps playing. Stop via notification or open-the-app-and-tap-stop.
- onTaskRemoved keeps the service alive iff something is playing.
Versions shipped: P+Q as vc=4, R as vc=5, S as vc=6. Each landed in the
F-Droid repo for the day-by-day refresh path.
Day-N+ ideas: real MediaController unification (single Player for both
foreground + background paths), MergingMediaSource on the service side
for high-res YT videos, real upload-timestamp sort for feed once the
extractor exposes it consistently, queue/playlist.
VideoDetail screen:
- New "Related" section at the bottom — pulls
StreamInfo.relatedItems, filters to StreamInfoItem, renders as
inline thumbnail rows. Tap → push another VideoDetail. Up to 20
items shown. Each row uses bestThumbnail() for hi-res.
Settings screen + PlayerViewModel:
- New "Playback" section with a Max-Resolution picker:
Auto / 1080p / 720p / 480p / 360p / 144p. Persisted to
SharedPreferences (KEY_MAX_RES) via SettingsStore.maxResolution
StateFlow.
- PlayerViewModel.resolve filters videoStreams + videoOnlyStreams by
the ceiling before picking the max-bitrate one. Auto (Int.MAX_VALUE)
is unchanged behavior. Choosing 720p caps the renderer so 1080p/4K
streams are skipped — saves bandwidth on mobile + helps low-end
decoders.
Phase P next ideas: bottom navigation tabs (Home / Subs feed /
Library), Download (audio + video), the MediaSessionService refactor
for true background audio after activity death.
Player overlay (top-right) now hosts four buttons in a row:
- Speed: 1× by default; tap opens a dialog of 0.25× / 0.5× / 0.75× / 1× /
1.25× / 1.5× / 1.75× / 2×. Applies via exoPlayer.playbackParameters.
- Audio-only toggle (📻/📺): toggles Player.TRACK_TYPE_VIDEO via
TrackSelectionParameters. Saves bandwidth + battery for screen-off
listening. Toast confirms state.
- Share (↗): Intent.ACTION_SEND with text/plain containing the YouTube
URL + the video title as EXTRA_SUBJECT. Hands off to Android share
sheet.
- PiP (⊟): same as M-1 but now part of the row instead of its own
floating square.
VideoDetail screen: Play button now lives in a Row with an OutlinedButton
"Share" that fires the same ACTION_SEND chooser. Same UX surface for
users who land on detail without going to player.
Version: STRAW_VERSION_CODE 1 → 2, STRAW_VERSION_NAME "0.1.0-day1" →
"0.1.0-N" so the F-Droid client sees this as an upgrade.
Phase O next (per Cobb's "where are all the features"): quality picker,
related videos on detail, download (audio + video).
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.
Move important version properties to buildSrc directory to access between modules
as needed.
Also add a simple task to generate a simple BuildConfig class to access version name.
This is better than adding dependency on a third-party library/plugin.
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>