diff --git a/moe.tsuna.tsukimi.gschema.xml b/moe.tsuna.tsukimi.gschema.xml index be81cf10..7a8f56ad 100644 --- a/moe.tsuna.tsukimi.gschema.xml +++ b/moe.tsuna.tsukimi.gschema.xml @@ -29,6 +29,10 @@ true Default switch state + + true + Default switch state + 700 Default background height diff --git a/resources/ui/settings.ui b/resources/ui/settings.ui index f93969c2..f679b2a4 100644 --- a/resources/ui/settings.ui +++ b/resources/ui/settings.ui @@ -57,6 +57,11 @@ Show Playing Window Immediately + + + Resume Playing + + diff --git a/src/ui/moviedrop.rs b/src/ui/moviedrop.rs index 3f468f8d..96d5bbbf 100644 --- a/src/ui/moviedrop.rs +++ b/src/ui/moviedrop.rs @@ -76,6 +76,16 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SearchResult) -> gtk: vbox.append(&subdropdown); let info = info.clone(); let playbutton = gtk::Button::with_label("Play"); + let settings = gtk::gio::Settings::new(crate::APP_ID); + if settings.boolean("is-resume") { + if let Some(userdata) = &info.user_data { + if let Some(percentage) = userdata.played_percentage { + if percentage > 0. { + playbutton.set_label("Resume"); + } + } + } + } playbutton.connect_clicked(move |button| { button.set_label("Playing..."); let nameselected = namedropdown.selected_item(); @@ -94,7 +104,11 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SearchResult) -> gtk: playsessionid: playback_info.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),directurl,None,media.name,back); + if let Some(userdata) = &info.user_data { + play_event(button.clone(),directurl,None,media.name,back,userdata.played_percentage); + return; + } + play_event(button.clone(),directurl,None,media.name,back,None); return; } } @@ -117,11 +131,16 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SearchResult) -> gtk: playsessionid: playback_info.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),Some(directurl),Some(suburl),media.name,back); + if let Some(userdata) = &info.user_data { + play_event(button.clone(),Some(directurl),Some(suburl),media.name,back,userdata.played_percentage); + return; + } + play_event(button.clone(),Some(directurl),Some(suburl),media.name,back,None); return; } else { - super::new_dropsel::set_sub(info.id.clone(),media.id.clone(),nameselected.to_string(),subselected.to_string(),button.clone()); - return; + let userdata = info.user_data.clone(); + super::new_dropsel::set_sub(info.id.clone(),media.id.clone(),nameselected.to_string(),subselected.to_string(),button.clone(),userdata); + return; } } else { let back = Back { @@ -130,7 +149,11 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SearchResult) -> gtk: playsessionid: playback_info.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),Some(directurl),None,media.name,back); + if let Some(userdata) = &info.user_data { + play_event(button.clone(),Some(directurl),None,media.name,back,userdata.played_percentage); + return; + } + play_event(button.clone(),Some(directurl),None,media.name,back,None); return; } } diff --git a/src/ui/mpv/event.rs b/src/ui/mpv/event.rs index 0b987a6d..5333d59c 100644 --- a/src/ui/mpv/event.rs +++ b/src/ui/mpv/event.rs @@ -4,7 +4,7 @@ use libmpv::{events::*, *}; use std::{collections::HashMap, env, thread, time::{Duration, Instant}}; use crate::{config::set_config, ui::network::{runtime, Back}, APP_ID}; -pub fn play(url:String,suburl:Option,name:Option,back:&Back) -> Result<()> { +pub fn play(url:String,suburl:Option,name:Option,back:&Back,percentage:Option) -> Result<()> { unsafe { use libc::setlocale; @@ -21,17 +21,26 @@ pub fn play(url:String,suburl:Option,name:Option,back:&Back) -> init.set_property("config", true)?; init.set_property("input-vo-keyboard", true)?; init.set_property("input-default-bindings", true)?; + if let Some(name) = name { init.set_property("force-media-title", name)?; } + let settings = gtk::gio::Settings::new(APP_ID); + if settings.boolean("is-fullscreen") { init.set_property("fullscreen", true)?; } + if settings.boolean("is-force-window") { init.set_property("force-window", "immediate")?; } + if settings.boolean("is-resume") { + if let Some(percentage) = percentage { + init.set_property("start", format!("{}%",percentage as u32))?; + } + } Ok(()) }).unwrap(); @@ -42,12 +51,15 @@ pub fn play(url:String,suburl:Option,name:Option,back:&Back) -> ev_ctx.observe_property("volume", Format::Int64, 0)?; ev_ctx.observe_property("time-pos", Format::Double, 0)?; - let backc = back.clone(); - + let mut backc = back.clone(); + if let Some(percentage) = percentage { + backc.tick = percentage * 10000000.0; + } runtime().spawn(async move { crate::ui::network::playstart(backc).await; - }); + }); + crossbeam::scope(|scope| { scope.spawn(|_| { mpv.playlist_load_files(&[(&url, FileState::AppendPlay, None)]) diff --git a/src/ui/new_dropsel.rs b/src/ui/new_dropsel.rs index 84b040fc..ef04032a 100644 --- a/src/ui/new_dropsel.rs +++ b/src/ui/new_dropsel.rs @@ -86,6 +86,16 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SeriesInfo) -> gtk::B vbox.append(&subdropdown); let info = info.clone(); let playbutton = gtk::Button::with_label("Play"); + let settings = gtk::gio::Settings::new(crate::APP_ID); + if settings.boolean("is-resume") { + if let Some(userdata) = &info.user_data { + if let Some(percentage) = userdata.played_percentage { + if percentage > 0. { + playbutton.set_label("Resume"); + } + } + } + } playbutton.connect_clicked(move |button| { button.set_label("Playing..."); button.set_sensitive(false); @@ -105,7 +115,11 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SeriesInfo) -> gtk::B playsessionid: playback_info.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),directurl,None,media.name,back); + if let Some(userdata) = &info.user_data { + play_event(button.clone(),directurl,None,media.name,back,userdata.played_percentage); + return; + } + play_event(button.clone(),directurl,None,media.name,back,None); return; } } @@ -128,11 +142,16 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SeriesInfo) -> gtk::B playsessionid: playback_info.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),Some(directurl),Some(suburl),media.name,back); + if let Some(userdata) = &info.user_data { + play_event(button.clone(),Some(directurl),Some(suburl),media.name,back,userdata.played_percentage); + return; + } + play_event(button.clone(),Some(directurl),Some(suburl),media.name,back,None); return; } else { // Ask Luke - set_sub(info.id.clone(),media.id.clone(),nameselected.to_string(),subselected.to_string(),button.clone()); + let userdata = info.user_data.clone(); + set_sub(info.id.clone(),media.id.clone(),nameselected.to_string(),subselected.to_string(),button.clone(),userdata); return; } } else { @@ -142,7 +161,11 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SeriesInfo) -> gtk::B playsessionid: playback_info.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),Some(directurl),None,media.name,back); + if let Some(userdata) = &info.user_data { + play_event(button.clone(),Some(directurl),None,media.name,back,userdata.played_percentage); + return; + } + play_event(button.clone(),Some(directurl),None,media.name,back,None); return; } } @@ -158,13 +181,13 @@ pub fn newmediadropsel(playbackinfo: network::Media, info: SeriesInfo) -> gtk::B hbox } -pub fn play_event(button: gtk::Button, directurl: Option, suburl:Option, name: String, back: Back) { +pub fn play_event(button: gtk::Button, directurl: Option, suburl:Option, name: String, back: Back,percentage:Option) { let (sender, receiver) = async_channel::bounded(1); gtk::gio::spawn_blocking(move || { sender .send_blocking(false) .expect("The channel needs to be open."); - match mpv::event::play(directurl.expect("no url"),suburl,Some(name),&back) { + match mpv::event::play(directurl.expect("no url"),suburl,Some(name),&back,percentage) { Ok(_) => { sender .send_blocking(true) @@ -178,7 +201,12 @@ pub fn play_event(button: gtk::Button, directurl: Option, suburl:Option< glib::spawn_future_local(glib::clone!(@weak button =>async move { while let Ok(enable_button) = receiver.recv().await { if enable_button { - button.set_label("Play"); + let settings = gtk::gio::Settings::new(crate::APP_ID); + if settings.boolean("is-resume") { + button.set_label("Resume"); + } else { + button.set_label("Play"); + } } button.set_sensitive(enable_button); } @@ -190,7 +218,8 @@ pub fn set_sub( sourceid:String, nameselected: String, subselected: String, - button: gtk::Button + button: gtk::Button, + userdata: Option ) { let (sender, receiver) = async_channel::bounded::(1); let idc = id.clone(); @@ -222,7 +251,11 @@ pub fn set_sub( playsessionid: media.play_session_id.clone(), tick: 0., }; - play_event(button.clone(),Some(directurl),Some(suburl),mediasource.name,back); + if let Some(userdata) = userdata { + play_event(button.clone(),Some(directurl),Some(suburl),nameselected,back,userdata.played_percentage); + return; + } + play_event(button.clone(),Some(directurl),Some(suburl),nameselected,back,None); return; } } diff --git a/src/ui/widgets/settings.rs b/src/ui/widgets/settings.rs index a57db346..c3c3dff2 100644 --- a/src/ui/widgets/settings.rs +++ b/src/ui/widgets/settings.rs @@ -28,6 +28,8 @@ mod imp { pub spinrow: TemplateChild, #[template_child] pub forcewindowcontrol: TemplateChild, + #[template_child] + pub resumecontrol: TemplateChild, } // The central trait for subclassing a GObject @@ -57,6 +59,7 @@ mod imp { obj.set_spin(); obj.set_fullscreen(); obj.set_forcewindow(); + obj.set_resume(); } } @@ -136,5 +139,14 @@ impl SettingsPage { settings.set_boolean("is-force-window", control.is_active()).unwrap(); })); } + + pub fn set_resume(&self) { + let imp = imp::SettingsPage::from_obj(self); + let settings = gio::Settings::new(APP_ID); + imp.resumecontrol.set_active(settings.boolean("is-resume")); + imp.resumecontrol.connect_active_notify(glib::clone!(@weak self as obj =>move |control| { + settings.set_boolean("is-resume", control.is_active()).unwrap(); + })); + } }