diff --git a/hammond-data/src/models.rs b/hammond-data/src/models.rs index 739ba03..692a395 100644 --- a/hammond-data/src/models.rs +++ b/hammond-data/src/models.rs @@ -92,6 +92,12 @@ impl Episode { pub fn set_length(&mut self, value: Option) { self.length = value; } + + pub fn save(&self, db: &Database) -> Result<()> { + let tempdb = db.lock().unwrap(); + self.save_changes::(&*tempdb)?; + Ok(()) + } } #[derive(Queryable, Identifiable, AsChangeset, Associations)] @@ -139,6 +145,12 @@ impl Podcast { pub fn set_image_uri(&mut self, value: Option<&str>) { self.image_uri = value.map(|x| x.to_string()); } + + pub fn save(&self, db: &Database) -> Result<()> { + let tempdb = db.lock().unwrap(); + self.save_changes::(&*tempdb)?; + Ok(()) + } } #[derive(Queryable, Identifiable, AsChangeset)] @@ -191,12 +203,17 @@ impl<'a> Source { { self.http_etag = etag.map(|x| x.tag().to_string().to_owned()); self.last_modified = lmod.map(|x| format!("{}", x)); - let con = db.lock().unwrap(); - self.save_changes::(&*con)?; + self.save(&db)?; } Ok(()) } + + pub fn save(&self, db: &Database) -> Result<()> { + let tempdb = db.lock().unwrap(); + self.save_changes::(&*tempdb)?; + Ok(()) + } } #[derive(Insertable)] diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index df269db..d9c4157 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -1,6 +1,5 @@ use reqwest; use hyper::header::*; -use diesel::prelude::*; use std::fs::{rename, DirBuilder, File}; use std::io::{BufWriter, Read, Write}; @@ -75,11 +74,11 @@ pub fn latest_dl(connection: &Database, limit: u32) -> Result<()> { } }; - let dl_fold = get_dl_folder(x.title())?; + let download_fold = get_download_folder(x.title())?; // Download the episodes eps.iter_mut().for_each(|ep| { - let x = get_episode(connection, ep, &dl_fold); + let x = get_episode(connection, ep, &download_fold); if let Err(err) = x { error!("An Error occured while downloading an episode."); error!("Error: {}", err); @@ -94,27 +93,25 @@ pub fn latest_dl(connection: &Database, limit: u32) -> Result<()> { } // TODO: Right unit test -pub fn get_dl_folder(pd_title: &str) -> Result { +pub fn get_download_folder(pd_title: &str) -> Result { // It might be better to make it a hash of the title - let dl_fold = format!("{}/{}", DL_DIR.to_str().unwrap(), pd_title); + let download_fold = format!("{}/{}", DL_DIR.to_str().unwrap(), pd_title); // Create the folder - DirBuilder::new().recursive(true).create(&dl_fold)?; - Ok(dl_fold) + DirBuilder::new().recursive(true).create(&download_fold)?; + Ok(download_fold) } // TODO: Refactor -pub fn get_episode(connection: &Database, ep: &mut Episode, dl_folder: &str) -> Result<()> { +pub fn get_episode(connection: &Database, ep: &mut Episode, download_folder: &str) -> Result<()> { // Check if its alrdy downloaded if ep.local_uri().is_some() { if Path::new(ep.local_uri().unwrap()).exists() { return Ok(()); } - { - let db = connection.lock().unwrap(); - ep.set_local_uri(None); - ep.save_changes::(&*db)?; - } + + ep.set_local_uri(None); + ep.save(connection)?; }; // FIXME: Unreliable and hacky way to extract the file extension from the url. @@ -122,7 +119,12 @@ pub fn get_episode(connection: &Database, ep: &mut Episode, dl_folder: &str) -> // Construct the download path. // TODO: Check if its a valid path - let dlpath = format!("{}/{}.{}", dl_folder, ep.title().unwrap().to_owned(), ext); + let dlpath = format!( + "{}/{}.{}", + download_folder, + ep.title().unwrap().to_owned(), + ext + ); // info!("Downloading {:?} into: {}", y.title(), dlpath); let uri = ep.uri().to_owned(); @@ -137,8 +139,7 @@ pub fn get_episode(connection: &Database, ep: &mut Episode, dl_folder: &str) -> // If download succedes set episode local_uri to dlpath. ep.set_local_uri(Some(&dlpath)); - let db = connection.lock().unwrap(); - ep.save_changes::(&*db)?; + ep.save(connection)?; Ok(()) } @@ -154,9 +155,12 @@ pub fn cache_image(title: &str, image_uri: Option<&str>) -> Option { // FIXME: let ext = url.split('.').last().unwrap(); - let dl_fold = format!("{}{}", HAMMOND_CACHE.to_str().unwrap(), title); - DirBuilder::new().recursive(true).create(&dl_fold).unwrap(); - let dlpath = format!("{}/{}.{}", dl_fold, title, ext); + let download_fold = format!("{}{}", HAMMOND_CACHE.to_str().unwrap(), title); + DirBuilder::new() + .recursive(true) + .create(&download_fold) + .unwrap(); + let dlpath = format!("{}/{}.{}", download_fold, title, ext); if Path::new(&dlpath).exists() { return Some(dlpath); diff --git a/hammond-gtk/gtk/episode_widget.ui b/hammond-gtk/gtk/episode_widget.ui index eef57f4..e81528d 100644 --- a/hammond-gtk/gtk/episode_widget.ui +++ b/hammond-gtk/gtk/episode_widget.ui @@ -10,6 +10,78 @@ 5 5 5 + + + delete_button + True + True + center + center + + + True + False + gtk-delete + + + + + False + False + end + 0 + + + + + True + True + True + center + 5 + 5 + True + + + True + False + gtk-save + True + + + + + False + False + 5 + end + 1 + + + + + True + True + center + 5 + 5 + + + True + False + gtk-media-play + True + + + + + False + False + 5 + end + 2 + + True @@ -80,78 +152,7 @@ True True 5 - 0 - - - - - delete_button - True - True - center - center - - - True - False - gtk-delete - - - - - False - False - 1 - - - - - True - True - True - center - 5 - 5 - True - - - True - False - gtk-save - True - - - - - False - False - 5 - end - 1 - - - - - True - True - center - 5 - 5 - - - True - False - gtk-media-play - True - - - - - False - False - 5 - end - 2 + 3 diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 2e8b2ab..3f7e051 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -11,6 +11,7 @@ use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; use std::path::Path; +use std::fs; use glib; use gtk; @@ -48,8 +49,9 @@ fn epidose_widget(db: &Database, episode: &mut Episode, pd_title: &str) -> gtk:: let builder = gtk::Builder::new_from_string(builder); let ep: gtk::Box = builder.get_object("episode_box").unwrap(); - let dl_button: gtk::Button = builder.get_object("download_button").unwrap(); + let download_button: gtk::Button = builder.get_object("download_button").unwrap(); let play_button: gtk::Button = builder.get_object("play_button").unwrap(); + let delete_button: gtk::Button = builder.get_object("delete_button").unwrap(); let title_label: gtk::Label = builder.get_object("title_label").unwrap(); let desc_label: gtk::Label = builder.get_object("desc_label").unwrap(); @@ -71,20 +73,31 @@ fn epidose_widget(db: &Database, episode: &mut Episode, pd_title: &str) -> gtk:: }); } - // Show play button upon widget initialization. + // Show or hide the play/delete/download buttons upon widget initialization. let local_uri = episode.local_uri(); if local_uri.is_some() && Path::new(local_uri.unwrap()).exists() { - dl_button.hide(); + download_button.hide(); play_button.show(); + delete_button.show(); } play_button.connect_clicked(clone!(episode, db => move |_| { on_play_bttn_clicked(&db, episode.id()); })); + delete_button.connect_clicked( + clone!(episode, db, play_button, download_button => move |del|{ + on_delete_bttn_clicked(&db, episode.id()); + del.hide(); + play_button.hide(); + download_button.show(); + // TODO: reload the widget + }), + ); + let pd_title = pd_title.to_owned(); - dl_button.connect_clicked(clone!(db, play_button, episode => move |dl| { - on_dl_clicked( + download_button.connect_clicked(clone!(db, play_button, episode => move |dl| { + on_download_clicked( &db, &pd_title, &mut episode.clone(), @@ -97,26 +110,26 @@ fn epidose_widget(db: &Database, episode: &mut Episode, pd_title: &str) -> gtk:: } // TODO: show notification when dl is finished and block play_bttn till then. -fn on_dl_clicked( +fn on_download_clicked( db: &Database, pd_title: &str, ep: &mut Episode, - dl_bttn: >k::Button, + download_bttn: >k::Button, play_bttn: >k::Button, ) { // Create a async channel. let (sender, receiver) = channel(); // Pass the desired arguments into the Local Thread Storage. - GLOBAL.with(clone!(dl_bttn, play_bttn => move |global| { - *global.borrow_mut() = Some((dl_bttn, play_bttn, receiver)); + GLOBAL.with(clone!(download_bttn, play_bttn => move |global| { + *global.borrow_mut() = Some((download_bttn, play_bttn, receiver)); })); let pd_title = pd_title.to_owned(); let mut ep = ep.clone(); thread::spawn(clone!(db => move || { - let dl_fold = downloader::get_dl_folder(&pd_title).unwrap(); - let e = downloader::get_episode(&db, &mut ep, dl_fold.as_str()); + let download_fold = downloader::get_download_folder(&pd_title).unwrap(); + let e = downloader::get_episode(&db, &mut ep, download_fold.as_str()); if let Err(err) = e { error!("Error while trying to download: {}", ep.uri()); error!("Error: {}", err); @@ -132,9 +145,7 @@ fn on_play_bttn_clicked(db: &Database, episode_id: i32) { dbqueries::get_episode_local_uri(&tempdb, episode_id).unwrap() }; - if local_uri.is_some() { - let uri = local_uri.unwrap().to_owned(); - + if let Some(uri) = local_uri { if Path::new(&uri).exists() { info!("Opening {}", uri); let e = open::that(&uri); @@ -151,11 +162,46 @@ fn on_play_bttn_clicked(db: &Database, episode_id: i32) { } } +fn on_delete_bttn_clicked(db: &Database, episode_id: i32) { + let mut ep = { + let tempdb = db.lock().unwrap(); + dbqueries::get_episode(&tempdb, episode_id).unwrap() + }; + + let ep2 = ep.clone(); + let local_uri = ep2.local_uri(); + + if local_uri.is_some() { + let uri = local_uri.unwrap().to_owned(); + if Path::new(&uri).exists() { + let res = fs::remove_file(&uri); + if res.is_ok() { + ep.set_local_uri(None); + let res2 = ep.save(db); + if res2.is_ok() { + info!("Deleted file at: {}", uri); + } else { + error!("Error while trying to delete file: {}", uri); + error!("Error: {}", res2.unwrap_err()); + } + } else { + error!("Error while trying to delete file: {}", uri); + error!("Error: {}", res.unwrap_err()); + }; + } + } else { + error!( + "Something went wrong evaluating the following path: {:?}", + local_uri + ); + } +} + fn receive() -> glib::Continue { GLOBAL.with(|global| { - if let Some((ref dl_bttn, ref play_bttn, ref reciever)) = *global.borrow() { + if let Some((ref download_bttn, ref play_bttn, ref reciever)) = *global.borrow() { if reciever.try_recv().is_ok() { - dl_bttn.hide(); + download_bttn.hide(); play_bttn.show(); } }