pub mod trakt;
pub use trakt::TraktScrobbler;
use crate::extensions::MediaInfo;
pub trait Scrobbler: Send + Sync {
fn name(&self) -> &str;
fn on_init(&mut self) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
fn on_start(&self, media: &MediaInfo);
fn on_stop(&self, media: &MediaInfo, watched_percent: f64);
fn on_shutdown(&self) {}
}
pub struct ScrobblerManager {
scrobblers: Vec<Box<dyn Scrobbler>>,
}
impl ScrobblerManager {
pub fn new() -> Self {
Self {
scrobblers: Vec::new(),
}
}
pub fn register(&mut self, mut scrobbler: Box<dyn Scrobbler>) {
match scrobbler.on_init() {
Ok(()) => {
tracing::info!(name = scrobbler.name(), "scrobbler loaded");
self.scrobblers.push(scrobbler);
}
Err(e) => {
tracing::error!(name = scrobbler.name(), error = %e, "failed to load scrobbler");
}
}
}
pub fn on_start(&self, media: &MediaInfo) {
for scrobbler in &self.scrobblers {
scrobbler.on_start(media);
}
}
pub fn on_stop(&self, media: &MediaInfo, watched_percent: f64) {
for scrobbler in &self.scrobblers {
scrobbler.on_stop(media, watched_percent);
}
}
pub fn shutdown(&self) {
for scrobbler in &self.scrobblers {
scrobbler.on_shutdown();
}
}
}
impl Default for ScrobblerManager {
fn default() -> Self {
Self::new()
}
}
pub fn create_scrobbler(
name: &str,
client_id: Option<String>,
access_token: Option<String>,
) -> Option<Box<dyn Scrobbler>> {
match name {
"trakt" => Some(Box::new(TraktScrobbler::new(client_id, access_token))),
_ => None,
}
}