1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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(())
}
|