diff options
Diffstat (limited to 'yt/src/watch/mod.rs')
-rw-r--r-- | yt/src/watch/mod.rs | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/yt/src/watch/mod.rs b/yt/src/watch/mod.rs new file mode 100644 index 0000000..3bcf1fc --- /dev/null +++ b/yt/src/watch/mod.rs @@ -0,0 +1,117 @@ +// yt - A fully featured command line YouTube client +// +// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de> +// 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 <https://www.gnu.org/licenses/gpl-3.0.txt>. + +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<String, ExtractorHash> = + 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(()) +} |