enrich_feed_item now calls the new strawcore stream_metadata() path (Android /player + videoDetails read only) instead of the full stream_info. The full path ran the JS sig/nsig deobf, an extra WEB /player metadata round-trip, the iOS client, and stream/manifest/caption extraction — then kept only view_count + duration_seconds. Those two come from the same videoDetails the lightweight path reads (populate_microformat never touches them), so the values are identical; the feed just stops paying for the discarded work — ~one heavy round-trip dropped per enriched item per refresh. FFI surface (enrichFeedItem -> EnrichedFeedMetadata) unchanged. Needs strawcore 30f24d2 (pushed first; CI clones strawcore main).
154 lines
8.6 KiB
Kotlin
154 lines
8.6 KiB
Kotlin
/*
|
||
* SPDX-FileCopyrightText: 2026 Sulkta-Coop
|
||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||
*/
|
||
|
||
const val STRAW_SDK_COMPILE_MAJOR = 36
|
||
const val STRAW_SDK_COMPILE_MINOR = 1
|
||
const val STRAW_SDK_TARGET = 35
|
||
|
||
// Sulkta fork — Straw
|
||
//
|
||
// vc=82 / 0.1.0-CP — subscription-feed enrichment goes lightweight:
|
||
// * Filling in a feed row's view count + duration used to run the FULL
|
||
// stream extraction per item (the same path opening a video does):
|
||
// Android /player, the JS signature/nsig deobfuscation, an extra WEB
|
||
// /player metadata round-trip, plus stream/manifest/caption parsing —
|
||
// then threw all of it away except those two numbers. On a refresh
|
||
// that touched dozens of items that was dozens of redundant heavy
|
||
// round-trips.
|
||
// * Now it calls a new strawcore stream_metadata() path that does only
|
||
// the Android /player fetch + the videoDetails read those two fields
|
||
// come from, skipping the JS eval, the extra WEB round-trip, iOS, and
|
||
// stream extraction. The values are identical (they come from the same
|
||
// videoDetails the full path used), the feed just stops paying for
|
||
// work it discarded. (strawcore 30f24d2.)
|
||
//
|
||
// vc=81 / 0.1.0-CO — perf-audit app-side batch (no behavior change):
|
||
// * Search: the reactive cache-preview filter no longer runs on the
|
||
// main thread on every keystroke. It walked the entire cached-
|
||
// results pool (thousands of items on a heavy user) inline; now each
|
||
// keystroke debounces ~150ms and the scan runs on Dispatchers.Default.
|
||
// A submit cancels the pending preview so it can't clobber live
|
||
// results.
|
||
// * Subscription feed: the merge memoizes the relative-upload-date
|
||
// parse by string, so the recency regex runs once per distinct
|
||
// "N days ago" value instead of once per item (~3000 per merge on a
|
||
// 200-sub feed) — across hydration, every refresh, and each
|
||
// background-enrichment emit.
|
||
//
|
||
// vc=80 / 0.1.0-CN — strawcore extraction perf (Rust batch):
|
||
// * The extractor borrows the streamingData subtree out of the Android
|
||
// + iOS player responses instead of deep-cloning the largest part of
|
||
// each response, and merges format objects by reference rather than
|
||
// cloning all ~20-40 of them per video open.
|
||
// * Channel pages fetch their Home + Videos tabs concurrently, so
|
||
// opening a channel costs one network round-trip of latency instead
|
||
// of two.
|
||
// * Response bodies decode in place on the (overwhelmingly common)
|
||
// valid-UTF-8 path instead of always copying.
|
||
// No behavior change — purely allocation + latency wins in strawcore
|
||
// (strawcore 91d4824).
|
||
//
|
||
// vc=79 / 0.1.0-CM — perf-audit pass-2 (app-side slam-dunks):
|
||
// * FIX a wrong-thread crash: the headphone-disconnect settings watcher
|
||
// ran on the IO scope and touched the ExoPlayer (thread-affine to the
|
||
// Main thread it was built on) → "Player accessed on the wrong thread"
|
||
// latent on every session. Collector now runs on Dispatchers.Main.
|
||
// * recordSearch (json-encode + SharedPrefs write) moved off the Main
|
||
// thread into withContext(Dispatchers.IO).
|
||
//
|
||
// vc=78 / 0.1.0-CL — perf-audit batch 1 (app-side):
|
||
// * Autoplay-next no longer drops the user's max-resolution cap. The
|
||
// enter-video track-selection reset built params from scratch, wiping
|
||
// the data-saver ceiling on every URL change; now it re-enables the
|
||
// video track surgically + re-asserts applyMaxResolutionCap().
|
||
// * VideoDetail body is now a LazyColumn, not a verticalScroll Column.
|
||
// The related + more-from-channel lists recycle and defer each row's
|
||
// image decode + its two progress-overlay flow collectors until
|
||
// scrolled into view (was ~40 decodes + ~80 collectors mounted eagerly
|
||
// on every video open). Namespaced item keys; dialogs hoisted out.
|
||
//
|
||
// vc=77 / 0.1.0-CK — morph perf: static poster during collapse/morph:
|
||
// * The minibar + the whole collapse/expand morph now render the video's
|
||
// static poster, not the live TextureView. Scaling a live-playing
|
||
// TextureView through the morph's graphicsLayer every frame was the
|
||
// remaining sluggishness; the live PlayerView only mounts once settled
|
||
// fully expanded. Audio is unaffected (it's in the foreground service).
|
||
//
|
||
// vc=76 / 0.1.0-CJ — expandable-player smoothness pass:
|
||
// * The detail body no longer renders to an offscreen buffer every
|
||
// frame during the morph (CompositingStrategy.ModulateAlpha) — that
|
||
// offscreen alpha pass on the whole scroll subtree was the main
|
||
// cause of the sluggish feel.
|
||
// * Morph animation is now a snappy no-bounce spring instead of a
|
||
// 300ms FastOutSlowIn tween (which ramped slowly at both ends).
|
||
//
|
||
// vc=75 / 0.1.0-CI — expandable player (full rearchitect):
|
||
// * The video page and the bottom minibar are now ONE container that
|
||
// morphs continuously between them, both directions. Replaces the
|
||
// old separate Screen.VideoDetail page + MinibarOverlay (which just
|
||
// appeared/vanished). One fraction (0=minibar, 1=full page) drives a
|
||
// graphicsLayer scale+translate on a single mounted TextureView, so
|
||
// the morph runs in the render phase (smooth) and the same video
|
||
// surface stays live across the whole range — a true shared-element
|
||
// transition. Swipe the player down → it shrinks into the toolbar;
|
||
// swipe/tap the toolbar up → it grows back into the page.
|
||
// * Opening a video is no longer a nav push — it sets OpenVideo +
|
||
// expands. The browse screen underneath stays put, so collapsing
|
||
// drops you right back where you were.
|
||
// * Playback plumbing unchanged: shared controller, NowPlaying,
|
||
// setPlayingFrom, SponsorBlock, autoplay-next, PiP, background audio,
|
||
// and the true-fullscreen Player (⛶) all still key off NowPlaying.
|
||
//
|
||
// vc=73 / 0.1.0-CG — VideoDetail cleanup:
|
||
// * Inline player → TextureView surface so the swipe-down-to-minimize
|
||
// drag is smooth (a SurfaceView won't follow the Compose graphicsLayer
|
||
// transform — that was the stutter).
|
||
// * Description folded into a collapsible "Details" section, collapsed
|
||
// by default, sitting just above the recommendations.
|
||
// * Action buttons restyled into one tidy horizontally-scrollable row
|
||
// of uniform icon pills (dropped the redundant "Play").
|
||
//
|
||
// vc=23 / 0.1.0-AI — minibar + downloads UI + green theme:
|
||
// * MediaController/MediaSessionService unification — single ExoPlayer
|
||
// owned by PlaybackService, every UI surface is a controller client.
|
||
// Inline player on VideoDetail, fullscreen Player, and the new
|
||
// minibar overlay all drive the same underlying player; nothing
|
||
// restarts on screen transitions.
|
||
// * Persistent minibar overlay at the bottom of every non-Player
|
||
// screen whenever something is loaded. Tap → expand to fullscreen.
|
||
// Drag-down on fullscreen → minimize to minibar. ⌄ overlay button
|
||
// also minimizes. × on the minibar stops + clears.
|
||
// * Downloads page wired into the drawer.
|
||
// * Theme: forest-green primary palette in place of M3 default
|
||
// lavender / NewPipe red — modern, clean, distinct.
|
||
//
|
||
// vc=22 / 0.1.0-AH — V-2 player polish + local playlists:
|
||
// * Inline → fullscreen now hands off seek position. Tap Play (or the
|
||
// ⛶ pill on the inline player) while the inline is mid-track and
|
||
// the fullscreen Player picks up at the same point. Same handoff
|
||
// pattern as fullscreen → background from vc=21.
|
||
// * Local playlists: drawer entry "Playlists", "Save" button on
|
||
// VideoDetail. SharedPreferences-backed, no queue/autoplay yet
|
||
// (tap an entry to open VideoDetail as normal).
|
||
//
|
||
// vc=21 / 0.1.0-AG — player hand-off polish:
|
||
// * 🎧 background-audio button now captures the current position and
|
||
// resumes the foreground service from there instead of restarting.
|
||
// * HOME / recents button while on the player now hands off seamlessly
|
||
// to background audio (same position-preserving path) instead of
|
||
// auto-entering Picture-in-Picture. Manual PiP via the ⊟ overlay
|
||
// button is unchanged.
|
||
//
|
||
// vc=20 / 0.1.0-AF — channel-videos fix on top of the rust pipeline
|
||
// cutover. vc=19 returned empty subscription feeds because
|
||
// strawcore-core's channel_info wasn't doing the second browse for the
|
||
// Videos tab AND wasn't parsing the new lockupViewModel shape.
|
||
//
|
||
// vc=19 / 0.1.0-AE — rust pipeline cutover. Extraction via
|
||
// strawcore-core (Sulkta-Coop/strawcore) via the UniFFI wrapper; no
|
||
// NewPipeExtractor in the runtime path.
|
||
const val STRAW_VERSION_CODE = 82
|
||
const val STRAW_VERSION_NAME = "0.1.0-CP"
|
||
const val STRAW_APPLICATION_ID = "com.sulkta.straw"
|