The project uses a trait-based system to abstract different media server backends (like Plex or Emby). To implement a new client, you must satisfy two primary traits:
ProvideNowPlaying: Responsible for discovering active playback sessions and extracting metadata from them.
sessions(): Returns a list of active sessions.extract(session): Converts a specific session into a NowPlaying object.now_playing(): A helper method that returns a stream of all current NowPlaying data.
Client: The high-level interface for interacting with the media server.
now_playing(): Returns a stream of current playback data.now_playing_updates(interval, has_pending): Returns a stream that polls the server at a specified interval. It uses an AtomicBool (has_pending) to allow the system to trigger an immediate poll if new data needs processing, rather than waiting for the full interval.probe(): Checks if the server is reachable.run(): Starts the client loop.
If your client also supports adding items to a playback queue, implement the Queue trait.
append(np, episodes): Adds specific EpisodeRef pairs to the session referenced by np.
// Example of the relationship between traits
pub trait ProvideNowPlaying {
type Session;
fn sessions(&self) -> impl std::future::Future<Output = anyhow::Result<Vec<Self::Session>>> + Send;
fn extract(&self, session: Self::Session) -> impl std::future::Future<Output = anyhow::Result<NowPlaying>> + Send;
}
pub trait Client {
fn now_playing(&self) -> BoxFuture<'_, anyhow::Result<BoxStream<'_, NowPlaying>>>;
fn probe(&self) -> LocalBoxFuture<'_, anyhow::Result<()>>;
fn run(&self) -> BoxFuture<'_, ()>;
}