diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-25 15:53:05 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-25 15:53:05 +0200 |
commit | 83643e0370b101968bd3de5e9a81c2b309955cbd (patch) | |
tree | d1c0f7543db0ad700e0433334cedf4bd051d8b0a | |
parent | fix(storage/extractor_hash): Remove useless logs (diff) | |
download | yt-83643e0370b101968bd3de5e9a81c2b309955cbd.tar.gz yt-83643e0370b101968bd3de5e9a81c2b309955cbd.zip |
refactor(watch/playlist_handler): Init
This facilitates outsourcing the mpv playlist operations and overlaying them with an cache that provides the facility to convert for `playlist_entry_id`s to `ExtractorHash`es even after their corresponding video has been removed from the playlist.
-rw-r--r-- | src/watch/events/mod.rs (renamed from src/watch/events.rs) | 94 | ||||
-rw-r--r-- | src/watch/events/playlist_handler.rs | 96 |
2 files changed, 120 insertions, 70 deletions
diff --git a/src/watch/events.rs b/src/watch/events/mod.rs index c1a2d13..9ca12fd 100644 --- a/src/watch/events.rs +++ b/src/watch/events/mod.rs @@ -8,12 +8,11 @@ // 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, env::current_exe, time::Duration, usize}; +use std::{collections::HashMap, env::current_exe, mem, time::Duration, usize}; use anyhow::{bail, Result}; use libmpv2::{ events::{Event, PlaylistEntryId}, - mpv_node::MpvNode, EndFileReason, Mpv, }; use log::{debug, info, warn}; @@ -30,72 +29,25 @@ use crate::{ }, }; +use playlist_handler::PlaylistHandler; + +mod playlist_handler; + #[derive(Debug)] pub struct MpvEventHandler { watch_later_block_list: HashMap<ExtractorHash, ()>, - // current_playlist: HashMap<PlaylistEntryId, ExtractorHash>, - playlist_cache: HashMap<String, ExtractorHash>, + playlist_handler: PlaylistHandler, } impl MpvEventHandler { pub fn from_playlist(playlist_cache: HashMap<String, ExtractorHash>) -> Self { + let playlist_handler = PlaylistHandler::from_cache(playlist_cache); Self { - // current_playlist, - playlist_cache, + playlist_handler, watch_later_block_list: HashMap::new(), } } - fn get_current_mpv_playlist( - &self, - mpv: &Mpv, - ) -> Result<HashMap<PlaylistEntryId, ExtractorHash>> { - let mpv_playlist: Vec<(String, PlaylistEntryId)> = match mpv.get_property("playlist")? { - MpvNode::ArrayIter(array) => array - .map(|val| match val { - MpvNode::MapIter(map) => { - struct BuildPlaylistEntry { - filename: Option<String>, - id: Option<PlaylistEntryId>, - } - let mut entry = BuildPlaylistEntry { - filename: None, - id: None, - }; - - map.for_each(|(key, value)| match key.as_str() { - "filename" => { - entry.filename = Some(value.str().expect("work").to_owned()) - } - "id" => { - entry.id = Some(PlaylistEntryId::new(value.i64().expect("Works"))) - } - _ => (), - }); - (entry.filename.expect("is some"), entry.id.expect("is some")) - } - _ => unreachable!(), - }) - .collect(), - _ => unreachable!(), - }; - - let mut playlist: HashMap<PlaylistEntryId, ExtractorHash> = - HashMap::with_capacity(mpv_playlist.len()); - for (path, key) in mpv_playlist { - let hash = self - .playlist_cache - .get(&path) - .expect("All path should also be stored in the cache") - .to_owned(); - playlist.insert(key, hash); - } - - // debug!("Requested the current playlist: '{:#?}'", &playlist); - - Ok(playlist) - } - /// Checks, whether new videos are ready to be played pub async fn possibly_add_new_videos( &mut self, @@ -114,7 +66,7 @@ impl MpvEventHandler { } let mut blocked_videos = 0; - let current_playlist = self.get_current_mpv_playlist(mpv)?; + let current_playlist = self.playlist_handler.playlist_ids(mpv)?; let play_things = play_things .into_iter() .filter(|val| { @@ -142,9 +94,8 @@ impl MpvEventHandler { blocked_videos ); - self.playlist_cache.reserve(play_things.len()); - let num = play_things.len(); + self.playlist_handler.reserve(play_things.len()); for play_thing in play_things { debug!("Adding '{}' to playlist.", play_thing.title); @@ -155,8 +106,8 @@ impl MpvEventHandler { let args = &[&fmt_cache_path, "append-play"]; mpv.execute("loadfile", args)?; - self.playlist_cache - .insert(cache_path.to_owned(), play_thing.extractor_hash); + self.playlist_handler + .add(cache_path.to_owned(), play_thing.extractor_hash); } if force_message || num > 0 { @@ -182,7 +133,7 @@ impl MpvEventHandler { /// You can specify an offset, which is added to the playlist_position to get, for example, the /// previous video (-1) or the next video (+1). /// Beware that setting an offset can cause an property error if it's out of bound. - fn get_cvideo_hash(&self, mpv: &Mpv, offset: i64) -> Result<ExtractorHash> { + fn get_cvideo_hash(&mut self, mpv: &Mpv, offset: i64) -> Result<ExtractorHash> { let playlist_entry_id = { let playlist_position = { let raw = mpv.get_property::<i64>("playlist-pos")?; @@ -201,9 +152,11 @@ impl MpvEventHandler { // debug!("Trying to get playlist entry: '{}'", playlist_entry_id); let video_hash = self - .get_current_mpv_playlist(mpv)? - .remove(&playlist_entry_id) - .expect("The stored playling index should always be in the playlist"); + .playlist_handler + .playlist_ids(mpv)? + .get(&playlist_entry_id) + .expect("The stored playling index should always be in the playlist") + .to_owned(); Ok(video_hash) } @@ -220,7 +173,7 @@ impl MpvEventHandler { mpv: &Mpv, playlist_index: PlaylistEntryId, ) -> Result<()> { - let current_playlist = self.get_current_mpv_playlist(mpv)?; + let current_playlist = self.playlist_handler.playlist_ids(mpv)?; let video_hash = current_playlist .get(&playlist_index) .expect("The video index should always be correctly tracked"); @@ -234,7 +187,7 @@ impl MpvEventHandler { mpv: &Mpv, playlist_index: PlaylistEntryId, ) -> Result<()> { - let current_playlist = self.get_current_mpv_playlist(mpv)?; + let current_playlist = self.playlist_handler.playlist_ids(mpv)?; let video_hash = current_playlist .get(&playlist_index) .expect("The video index should always be correctly tracked"); @@ -304,7 +257,8 @@ impl MpvEventHandler { info!("Mpv quit. Exiting playback"); // draining the playlist is okay, as mpv is done playing - let videos = self.get_current_mpv_playlist(mpv)?; + let mut handler = mem::take(&mut self.playlist_handler); + let videos = handler.playlist_ids(mpv)?; for (_, hash) in videos { self.mark_video_watched(app, &hash).await?; set_state_change(&app, &hash, false).await?; @@ -324,8 +278,8 @@ impl MpvEventHandler { // We don't need to check, whether other videos are still active, as they should // have been marked inactive in the `Stop` handler. self.mark_video_active(app, mpv, entry_id).await?; - self.apply_options(app, mpv, &self.get_cvideo_hash(mpv, 0)?) - .await?; + let hash = self.get_cvideo_hash(mpv, 0)?; + self.apply_options(app, mpv, &hash).await?; } Event::ClientMessage(a) => { debug!("Got Client Message event: '{}'", a.join(" ")); diff --git a/src/watch/events/playlist_handler.rs b/src/watch/events/playlist_handler.rs new file mode 100644 index 0000000..8f2f322 --- /dev/null +++ b/src/watch/events/playlist_handler.rs @@ -0,0 +1,96 @@ +// 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 libmpv2::{events::PlaylistEntryId, mpv_node::MpvNode, Mpv}; + +use crate::storage::video_database::extractor_hash::ExtractorHash; + +#[derive(Debug, Default)] +pub struct PlaylistHandler { + /// A map of the original file paths to the videos extractor hashes. + /// Used to get the extractor hash from a video returned by mpv + playlist_cache: HashMap<String, ExtractorHash>, + + /// A map of the playlist_entry_id field to their corresponding extractor hashes. + playlist_ids: HashMap<PlaylistEntryId, ExtractorHash>, +} +impl PlaylistHandler { + pub fn from_cache(cache: HashMap<String, ExtractorHash>) -> Self { + Self { + playlist_cache: cache, + playlist_ids: HashMap::new(), + } + } + + pub fn reserve(&mut self, len: usize) { + self.playlist_cache.reserve(len) + } + pub fn add(&mut self, cache_path: String, extractor_hash: ExtractorHash) { + assert_eq!( + self.playlist_cache.insert(cache_path, extractor_hash), + None, + "Only new video should ever be added" + ); + } + + pub fn playlist_ids(&mut self, mpv: &Mpv) -> Result<&HashMap<PlaylistEntryId, ExtractorHash>> { + let mpv_playlist: Vec<(String, PlaylistEntryId)> = match mpv.get_property("playlist")? { + MpvNode::ArrayIter(array) => array + .map(|val| match val { + MpvNode::MapIter(map) => { + struct BuildPlaylistEntry { + filename: Option<String>, + id: Option<PlaylistEntryId>, + } + let mut entry = BuildPlaylistEntry { + filename: None, + id: None, + }; + + map.for_each(|(key, value)| match key.as_str() { + "filename" => { + entry.filename = Some(value.str().expect("work").to_owned()) + } + "id" => { + entry.id = Some(PlaylistEntryId::new(value.i64().expect("Works"))) + } + _ => (), + }); + (entry.filename.expect("is some"), entry.id.expect("is some")) + } + _ => unreachable!(), + }) + .collect(), + _ => unreachable!(), + }; + + let mut playlist: HashMap<PlaylistEntryId, ExtractorHash> = + HashMap::with_capacity(mpv_playlist.len()); + for (path, key) in mpv_playlist { + let hash = self + .playlist_cache + .get(&path) + .expect("All path should also be stored in the cache") + .to_owned(); + playlist.insert(key, hash); + } + + for (id, hash) in playlist { + if !self.playlist_ids.contains_key(&id) { + self.playlist_ids.insert(id, hash); + } + } + + Ok(&self.playlist_ids) + } +} |