v0.1.0-W2 (vc=11): fix playback — TV+Ios YT clients + visible play errors

Black-screen-on-play bug: rustypipe's default player() uses YT's Web
client, which serves stream URLs that are session/UA-locked. ExoPlayer
fetching with a different UA gets a silent 403 from googlevideo and
renders a black surface.

Fix: pin stream_info() to player_from_clients(id, [Tv, Ios]) — the
TVHTML5 + iOS Innertube clients serve direct-play URLs that work in
any HTTP player. Same trick NewPipe uses. No Apple/iOS code involved
— it's just the API client identifier rustypipe sends to YT.

Also added a Player.Listener in PlayerScreen that Toasts any
PlaybackException (codeName + message) so future stream failures don't
look like silent black screens. Logs to logcat 'StrawPlayer' too.
This commit is contained in:
Kayos 2026-05-24 09:33:34 -07:00
parent a13896f5e9
commit 5be7d4c276
3 changed files with 34 additions and 4 deletions

View file

@ -17,7 +17,7 @@
use crate::error::StrawcoreError;
use crate::search::SearchItem;
use rustypipe::client::RustyPipe;
use rustypipe::client::{ClientType, RustyPipe};
#[derive(Debug, Clone, uniffi::Record)]
pub struct StreamInfo {
@ -129,7 +129,15 @@ pub async fn stream_info(url: String) -> Result<StreamInfo, StrawcoreError> {
log::info!("strawcore::stream_info id={}", id);
let rp = RustyPipe::new();
let player = rp.query().player(&id).await?;
// rustypipe's default `player()` uses the Web client first. Those URLs
// come back signed against the Web fetch's session/UA — ExoPlayer can't
// replay them (404/403/black screen). Force the TV embedded + iOS
// clients, both of which return ungated direct-play URLs the way
// NewPipe's resolver does.
let player = rp
.query()
.player_from_clients(&id, &[ClientType::Tv, ClientType::Ios])
.await?;
let details = &player.details;
// Progressive (combined audio+video) goes through video_streams; the