Files
proton-stream/crates/pstr-player/src/lib.rs
T
2026-08-02 19:37:03 +02:00

56 lines
2.4 KiB
Rust

//! Playback, through libmpv, of streams that only exist behind a Proton link.
//!
//! mpv is not asked to download anything. A custom `pstr://` protocol is
//! registered with `mpv_stream_cb_add_ro`, and mpv's demuxer reads through it
//! exactly as it would read a local file — small reads, seeks, an EOF. Every one
//! of those lands in [`pstr_stream`], which serves it from the block ring, the
//! disk cache or Proton, in that order.
//!
//! ```text
//! Player::play(stream) registry: 7 → VideoStream
//! │ loadfile pstr://7 ▲
//! ▼ │ hash lookup, no I/O
//! mpv demuxer thread ── read/seek/size ──▶ StreamCursor ──▶ VideoStream
//! │ │
//! └── cancel (another thread) ──▶ CancelLatch ─┘
//! ```
//!
//! Three things about that shape are deliberate:
//!
//! * **mpv gets a token, not an identity.** The URL fragment of a Proton share
//! link *is* its decryption password, and mpv puts a stream's URL in its log,
//! its `path` property and its window title. A `u64` leaks nothing.
//! * **The open callback does no work.** Opening a revision can take seconds and
//! fail for reasons a person needs to read; mpv's open callback can only say
//! "loading failed". So the caller opens first and registers the result.
//! * **`stream_cb`, not a loopback HTTP server.** No port, no other local
//! process able to ask for the plaintext, no decrypted bytes leaving the
//! process.
//!
//! Where the picture ends up is a separate axis, and the streaming path above
//! is identical either way: [`VideoOutput::Window`] lets mpv make a window, and
//! [`VideoOutput::Embedded`] plus a [`VideoRenderer`] draws each frame into an
//! OpenGL framebuffer the caller owns. Only [`PlayerConfig`] and [`render`] know
//! the difference.
mod chapters;
mod cursor;
mod error;
mod gl;
mod player;
mod protocol;
mod registry;
mod render;
#[cfg(test)]
mod testing;
mod tracks;
pub use chapters::{Chapter, ChapterRole, chapter_at, chapter_end, credits_start, roles};
pub use error::{Error, Result};
pub use player::{
EndReason, MAX_VOLUME, Player, PlayerConfig, PlayerEvent, READAHEAD_BLOCKS, VideoOutput,
};
pub use registry::{PROTOCOL, StreamHandle, StreamRegistry};
pub use render::VideoRenderer;
pub use tracks::{Track, TrackKind, language_name};