// yt - A fully featured command line YouTube client // // Copyright (C) 2024 Benedikt Peetz // SPDX-License-Identifier: GPL-3.0-or-later // // This file is part of Yt. // // You should have received a copy of the License along with this program. // If not, see . use std::collections::HashMap; use anyhow::Result; use events::MpvEventHandler; use libmpv2::{events::EventContext, Mpv}; use log::{debug, info, warn}; use crate::{ app::App, cache::maintain, storage::video_database::{extractor_hash::ExtractorHash, getters::get_videos, VideoStatus}, }; pub mod events; pub async fn watch(app: &App) -> Result<()> { maintain(app, false).await?; // set some default values, to make things easier (these can be overridden by the config file, // which we load later) let mpv = Mpv::with_initializer(|mpv| { // Enable default key bindings, so the user can actually interact with // the player (and e.g. close the window). mpv.set_property("input-default-bindings", "yes")?; mpv.set_property("input-vo-keyboard", "yes")?; // Show the on screen controller. mpv.set_property("osc", "yes")?; // Don't automatically advance to the next video (or exit the player) mpv.set_option("keep-open", "always")?; Ok(()) })?; let config_path = &app.config.paths.mpv_config_path; if config_path.try_exists()? { info!("Found mpv.conf at '{}'!", config_path.display()); mpv.execute( "load-config-file", &[config_path.to_str().expect("This should be utf8-able")], )?; } else { warn!( "Did not find a mpv.conf file at '{}'", config_path.display() ); } let input_path = &app.config.paths.mpv_input_path; if input_path.try_exists()? { info!("Found mpv.input.conf at '{}'!", input_path.display()); mpv.execute( "load-input-conf", &[input_path.to_str().expect("This should be utf8-able")], )?; } else { warn!( "Did not find a mpv.input.conf file at '{}'", input_path.display() ); } let mut ev_ctx = EventContext::new(mpv.ctx); ev_ctx.disable_deprecated_events()?; let play_things = get_videos(app, &[VideoStatus::Cached], Some(false)).await?; info!( "{} videos are cached and ready to be played", play_things.len() ); let mut playlist_cache: HashMap = HashMap::with_capacity(play_things.len()); for play_thing in play_things { debug!("Adding '{}' to playlist.", play_thing.title); let orig_cache_path = play_thing.cache_path.expect("Is cached and thus some"); let cache_path = orig_cache_path.to_str().expect("Should be vaild utf8"); let fmt_cache_path = format!("\"{}\"", cache_path); let args = &[&fmt_cache_path, "append-play"]; mpv.execute("loadfile", args)?; playlist_cache.insert(cache_path.to_owned(), play_thing.extractor_hash); } let mut mpv_event_handler = MpvEventHandler::from_playlist(playlist_cache); loop { while mpv_event_handler.check_idle(app, &mpv).await? {} if let Some(ev) = ev_ctx.wait_event(600.) { match ev { Ok(event) => { debug!("Mpv event triggered: {:#?}", event); if mpv_event_handler.handle_mpv_event(app, &mpv, event).await? { break; } } Err(e) => debug!("Mpv Event errored: {}", e), } } } Ok(()) }