From a3cd76dbf888791278e6edba09a96b368bd2c735 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 31 Dec 2017 03:59:48 +0200 Subject: [PATCH 01/19] hammond-downloader: Use glob Insead of hardcoded file extensions. --- Cargo.lock | 15 +++++++--- hammond-downloader/Cargo.toml | 1 + hammond-downloader/src/downloader.rs | 44 +++++++++++++--------------- hammond-downloader/src/lib.rs | 1 + 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d33e5d..3e8538e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -410,7 +410,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -519,6 +519,11 @@ dependencies = [ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "gobject-sys" version = "0.5.0" @@ -602,6 +607,7 @@ version = "0.1.0" dependencies = [ "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hammond-data 0.1.0", "hyper 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1010,7 +1016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1188,7 +1194,7 @@ dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1795,6 +1801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a303bbf7a5e75ab3b627117ff10e495d1b9e97e1d68966285ac2b1f6270091bc" "checksum glib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "450247060df7d52fdad31e1d66f30d967e925c9d1d26a0ae050cfe33dcd00d08" "checksum glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9693049613ff52b93013cc3d2590366d8e530366d288438724b73f6c7dc4be8" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60d507c87a71b1143c66ed21a969be9b99a76df234b342d733e787e6c9c7d7c2" "checksum gtk 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0847c507e52c1feaede13ef56fb4847742438602655449d5f1f782e8633f146f" "checksum gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "905fcfbaaad1b44ec0b4bba9e4d527d728284c62bc2ba41fccedace2b096766f" @@ -1839,7 +1846,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" "checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854" "checksum openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "2200ffec628e3f14c39fc0131a301db214f1a7d584e36507ee8700b0c7fb7a46" diff --git a/hammond-downloader/Cargo.toml b/hammond-downloader/Cargo.toml index efb8754..7116ab7 100644 --- a/hammond-downloader/Cargo.toml +++ b/hammond-downloader/Cargo.toml @@ -11,6 +11,7 @@ log = "0.3.8" mime_guess = "1.8.3" reqwest = "0.8.2" tempdir = "0.3.5" +glob = "0.2.11" [dependencies.diesel] features = ["sqlite"] diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 7df62b6..fc6220a 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -2,6 +2,7 @@ use reqwest; use hyper::header::*; use tempdir::TempDir; use mime_guess; +use glob::glob; use std::fs::{rename, DirBuilder, File}; use std::io::{BufWriter, Read, Write}; @@ -43,7 +44,8 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { info!("Extension: {}", ext); // Construct a temp file to save desired content. - let tempdir = TempDir::new_in(dir, "")?; + // It has to be a `new_in` instead of new cause rename can't move cross filesystems. + let tempdir = TempDir::new_in(dir, "temp_download")?; let out_file = format!("{}/temp.part", tempdir.path().to_str().unwrap(),); @@ -151,21 +153,13 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { pd.title().to_owned() ); - // Hacky way - // TODO: make it so it returns the first cover.* file encountered. - // Use glob instead - let png = format!("{}/cover.png", download_fold); - let jpg = format!("{}/cover.jpg", download_fold); - let jpe = format!("{}/cover.jpe", download_fold); - let jpeg = format!("{}/cover.jpeg", download_fold); - if Path::new(&png).exists() { - return Some(png); - } else if Path::new(&jpe).exists() { - return Some(jpe); - } else if Path::new(&jpg).exists() { - return Some(jpg); - } else if Path::new(&jpeg).exists() { - return Some(jpeg); + // Weird glob magic. + if let Ok(mut foo) = glob(&format!("{}/cover.*", download_fold)) { + // For some reason there is no .first() method so nth(0) is used + let path = foo.nth(0).and_then(|x| x.ok()); + if let Some(p) = path { + return Some(p.to_str()?.into()); + } }; DirBuilder::new() @@ -173,14 +167,16 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { .create(&download_fold) .unwrap(); - let dlpath = download_into(&download_fold, "cover", &url); - if let Ok(path) = dlpath { - info!("Cached img into: {}", &path); - Some(path) - } else { - error!("Failed to get feed image."); - error!("Error: {}", dlpath.unwrap_err()); - None + match download_into(&download_fold, "cover", &url) { + Ok(path) => { + info!("Cached img into: {}", &path); + Some(path) + } + Err(err) => { + error!("Failed to get feed image."); + error!("Error: {}", err); + None + } } } diff --git a/hammond-downloader/src/lib.rs b/hammond-downloader/src/lib.rs index 98f6678..9e57db8 100644 --- a/hammond-downloader/src/lib.rs +++ b/hammond-downloader/src/lib.rs @@ -3,6 +3,7 @@ extern crate diesel; #[macro_use] extern crate error_chain; +extern crate glob; extern crate hammond_data; extern crate hyper; #[macro_use] From b32f448957f3ffd8c6c0a8c16375c1112cb26aff Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 1 Jan 2018 16:36:15 +0200 Subject: [PATCH 02/19] When downloading an episode, set it's title to rowid instead of it's title. --- Cargo.lock | 1 + hammond-downloader/Cargo.toml | 1 + hammond-downloader/src/downloader.rs | 15 +++++++-------- hammond-downloader/src/lib.rs | 2 ++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e8538e..900c1e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,6 +610,7 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hammond-data 0.1.0", "hyper 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/hammond-downloader/Cargo.toml b/hammond-downloader/Cargo.toml index 7116ab7..cb7d6f5 100644 --- a/hammond-downloader/Cargo.toml +++ b/hammond-downloader/Cargo.toml @@ -12,6 +12,7 @@ mime_guess = "1.8.3" reqwest = "0.8.2" tempdir = "0.3.5" glob = "0.2.11" +lazy_static = "1.0.0" [dependencies.diesel] features = ["sqlite"] diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index fc6220a..14a205d 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -34,7 +34,6 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { } let headers = resp.headers().clone(); - let ct_len = headers.get::().map(|ct_len| **ct_len); let ct_type = headers.get::(); ct_len.map(|x| info!("File Lenght: {}", x)); @@ -46,7 +45,6 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { // Construct a temp file to save desired content. // It has to be a `new_in` instead of new cause rename can't move cross filesystems. let tempdir = TempDir::new_in(dir, "temp_download")?; - let out_file = format!("{}/temp.part", tempdir.path().to_str().unwrap(),); // Save requested content into the file. @@ -60,7 +58,7 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { Ok(target) } -// Determine the file extension from the http content-type header. +/// Determine the file extension from the http content-type header. fn get_ext(content: Option) -> Option { let cont = content.clone()?; content @@ -121,7 +119,7 @@ pub fn get_episode(ep: &mut EpisodeWidgetQuery, download_folder: &str) -> Result ep.save()?; }; - let res = download_into(download_folder, ep.title(), ep.uri().unwrap()); + let res = download_into(download_folder, &ep.rowid().to_string(), ep.uri().unwrap()); if let Ok(path) = res { // If download succedes set episode local_uri to dlpath. @@ -147,14 +145,14 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { return None; } - let download_fold = format!( + let cache_download_fold = format!( "{}{}", HAMMOND_CACHE.to_str().unwrap(), pd.title().to_owned() ); // Weird glob magic. - if let Ok(mut foo) = glob(&format!("{}/cover.*", download_fold)) { + if let Ok(mut foo) = glob(&format!("{}/cover.*", cache_download_fold)) { // For some reason there is no .first() method so nth(0) is used let path = foo.nth(0).and_then(|x| x.ok()); if let Some(p) = path { @@ -162,12 +160,13 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { } }; + // Create the folders if they don't exist. DirBuilder::new() .recursive(true) - .create(&download_fold) + .create(&cache_download_fold) .unwrap(); - match download_into(&download_fold, "cover", &url) { + match download_into(&cache_download_fold, "cover", &url) { Ok(path) => { info!("Cached img into: {}", &path); Some(path) diff --git a/hammond-downloader/src/lib.rs b/hammond-downloader/src/lib.rs index 9e57db8..ef75fa5 100644 --- a/hammond-downloader/src/lib.rs +++ b/hammond-downloader/src/lib.rs @@ -7,6 +7,8 @@ extern crate glob; extern crate hammond_data; extern crate hyper; #[macro_use] +extern crate lazy_static; +#[macro_use] extern crate log; extern crate mime_guess; extern crate reqwest; From 37e9b6fbf06cfb14d9987ac28c306cff55990752 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 2 Jan 2018 07:23:53 +0200 Subject: [PATCH 03/19] 'How hard could it be' --- hammond-data/src/database.rs | 3 +- hammond-data/src/lib.rs | 4 +- hammond-data/src/models/queryables.rs | 16 ++++ hammond-downloader/src/downloader.rs | 2 +- hammond-downloader/src/lib.rs | 1 + hammond-downloader/src/manager.rs | 121 ++++++++++++++++++++++++++ hammond-gtk/src/widgets/episode.rs | 1 - 7 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 hammond-downloader/src/manager.rs diff --git a/hammond-data/src/database.rs b/hammond-data/src/database.rs index bb18bda..00454a8 100644 --- a/hammond-data/src/database.rs +++ b/hammond-data/src/database.rs @@ -35,7 +35,8 @@ lazy_static! { static ref DB_PATH: PathBuf = TEMPDIR.path().join("hammond.db"); } -pub(crate) fn connection() -> Pool { +// FIXME: this should not be public +pub fn connection() -> Pool { POOL.clone() } diff --git a/hammond-data/src/lib.rs b/hammond-data/src/lib.rs index 21b70ac..f9ed95d 100644 --- a/hammond-data/src/lib.rs +++ b/hammond-data/src/lib.rs @@ -56,7 +56,9 @@ pub mod utils; pub mod feed; #[allow(missing_docs)] pub mod errors; -pub(crate) mod database; +// FIXME: this should not be public +#[allow(missing_docs)] +pub mod database; pub(crate) mod models; mod parser; mod schema; diff --git a/hammond-data/src/models/queryables.rs b/hammond-data/src/models/queryables.rs index d1a9cc0..99fc27c 100644 --- a/hammond-data/src/models/queryables.rs +++ b/hammond-data/src/models/queryables.rs @@ -215,6 +215,22 @@ pub struct EpisodeWidgetQuery { podcast_id: i32, } +impl From for EpisodeWidgetQuery { + fn from(e: Episode) -> EpisodeWidgetQuery { + EpisodeWidgetQuery { + rowid: e.rowid, + title: e.title, + uri: e.uri, + local_uri: e.local_uri, + epoch: e.epoch, + length: e.length, + duration: e.duration, + played: e.played, + podcast_id: e.podcast_id, + } + } +} + impl EpisodeWidgetQuery { /// Get the value of the sqlite's `ROW_ID` pub fn rowid(&self) -> i32 { diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 14a205d..2f9e721 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -39,7 +39,7 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { ct_len.map(|x| info!("File Lenght: {}", x)); ct_type.map(|x| info!("Content Type: {}", x)); - let ext = get_ext(ct_type.cloned()).unwrap_or(String::from("unkown")); + let ext = get_ext(ct_type.cloned()).unwrap_or(String::from("unknown")); info!("Extension: {}", ext); // Construct a temp file to save desired content. diff --git a/hammond-downloader/src/lib.rs b/hammond-downloader/src/lib.rs index ef75fa5..31cc0b2 100644 --- a/hammond-downloader/src/lib.rs +++ b/hammond-downloader/src/lib.rs @@ -16,3 +16,4 @@ extern crate tempdir; pub mod downloader; pub mod errors; +pub mod manager; diff --git a/hammond-downloader/src/manager.rs b/hammond-downloader/src/manager.rs new file mode 100644 index 0000000..eeb4057 --- /dev/null +++ b/hammond-downloader/src/manager.rs @@ -0,0 +1,121 @@ +use hammond_data::Episode; +use hammond_data::dbqueries; + +use downloader::get_episode; + +use std::collections::HashSet; +use std::sync::{Arc, Mutex}; +use std::path::PathBuf; +use std::thread; + +struct DonwloadInstance { + uri: String, + // FIXME: MAKE ME A PATHBUF + local_uri: Option, + downloaded_bytes: u64, + total_bytes: u64, +} + +impl DonwloadInstance { + fn new(url: &str, total_bytes: u64) -> Self { + DonwloadInstance { + uri: url.into(), + local_uri: None, + downloaded_bytes: 0, + total_bytes, + } + } +} + +struct Manager { + active: Arc>>, +} + +impl Default for Manager { + fn default() -> Self { + Manager { + active: Arc::new(Mutex::new(HashSet::new())), + } + } +} + +impl Manager { + fn new() -> Self { + Manager::default() + } + + fn add(&self, id: i32, directory: &str) { + { + let mut m = self.active.lock().unwrap(); + m.insert(id); + } + + let dir = directory.to_owned(); + let list = self.active.clone(); + thread::spawn(move || { + let episode = dbqueries::get_episode_from_rowid(id).unwrap(); + let e = get_episode(&mut episode.into(), dir.as_str()); + if let Err(err) = e { + error!("Error: {}", err); + }; + + let mut m = list.lock().unwrap(); + m.remove(&id); + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use downloader; + + use diesel::Identifiable; + + use hammond_data::database; + use hammond_data::feed::*; + use hammond_data::{Episode, Source}; + use hammond_data::dbqueries; + + use std::path::Path; + use std::{thread, time}; + + #[test] + // This test inserts an rss feed to your `XDG_DATA/hammond/hammond.db` so we make it explicit + // to run it. + #[ignore] + // THIS IS NOT A RELIABLE TEST + // Just quick sanity check + fn test_start_dl() { + let url = "http://www.newrustacean.com/feed.xml"; + + // Create and index a source + let source = Source::from_url(url).unwrap(); + // Copy it's id + let sid = source.id().clone(); + + // Convert Source it into a Feed and index it + let feed = source.into_feed(true).unwrap(); + index(&feed); + + // Get the Podcast + let pd = dbqueries::get_podcast_from_source_id(sid).unwrap(); + // Get an episode + let episode: Episode = { + let con = database::connection(); + dbqueries::get_episode_from_pk(&*con.get().unwrap(), "e000: Hello, world!", *pd.id()) + .unwrap() + }; + + let manager = Manager::new(); + let download_fold = downloader::get_download_folder(&pd.title()).unwrap(); + manager.add(episode.rowid(), download_fold.as_str()); + + // Give it soem time to download the file + thread::sleep(time::Duration::from_secs(20)); + + let final_path = format!("{}/{}.unknown", &download_fold, episode.rowid()); + println!("{}", &final_path); + assert!(Path::new(&final_path).exists()); + } +} diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index ae17d73..ce952be 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -179,7 +179,6 @@ impl EpisodeWidget { } } -// TODO: show notification when dl is finished. fn on_download_clicked( ep: &mut EpisodeWidgetQuery, download_bttn: >k::Button, From c61d322569a8ed5f838656e43bcffee4171d5145 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 2 Jan 2018 08:00:38 +0200 Subject: [PATCH 04/19] EpisodeWidget: Implement shared download state. --- hammond-downloader/src/manager.rs | 10 +++--- hammond-gtk/src/app.rs | 6 ++++ hammond-gtk/src/widgets/episode.rs | 51 +++++++++++++++--------------- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/hammond-downloader/src/manager.rs b/hammond-downloader/src/manager.rs index eeb4057..53a914a 100644 --- a/hammond-downloader/src/manager.rs +++ b/hammond-downloader/src/manager.rs @@ -27,8 +27,10 @@ impl DonwloadInstance { } } -struct Manager { - active: Arc>>, +#[derive(Debug, Clone)] +// FIXME: privacy stuff +pub struct Manager { + pub active: Arc>>, } impl Default for Manager { @@ -40,11 +42,11 @@ impl Default for Manager { } impl Manager { - fn new() -> Self { + pub fn new() -> Self { Manager::default() } - fn add(&self, id: i32, directory: &str) { + pub fn add(&self, id: i32, directory: &str) { { let mut m = self.active.lock().unwrap(); m.insert(id); diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index 99415d9..35fe044 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -5,12 +5,18 @@ use gtk::prelude::*; use gio::{ActionMapExt, ApplicationExt, ApplicationExtManual, SimpleActionExt}; use hammond_data::utils::checkup; +use hammond_downloader::manager::Manager; use headerbar::Header; use content::Content; use utils; use std::rc::Rc; +use std::sync::{Arc, Mutex}; + +lazy_static! { + pub static ref DOWNLOADS_MANAGER: Arc> = Arc::new(Mutex::new(Manager::new())); +} #[derive(Debug, Clone)] pub struct App { diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index ce952be..a318488 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -13,6 +13,8 @@ use hammond_data::{EpisodeWidgetQuery, Podcast}; use hammond_data::errors::*; use hammond_downloader::downloader; +use app::DOWNLOADS_MANAGER; + use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; @@ -105,6 +107,14 @@ impl EpisodeWidget { .map(|c| c.add_class("dim-label")); } + { + let m = DOWNLOADS_MANAGER.lock().unwrap(); + let list = m.active.lock().unwrap(); + if list.contains(&episode.rowid()) { + self.show_progess_bar() + }; + } + // Declare a custom humansize option struct // See: https://docs.rs/humansize/1.0.2/humansize/file_size_opts/struct.FileSizeOpts.html let custom_options = size_opts::FileSizeOpts { @@ -177,6 +187,16 @@ impl EpisodeWidget { ); })); } + + fn show_progess_bar(&self) { + let progress_bar = self.progress.clone(); + timeout_add(200, move || { + progress_bar.pulse(); + glib::Continue(true) + }); + + self.progress.show(); + } } fn on_download_clicked( @@ -194,37 +214,18 @@ fn on_download_clicked( glib::Continue(true) }); - // Create a async channel. - let (sender, receiver) = channel(); - - // Pass the desired arguments into the Local Thread Storage. - GLOBAL.with( - clone!(download_bttn, play_bttn, cancel_bttn, progress => move |global| { - *global.borrow_mut() = Some(( - download_bttn, - play_bttn, - cancel_bttn, - progress, - receiver)); - }), - ); - let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap(); let pd_title = pd.title().to_owned(); let mut ep = ep.clone(); cancel_bttn.show(); progress.show(); download_bttn.hide(); - thread::spawn(move || { - let download_fold = downloader::get_download_folder(&pd_title).unwrap(); - let e = downloader::get_episode(&mut ep, download_fold.as_str()); - if let Err(err) = e { - error!("Error while trying to download: {:?}", ep.uri()); - error!("Error: {}", err); - }; - sender.send(true).expect("Couldn't send data to channel");; - glib::idle_add(receive); - }); + let download_fold = downloader::get_download_folder(&pd_title).unwrap(); + { + let m = DOWNLOADS_MANAGER.clone(); + let man = m.lock().unwrap(); + man.add(ep.rowid(), &download_fold); + } } fn on_play_bttn_clicked(episode_id: i32) { From c67c6e463ecd959c0f9a35ec7d1542235d1ec9c5 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 2 Jan 2018 08:19:24 +0200 Subject: [PATCH 05/19] EpisodeWidget: Its still a mess, but a bit cleaner. --- hammond-gtk/src/widgets/episode.rs | 59 +++++------------------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index a318488..b0bafbe 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -15,25 +15,8 @@ use hammond_downloader::downloader; use app::DOWNLOADS_MANAGER; -use std::thread; -use std::cell::RefCell; -use std::sync::mpsc::{channel, Receiver}; use std::path::Path; -type Foo = RefCell< - Option< - ( - gtk::Button, - gtk::Button, - gtk::Button, - gtk::ProgressBar, - Receiver, - ), - >, ->; - -thread_local!(static GLOBAL: Foo = RefCell::new(None)); - #[derive(Debug, Clone)] pub struct EpisodeWidget { pub container: gtk::Box, @@ -173,15 +156,13 @@ impl EpisodeWidget { }; })); - let play = &self.play; let cancel = &self.cancel; let progress = self.progress.clone(); self.download - .connect_clicked(clone!(play, episode, cancel, progress => move |dl| { + .connect_clicked(clone!(episode, cancel, progress => move |dl| { on_download_clicked( - &mut episode.clone(), + &episode, dl, - &play, &cancel, progress.clone() ); @@ -196,13 +177,14 @@ impl EpisodeWidget { }); self.progress.show(); + self.download.hide(); + self.cancel.show(); } } fn on_download_clicked( - ep: &mut EpisodeWidgetQuery, + ep: &EpisodeWidgetQuery, download_bttn: >k::Button, - play_bttn: >k::Button, cancel_bttn: >k::Button, progress_bar: gtk::ProgressBar, ) { @@ -216,14 +198,12 @@ fn on_download_clicked( let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap(); let pd_title = pd.title().to_owned(); - let mut ep = ep.clone(); cancel_bttn.show(); progress.show(); download_bttn.hide(); let download_fold = downloader::get_download_folder(&pd_title).unwrap(); { - let m = DOWNLOADS_MANAGER.clone(); - let man = m.lock().unwrap(); + let man = DOWNLOADS_MANAGER.lock().unwrap(); man.add(ep.rowid(), &download_fold); } } @@ -260,34 +240,13 @@ fn on_play_bttn_clicked(episode_id: i32) { // }; // } -fn receive() -> glib::Continue { - GLOBAL.with(|global| { - if let Some(( - ref download_bttn, - ref play_bttn, - ref cancel_bttn, - ref progress_bar, - ref reciever, - )) = *global.borrow() - { - if reciever.try_recv().is_ok() { - download_bttn.hide(); - play_bttn.show(); - cancel_bttn.hide(); - progress_bar.hide(); - } - } - }); - glib::Continue(false) -} - pub fn episodes_listbox(pd: &Podcast) -> Result { - let episodes = dbqueries::get_pd_episodeswidgets(pd)?; + let mut episodes = dbqueries::get_pd_episodeswidgets(pd)?; let list = gtk::ListBox::new(); - episodes.into_iter().for_each(|mut ep| { - let widget = EpisodeWidget::new(&mut ep); + episodes.iter_mut().for_each(|ep| { + let widget = EpisodeWidget::new(ep); list.add(&widget.container); }); From 13ba2762add0ecfdb036baa47acb10f4f5c101e1 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 5 Jan 2018 22:02:06 +0200 Subject: [PATCH 06/19] Move the download manager to the gtk crate. --- Cargo.lock | 1 - hammond-downloader/Cargo.toml | 1 - hammond-downloader/src/lib.rs | 3 -- hammond-gtk/src/app.rs | 2 +- hammond-gtk/src/main.rs | 1 + .../src/manager.rs | 43 +++++++++---------- hammond-gtk/src/widgets/episode.rs | 2 - 7 files changed, 23 insertions(+), 30 deletions(-) rename {hammond-downloader => hammond-gtk}/src/manager.rs (82%) diff --git a/Cargo.lock b/Cargo.lock index 77c05f2..ba57fd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -599,7 +599,6 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hammond-data 0.1.0", "hyper 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/hammond-downloader/Cargo.toml b/hammond-downloader/Cargo.toml index 9646d26..f541ba8 100644 --- a/hammond-downloader/Cargo.toml +++ b/hammond-downloader/Cargo.toml @@ -12,7 +12,6 @@ mime_guess = "1.8.3" reqwest = "0.8.2" tempdir = "0.3.5" glob = "0.2.11" -lazy_static = "1.0.0" [dependencies.diesel] features = ["sqlite"] diff --git a/hammond-downloader/src/lib.rs b/hammond-downloader/src/lib.rs index 31cc0b2..9e57db8 100644 --- a/hammond-downloader/src/lib.rs +++ b/hammond-downloader/src/lib.rs @@ -7,8 +7,6 @@ extern crate glob; extern crate hammond_data; extern crate hyper; #[macro_use] -extern crate lazy_static; -#[macro_use] extern crate log; extern crate mime_guess; extern crate reqwest; @@ -16,4 +14,3 @@ extern crate tempdir; pub mod downloader; pub mod errors; -pub mod manager; diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index ada0284..d08df19 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -5,9 +5,9 @@ use gtk::prelude::*; use gio::{ActionMapExt, ApplicationExt, ApplicationExtManual, SimpleActionExt}; use hammond_data::utils::checkup; -use hammond_downloader::manager::Manager; use hammond_data::Source; +use manager::Manager; use headerbar::Header; use content::Content; use utils; diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 622cd10..9dead41 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -53,6 +53,7 @@ mod content; mod app; mod utils; +mod manager; mod static_resource; use app::App; diff --git a/hammond-downloader/src/manager.rs b/hammond-gtk/src/manager.rs similarity index 82% rename from hammond-downloader/src/manager.rs rename to hammond-gtk/src/manager.rs index 53a914a..ba26036 100644 --- a/hammond-downloader/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -1,31 +1,30 @@ -use hammond_data::Episode; +// use hammond_data::Episode; use hammond_data::dbqueries; - -use downloader::get_episode; +use hammond_downloader::downloader::get_episode; use std::collections::HashSet; use std::sync::{Arc, Mutex}; -use std::path::PathBuf; +// use std::path::PathBuf; use std::thread; -struct DonwloadInstance { - uri: String, - // FIXME: MAKE ME A PATHBUF - local_uri: Option, - downloaded_bytes: u64, - total_bytes: u64, -} +// struct DonwloadInstance { +// uri: String, +// // FIXME: MAKE ME A PATHBUF +// local_uri: Option, +// downloaded_bytes: u64, +// total_bytes: u64, +// } -impl DonwloadInstance { - fn new(url: &str, total_bytes: u64) -> Self { - DonwloadInstance { - uri: url.into(), - local_uri: None, - downloaded_bytes: 0, - total_bytes, - } - } -} +// impl DonwloadInstance { +// fn new(url: &str, total_bytes: u64) -> Self { +// DonwloadInstance { +// uri: url.into(), +// local_uri: None, +// downloaded_bytes: 0, +// total_bytes, +// } +// } +// } #[derive(Debug, Clone)] // FIXME: privacy stuff @@ -70,7 +69,7 @@ impl Manager { #[cfg(test)] mod tests { use super::*; - use downloader; + use hammond_downloader::downloader; use diesel::Identifiable; diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index c9245e8..8595883 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -14,10 +14,8 @@ use hammond_data::errors::*; use hammond_downloader::downloader; use app::DOWNLOADS_MANAGER; - use app::Action; -use std::thread; use std::sync::mpsc::Sender; use std::path::Path; From da459707becfe14b00d45b71e13e824665078bf9 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 5 Jan 2018 23:57:48 +0200 Subject: [PATCH 07/19] Wire up the callbacks to the client. --- hammond-gtk/src/manager.rs | 19 ++++++++++++++----- hammond-gtk/src/widgets/episode.rs | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index ba26036..3f51146 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -2,8 +2,11 @@ use hammond_data::dbqueries; use hammond_downloader::downloader::get_episode; +use app::Action; + use std::collections::HashSet; use std::sync::{Arc, Mutex}; +use std::sync::mpsc::Sender; // use std::path::PathBuf; use std::thread; @@ -45,7 +48,7 @@ impl Manager { Manager::default() } - pub fn add(&self, id: i32, directory: &str) { + pub fn add(&self, id: i32, directory: &str, sender: Sender) { { let mut m = self.active.lock().unwrap(); m.insert(id); @@ -60,8 +63,11 @@ impl Manager { error!("Error: {}", err); }; - let mut m = list.lock().unwrap(); - m.remove(&id); + { + let mut m = list.lock().unwrap(); + m.remove(&id); + } + sender.send(Action::RefreshViews).unwrap(); }); } } @@ -80,6 +86,7 @@ mod tests { use std::path::Path; use std::{thread, time}; + use std::sync::mpsc::channel; #[test] // This test inserts an rss feed to your `XDG_DATA/hammond/hammond.db` so we make it explicit @@ -108,12 +115,14 @@ mod tests { .unwrap() }; + let (sender, _rx) = channel(); + let manager = Manager::new(); let download_fold = downloader::get_download_folder(&pd.title()).unwrap(); - manager.add(episode.rowid(), download_fold.as_str()); + manager.add(episode.rowid(), download_fold.as_str(), sender); // Give it soem time to download the file - thread::sleep(time::Duration::from_secs(20)); + thread::sleep(time::Duration::from_secs(40)); let final_path = format!("{}/{}.unknown", &download_fold, episode.rowid()); println!("{}", &final_path); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 8595883..bdf4146 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -239,7 +239,7 @@ fn on_download_clicked( let download_fold = downloader::get_download_folder(&pd_title).unwrap(); { let man = DOWNLOADS_MANAGER.lock().unwrap(); - man.add(ep.rowid(), &download_fold); + man.add(ep.rowid(), &download_fold, sender.clone()); } sender.send(Action::RefreshEpisodesViewBGR).unwrap(); } From 6bd391d89ed5bfe74a482b23a449541e9db62a28 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 7 Jan 2018 05:51:29 +0200 Subject: [PATCH 08/19] I hate global mutable state.. --- hammond-gtk/src/app.rs | 7 +-- hammond-gtk/src/manager.rs | 93 +++++++++++++----------------- hammond-gtk/src/widgets/episode.rs | 13 ++--- 3 files changed, 45 insertions(+), 68 deletions(-) diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index d08df19..8aaadea 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -7,18 +7,13 @@ use gio::{ActionMapExt, ApplicationExt, ApplicationExtManual, SimpleActionExt}; use hammond_data::utils::checkup; use hammond_data::Source; -use manager::Manager; use headerbar::Header; use content::Content; use utils; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; -lazy_static! { - pub static ref DOWNLOADS_MANAGER: Arc> = Arc::new(Mutex::new(Manager::new())); -} - #[derive(Clone, Debug)] pub enum Action { UpdateSources(Option), diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 3f51146..2be4804 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -4,72 +4,58 @@ use hammond_downloader::downloader::get_episode; use app::Action; -use std::collections::HashSet; -use std::sync::{Arc, Mutex}; +use std::collections::{HashMap, HashSet}; +use std::sync::{Arc, Mutex, RwLock}; use std::sync::mpsc::Sender; +// use std::sync::atomic::AtomicUsize; // use std::path::PathBuf; use std::thread; -// struct DonwloadInstance { -// uri: String, -// // FIXME: MAKE ME A PATHBUF -// local_uri: Option, -// downloaded_bytes: u64, -// total_bytes: u64, -// } - -// impl DonwloadInstance { -// fn new(url: &str, total_bytes: u64) -> Self { -// DonwloadInstance { -// uri: url.into(), -// local_uri: None, -// downloaded_bytes: 0, -// total_bytes, -// } -// } -// } - -#[derive(Debug, Clone)] -// FIXME: privacy stuff -pub struct Manager { - pub active: Arc>>, +#[derive(Debug)] +pub struct Progress { + total_bytes: u64, + downloaded_bytes: u64, } -impl Default for Manager { - fn default() -> Self { - Manager { - active: Arc::new(Mutex::new(HashSet::new())), +impl Progress { + pub fn new(size: u64) -> Self { + Progress { + total_bytes: size, + downloaded_bytes: 0, } } } -impl Manager { - pub fn new() -> Self { - Manager::default() +lazy_static! { + pub static ref ACTIVE_DOWNLOADS: Arc>> = { + Arc::new(RwLock::new(HashSet::new())) + }; + + pub static ref ACTIVE_PROGRESS: Arc>>> = { + Arc::new(RwLock::new(HashMap::new())) + }; +} + +pub fn add(id: i32, directory: &str, sender: Sender) { + { + let mut m = ACTIVE_DOWNLOADS.write().unwrap(); + m.insert(id); } - pub fn add(&self, id: i32, directory: &str, sender: Sender) { + let dir = directory.to_owned(); + thread::spawn(move || { + let episode = dbqueries::get_episode_from_rowid(id).unwrap(); + let e = get_episode(&mut episode.into(), dir.as_str()); + if let Err(err) = e { + error!("Error: {}", err); + }; + { - let mut m = self.active.lock().unwrap(); - m.insert(id); + let mut m = ACTIVE_DOWNLOADS.write().unwrap(); + m.remove(&id); } - - let dir = directory.to_owned(); - let list = self.active.clone(); - thread::spawn(move || { - let episode = dbqueries::get_episode_from_rowid(id).unwrap(); - let e = get_episode(&mut episode.into(), dir.as_str()); - if let Err(err) = e { - error!("Error: {}", err); - }; - - { - let mut m = list.lock().unwrap(); - m.remove(&id); - } - sender.send(Action::RefreshViews).unwrap(); - }); - } + sender.send(Action::RefreshViews).unwrap(); + }); } #[cfg(test)] @@ -117,9 +103,8 @@ mod tests { let (sender, _rx) = channel(); - let manager = Manager::new(); let download_fold = downloader::get_download_folder(&pd.title()).unwrap(); - manager.add(episode.rowid(), download_fold.as_str(), sender); + add(episode.rowid(), download_fold.as_str(), sender); // Give it soem time to download the file thread::sleep(time::Duration::from_secs(40)); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index bdf4146..e7040af 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -13,8 +13,8 @@ use hammond_data::{EpisodeWidgetQuery, Podcast}; use hammond_data::errors::*; use hammond_downloader::downloader; -use app::DOWNLOADS_MANAGER; use app::Action; +use manager; use std::sync::mpsc::Sender; use std::path::Path; @@ -99,9 +99,8 @@ impl EpisodeWidget { self.show_buttons(episode.local_uri()); { - let m = DOWNLOADS_MANAGER.lock().unwrap(); - let list = m.active.lock().unwrap(); - if list.contains(&episode.rowid()) { + let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); + if m.contains(&episode.rowid()) { self.show_progess_bar() }; } @@ -237,10 +236,8 @@ fn on_download_clicked( progress.show(); download_bttn.hide(); let download_fold = downloader::get_download_folder(&pd_title).unwrap(); - { - let man = DOWNLOADS_MANAGER.lock().unwrap(); - man.add(ep.rowid(), &download_fold, sender.clone()); - } + + manager::add(ep.rowid(), &download_fold, sender.clone()); sender.send(Action::RefreshEpisodesViewBGR).unwrap(); } From 5c333291e1f8092fe6ea3ca33c7f52275b564929 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 7 Jan 2018 07:46:11 +0200 Subject: [PATCH 09/19] Move temporary downloads to XDG_CACHE/Downloads. --- hammond-downloader/src/downloader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 2f9e721..9980b9e 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -44,7 +44,7 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { // Construct a temp file to save desired content. // It has to be a `new_in` instead of new cause rename can't move cross filesystems. - let tempdir = TempDir::new_in(dir, "temp_download")?; + let tempdir = TempDir::new_in(HAMMOND_CACHE.to_str().unwrap(), "temp_download")?; let out_file = format!("{}/temp.part", tempdir.path().to_str().unwrap(),); // Save requested content into the file. From eef83fc98c17e16cb4fb4c967ff5a6081cc84b7f Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 8 Jan 2018 05:11:37 +0200 Subject: [PATCH 10/19] EpisodeWidget: Implement API to update the progress bar. --- hammond-gtk/resources/gtk/episode_widget.ui | 1 + hammond-gtk/src/app.rs | 10 ++- hammond-gtk/src/content.rs | 19 ++-- hammond-gtk/src/manager.rs | 24 ++--- hammond-gtk/src/utils.rs | 2 +- hammond-gtk/src/widgets/episode.rs | 99 +++++++++++---------- hammond-gtk/src/widgets/show.rs | 2 +- 7 files changed, 86 insertions(+), 71 deletions(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index 7d06799..fbccf01 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -257,6 +257,7 @@ False True + 0 False diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index 8aaadea..262293b 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -17,8 +17,10 @@ use std::sync::mpsc::{channel, Receiver, Sender}; #[derive(Clone, Debug)] pub enum Action { UpdateSources(Option), - RefreshViews, + RefreshAllViews, + RefreshEpisodesView, RefreshEpisodesViewBGR, + RefreshWidget, HeaderBarShowTile(String), HeaderBarNormal, HeaderBarHideUpdateIndicator, @@ -134,12 +136,14 @@ impl App { utils::refresh_feed(headerbar.clone(), Some(vec![s]), sender.clone()) } } - Ok(Action::RefreshViews) => content.update(), + Ok(Action::RefreshAllViews) => content.update(), + Ok(Action::RefreshWidget) => content.update_widget(), + Ok(Action::RefreshEpisodesView) => content.update_episode_view(), Ok(Action::RefreshEpisodesViewBGR) => content.update_episode_view_if_baground(), Ok(Action::HeaderBarShowTile(title)) => headerbar.switch_to_back(&title), Ok(Action::HeaderBarNormal) => headerbar.switch_to_normal(), Ok(Action::HeaderBarHideUpdateIndicator) => headerbar.hide_update_notification(), - _ => (), + Err(_) => (), } Continue(true) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 0480512..57a8018 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -41,8 +41,9 @@ impl Content { } pub fn update(&self) { - self.update_shows_view(); self.update_episode_view(); + self.update_shows_view(); + self.update_widget() } pub fn update_episode_view(&self) { @@ -56,7 +57,11 @@ impl Content { } pub fn update_shows_view(&self) { - self.shows.update(); + self.shows.update_podcasts(); + } + + pub fn update_widget(&self) { + self.shows.update_widget(); } pub fn get_stack(&self) -> gtk::Stack { @@ -100,15 +105,11 @@ impl ShowStack { show } - // fn is_empty(&self) -> bool { - // self.podcasts.is_empty() + // pub fn update(&self) { + // self.update_widget(); + // self.update_podcasts(); // } - pub fn update(&self) { - self.update_podcasts(); - self.update_widget(); - } - pub fn update_podcasts(&self) { let vis = self.stack.get_visible_child_name().unwrap(); diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 2be4804..9a21819 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -4,7 +4,7 @@ use hammond_downloader::downloader::get_episode; use app::Action; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::sync::{Arc, Mutex, RwLock}; use std::sync::mpsc::Sender; // use std::sync::atomic::AtomicUsize; @@ -24,26 +24,27 @@ impl Progress { downloaded_bytes: 0, } } + + pub fn get_fraction(&self) -> f64 { + self.downloaded_bytes as f64 / self.total_bytes as f64 + } } lazy_static! { - pub static ref ACTIVE_DOWNLOADS: Arc>> = { - Arc::new(RwLock::new(HashSet::new())) - }; - - pub static ref ACTIVE_PROGRESS: Arc>>> = { + pub static ref ACTIVE_DOWNLOADS: Arc>>>> = { Arc::new(RwLock::new(HashMap::new())) }; } -pub fn add(id: i32, directory: &str, sender: Sender) { +pub fn add(id: i32, directory: &str, sender: Sender, prog: Arc>) { { let mut m = ACTIVE_DOWNLOADS.write().unwrap(); - m.insert(id); + m.insert(id, prog.clone()); } let dir = directory.to_owned(); thread::spawn(move || { + info!("{:?}", prog); // just checking that it compiles let episode = dbqueries::get_episode_from_rowid(id).unwrap(); let e = get_episode(&mut episode.into(), dir.as_str()); if let Err(err) = e { @@ -54,7 +55,9 @@ pub fn add(id: i32, directory: &str, sender: Sender) { let mut m = ACTIVE_DOWNLOADS.write().unwrap(); m.remove(&id); } - sender.send(Action::RefreshViews).unwrap(); + + sender.send(Action::RefreshEpisodesView).unwrap(); + sender.send(Action::RefreshWidget).unwrap(); }); } @@ -102,9 +105,10 @@ mod tests { }; let (sender, _rx) = channel(); + let prog = Arc::new(Mutex::new(Progress::new(42))); let download_fold = downloader::get_download_folder(&pd.title()).unwrap(); - add(episode.rowid(), download_fold.as_str(), sender); + add(episode.rowid(), download_fold.as_str(), sender, prog); // Give it soem time to download the file thread::sleep(time::Duration::from_secs(40)); diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 4928abc..2f354ea 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -30,7 +30,7 @@ pub fn refresh_feed(headerbar: Arc
, source: Option>, sender: }; sender.send(Action::HeaderBarHideUpdateIndicator).unwrap(); - sender.send(Action::RefreshViews).unwrap(); + sender.send(Action::RefreshAllViews).unwrap(); }); } diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index e7040af..fae1ed7 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -17,6 +17,7 @@ use app::Action; use manager; use std::sync::mpsc::Sender; +use std::sync::{Arc, Mutex}; use std::path::Path; #[derive(Debug, Clone)] @@ -83,6 +84,8 @@ impl EpisodeWidget { // TODO: wire the progress_bar to the downloader. // TODO: wire the cancel button. fn init(&self, episode: &mut EpisodeWidgetQuery, sender: Sender) { + WidgetExt::set_name(&self.container, &episode.rowid().to_string()); + // Set the title label state. self.set_title(episode); @@ -98,12 +101,8 @@ impl EpisodeWidget { // Show or hide the play/delete/download buttons upon widget initialization. self.show_buttons(episode.local_uri()); - { - let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); - if m.contains(&episode.rowid()) { - self.show_progess_bar() - }; - } + // Determine what the state of the progress bar should be. + self.determine_progess_bar(); let title = &self.title; self.play @@ -118,17 +117,10 @@ impl EpisodeWidget { }; })); - let cancel = &self.cancel; - let progress = self.progress.clone(); self.download - .connect_clicked(clone!(episode, cancel, progress, sender => move |dl| { - on_download_clicked( - &mut episode.clone(), - dl, - &cancel, - progress.clone(), - sender.clone() - ); + .connect_clicked(clone!(episode, sender => move |dl| { + dl.set_sensitive(false); + on_download_clicked(&mut episode.clone(), sender.clone()); })); } @@ -202,43 +194,56 @@ impl EpisodeWidget { }; } - fn show_progess_bar(&self) { - let progress_bar = self.progress.clone(); - timeout_add(200, move || { - progress_bar.pulse(); - glib::Continue(true) - }); + fn determine_progess_bar(&self) { + let id = WidgetExt::get_name(&self.container) + .unwrap() + .parse::() + .unwrap(); - self.progress.show(); - self.download.hide(); - self.cancel.show(); + let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); + if !m.contains_key(&id) { + return; + }; + + let progress_bar = self.progress.clone(); + if let Some(prog) = m.get(&id) { + self.progress.show(); + self.download.hide(); + self.cancel.show(); + + timeout_add( + 400, + clone!(prog => move || { + let fraction = { + let m = prog.lock().unwrap(); + m.get_fraction() + }; + progress_bar.set_fraction(fraction); + // info!("Fraction: {}", progress_bar.get_fraction()); + + if fraction != 1.0{ + glib::Continue(true) + } else { + glib::Continue(false) + } + }), + ); + } } } -fn on_download_clicked( - ep: &EpisodeWidgetQuery, - download_bttn: >k::Button, - cancel_bttn: >k::Button, - progress_bar: gtk::ProgressBar, - sender: Sender, -) { - let progress = progress_bar.clone(); - - // Start the proggress_bar pulse. - timeout_add(200, move || { - progress_bar.pulse(); - glib::Continue(true) - }); - +fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender) { let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap(); - let pd_title = pd.title().to_owned(); - cancel_bttn.show(); - progress.show(); - download_bttn.hide(); - let download_fold = downloader::get_download_folder(&pd_title).unwrap(); + let download_fold = downloader::get_download_folder(&pd.title().to_owned()).unwrap(); - manager::add(ep.rowid(), &download_fold, sender.clone()); - sender.send(Action::RefreshEpisodesViewBGR).unwrap(); + // Create a new `Progress` struct to keep track of dl progress. + let prog = Arc::new(Mutex::new(manager::Progress::new(42))); + // Start a new download. + manager::add(ep.rowid(), &download_fold, sender.clone(), prog.clone()); + + // Update Views + sender.send(Action::RefreshEpisodesView).unwrap(); + sender.send(Action::RefreshWidget).unwrap(); } fn on_play_bttn_clicked(episode_id: i32) { diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 37a571e..6470596 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -142,7 +142,7 @@ fn on_unsub_button_clicked( })); shows.switch_podcasts_animated(); // Queue a refresh after the switch to avoid blocking the db. - sender.send(Action::RefreshViews).unwrap(); + sender.send(Action::RefreshAllViews).unwrap(); } #[allow(dead_code)] From 193117f579b8c615de42587a01e0e11c247d29c7 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 8 Jan 2018 12:29:47 +0200 Subject: [PATCH 11/19] Downloader: Update the progress index of downloads. --- hammond-downloader/src/downloader.rs | 53 ++++++++++++++++++++++++---- hammond-gtk/src/manager.rs | 42 +++++++++++++++++----- hammond-gtk/src/widgets/episode.rs | 28 +++++++++------ 3 files changed, 97 insertions(+), 26 deletions(-) diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 9980b9e..b985a26 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -8,6 +8,7 @@ use std::fs::{rename, DirBuilder, File}; use std::io::{BufWriter, Read, Write}; use std::path::Path; use std::fs; +use std::sync::{Arc, Mutex}; use errors::*; use hammond_data::{EpisodeWidgetQuery, PodcastCoverQuery}; @@ -16,6 +17,11 @@ use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE}; // TODO: Replace path that are of type &str with std::path. // TODO: Have a convention/document absolute/relative paths, if they should end with / or not. +pub trait DownloadProgress { + fn set_downloaded(&mut self, downloaded: u64); + fn set_size(&mut self, bytes: u64); +} + // Adapted from https://github.com/mattgathu/rget . // I never wanted to write a custom downloader. // Sorry to those who will have to work with that code. @@ -23,7 +29,12 @@ use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE}; // or bindings for a lib like youtube-dl(python), // But cant seem to find one. // TODO: Write unit-tests. -fn download_into(dir: &str, file_title: &str, url: &str) -> Result { +fn download_into( + dir: &str, + file_title: &str, + url: &str, + progress: Option>>, +) -> Result { info!("GET request to: {}", url); let client = reqwest::Client::builder().referer(false).build()?; let mut resp = client.get(url).send()?; @@ -47,8 +58,15 @@ fn download_into(dir: &str, file_title: &str, url: &str) -> Result { let tempdir = TempDir::new_in(HAMMOND_CACHE.to_str().unwrap(), "temp_download")?; let out_file = format!("{}/temp.part", tempdir.path().to_str().unwrap(),); + ct_len.map(|x| { + if let Some(p) = progress.clone() { + let mut m = p.lock().unwrap(); + m.set_size(x); + } + }); + // Save requested content into the file. - save_io(&out_file, &mut resp, ct_len)?; + save_io(&out_file, &mut resp, ct_len, progress)?; // Construct the desired path. let target = format!("{}/{}.{}", dir, file_title, ext); @@ -73,8 +91,14 @@ fn get_ext(content: Option) -> Option { } // TODO: Write unit-tests. +// TODO: Refactor... Somehow. /// Handles the I/O of fetching a remote file and saving into a Buffer and A File. -fn save_io(file: &str, resp: &mut reqwest::Response, content_lenght: Option) -> Result<()> { +fn save_io( + file: &str, + resp: &mut reqwest::Response, + content_lenght: Option, + progress: Option>>, +) -> Result<()> { info!("Downloading into: {}", file); let chunk_size = match content_lenght { Some(x) => x as usize / 99, @@ -89,6 +113,14 @@ fn save_io(file: &str, resp: &mut reqwest::Response, content_lenght: Option buffer.truncate(bcount); if !buffer.is_empty() { writer.write_all(buffer.as_slice())?; + if let Some(prog) = progress.clone() { + // This sucks. + let len = writer.get_ref().metadata().map(|x| x.len()); + if let Ok(l) = len { + let mut m = prog.lock().unwrap(); + m.set_downloaded(l); + } + } } else { break; } @@ -107,7 +139,11 @@ pub fn get_download_folder(pd_title: &str) -> Result { } // TODO: Refactor -pub fn get_episode(ep: &mut EpisodeWidgetQuery, download_folder: &str) -> Result<()> { +pub fn get_episode( + ep: &mut EpisodeWidgetQuery, + download_folder: &str, + progress: Option>>, +) -> Result<()> { // Check if its alrdy downloaded if ep.local_uri().is_some() { if Path::new(ep.local_uri().unwrap()).exists() { @@ -119,7 +155,12 @@ pub fn get_episode(ep: &mut EpisodeWidgetQuery, download_folder: &str) -> Result ep.save()?; }; - let res = download_into(download_folder, &ep.rowid().to_string(), ep.uri().unwrap()); + let res = download_into( + download_folder, + &ep.rowid().to_string(), + ep.uri().unwrap(), + progress, + ); if let Ok(path) = res { // If download succedes set episode local_uri to dlpath. @@ -166,7 +207,7 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { .create(&cache_download_fold) .unwrap(); - match download_into(&cache_download_fold, "cover", &url) { + match download_into(&cache_download_fold, "cover", &url, None) { Ok(path) => { info!("Cached img into: {}", &path); Some(path) diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 9a21819..fa74bbc 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -1,6 +1,7 @@ // use hammond_data::Episode; use hammond_data::dbqueries; use hammond_downloader::downloader::get_episode; +use hammond_downloader::downloader::DownloadProgress; use app::Action; @@ -18,15 +19,33 @@ pub struct Progress { } impl Progress { - pub fn new(size: u64) -> Self { + pub fn get_fraction(&self) -> f64 { + info!("Progress: {:?}", self); + let ratio = self.downloaded_bytes as f64 / self.total_bytes as f64; + + if ratio >= 1.0 { + return 1.0; + }; + ratio + } +} + +impl Default for Progress { + fn default() -> Self { Progress { - total_bytes: size, + total_bytes: 0, downloaded_bytes: 0, } } +} - pub fn get_fraction(&self) -> f64 { - self.downloaded_bytes as f64 / self.total_bytes as f64 +impl DownloadProgress for Progress { + fn set_downloaded(&mut self, downloaded: u64) { + self.downloaded_bytes = downloaded + } + + fn set_size(&mut self, bytes: u64) { + self.total_bytes = bytes; } } @@ -36,17 +55,23 @@ lazy_static! { }; } -pub fn add(id: i32, directory: &str, sender: Sender, prog: Arc>) { +pub fn add(id: i32, directory: &str, sender: Sender) { + // Create a new `Progress` struct to keep track of dl progress. + let prog = Arc::new(Mutex::new(Progress::default())); + { let mut m = ACTIVE_DOWNLOADS.write().unwrap(); m.insert(id, prog.clone()); } + { + let m = ACTIVE_DOWNLOADS.read().unwrap(); + info!("ACTIVE DOWNLOADS: {:#?}", m); + } let dir = directory.to_owned(); thread::spawn(move || { - info!("{:?}", prog); // just checking that it compiles let episode = dbqueries::get_episode_from_rowid(id).unwrap(); - let e = get_episode(&mut episode.into(), dir.as_str()); + let e = get_episode(&mut episode.into(), dir.as_str(), Some(prog)); if let Err(err) = e { error!("Error: {}", err); }; @@ -105,10 +130,9 @@ mod tests { }; let (sender, _rx) = channel(); - let prog = Arc::new(Mutex::new(Progress::new(42))); let download_fold = downloader::get_download_folder(&pd.title()).unwrap(); - add(episode.rowid(), download_fold.as_str(), sender, prog); + add(episode.rowid(), download_fold.as_str(), sender); // Give it soem time to download the file thread::sleep(time::Duration::from_secs(40)); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index fae1ed7..75d9885 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -17,7 +17,6 @@ use app::Action; use manager; use std::sync::mpsc::Sender; -use std::sync::{Arc, Mutex}; use std::path::Path; #[derive(Debug, Clone)] @@ -80,8 +79,6 @@ impl EpisodeWidget { widget } - // TODO: calculate lenght. - // TODO: wire the progress_bar to the downloader. // TODO: wire the cancel button. fn init(&self, episode: &mut EpisodeWidgetQuery, sender: Sender) { WidgetExt::set_name(&self.container, &episode.rowid().to_string()); @@ -218,13 +215,24 @@ impl EpisodeWidget { let m = prog.lock().unwrap(); m.get_fraction() }; - progress_bar.set_fraction(fraction); - // info!("Fraction: {}", progress_bar.get_fraction()); - if fraction != 1.0{ - glib::Continue(true) - } else { + // I hate floating points. + if (fraction >= 0.0) && (fraction <= 1.0) && (!fraction.is_nan()) { + progress_bar.set_fraction(fraction); + } + // info!("Fraction: {}", progress_bar.get_fraction()); + // info!("Fraction: {}", fraction); + let active = { + let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); + m.contains_key(&id) + }; + + if (fraction >= 1.0) && (!fraction.is_nan()){ glib::Continue(false) + } else if !active { + glib::Continue(false) + }else { + glib::Continue(true) } }), ); @@ -236,10 +244,8 @@ fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender) { let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap(); let download_fold = downloader::get_download_folder(&pd.title().to_owned()).unwrap(); - // Create a new `Progress` struct to keep track of dl progress. - let prog = Arc::new(Mutex::new(manager::Progress::new(42))); // Start a new download. - manager::add(ep.rowid(), &download_fold, sender.clone(), prog.clone()); + manager::add(ep.rowid(), &download_fold, sender.clone()); // Update Views sender.send(Action::RefreshEpisodesView).unwrap(); From 9dafb0ae9eefeeb0735e482e3f7edbef97771593 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 03:58:13 +0200 Subject: [PATCH 12/19] EpisodeWidget: Add local_size label that shows the amount of bytes downloaded. --- hammond-gtk/resources/gtk/episode_widget.ui | 25 +++++- hammond-gtk/src/manager.rs | 4 + hammond-gtk/src/widgets/episode.rs | 92 +++++++++++++++------ 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index fbccf01..64a9ad1 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -120,10 +120,10 @@ - + False True - 42 MB + 0 MB True False + + + False + True + 6 + + False diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index fa74bbc..33aa7d2 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -28,6 +28,10 @@ impl Progress { }; ratio } + + pub fn get_total_size(&self) -> u64 { + self.total_bytes + } } impl Default for Progress { diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 75d9885..59dcf85 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -17,8 +17,27 @@ use app::Action; use manager; use std::sync::mpsc::Sender; +use std::sync::Arc; use std::path::Path; +lazy_static! { + static ref SIZE_OPTS: Arc = { + // Declare a custom humansize option struct + // See: https://docs.rs/humansize/1.0.2/humansize/file_size_opts/struct.FileSizeOpts.html + Arc::new(size_opts::FileSizeOpts { + divider: size_opts::Kilo::Binary, + units: size_opts::Kilo::Decimal, + decimal_places: 0, + decimal_zeroes: 0, + fixed_at: size_opts::FixedAt::No, + long_units: false, + space: true, + suffix: "", + allow_negative: false, + }) + }; +} + #[derive(Debug, Clone)] pub struct EpisodeWidget { pub container: gtk::Box, @@ -28,11 +47,12 @@ pub struct EpisodeWidget { title: gtk::Label, date: gtk::Label, duration: gtk::Label, - size: gtk::Label, progress: gtk::ProgressBar, - progress_label: gtk::Label, + total_size: gtk::Label, + local_size: gtk::Label, separator1: gtk::Label, separator2: gtk::Label, + prog_separator: gtk::Label, } impl Default for EpisodeWidget { @@ -49,11 +69,12 @@ impl Default for EpisodeWidget { let title: gtk::Label = builder.get_object("title_label").unwrap(); let date: gtk::Label = builder.get_object("date_label").unwrap(); let duration: gtk::Label = builder.get_object("duration_label").unwrap(); - let size: gtk::Label = builder.get_object("size_label").unwrap(); - let progress_label: gtk::Label = builder.get_object("progress_label").unwrap(); + let local_size: gtk::Label = builder.get_object("local_size").unwrap(); + let total_size: gtk::Label = builder.get_object("total_size").unwrap(); let separator1: gtk::Label = builder.get_object("separator1").unwrap(); let separator2: gtk::Label = builder.get_object("separator2").unwrap(); + let prog_separator: gtk::Label = builder.get_object("prog_separator").unwrap(); EpisodeWidget { container, @@ -63,11 +84,12 @@ impl Default for EpisodeWidget { cancel, title, duration, - size, date, - progress_label, + total_size, + local_size, separator1, separator2, + prog_separator, } } } @@ -87,7 +109,7 @@ impl EpisodeWidget { self.set_title(episode); // Set the size label. - self.set_size(episode.length()); + self.set_total_size(episode.length()); // Set the duaration label. self.set_duration(episode.duration()); @@ -164,33 +186,20 @@ impl EpisodeWidget { } /// Set the Episode label dependings on its size - fn set_size(&self, bytes: Option) { - // Declare a custom humansize option struct - // See: https://docs.rs/humansize/1.0.2/humansize/file_size_opts/struct.FileSizeOpts.html - let custom_options = size_opts::FileSizeOpts { - divider: size_opts::Kilo::Binary, - units: size_opts::Kilo::Decimal, - decimal_places: 0, - decimal_zeroes: 0, - fixed_at: size_opts::FixedAt::No, - long_units: false, - space: true, - suffix: "", - allow_negative: false, - }; - + fn set_total_size(&self, bytes: Option) { if let Some(size) = bytes { if size != 0 { - let s = size.file_size(custom_options); + let s = size.file_size(SIZE_OPTS.clone()); if let Ok(s) = s { - self.size.set_text(&s); - self.size.show(); + self.total_size.set_text(&s); + self.total_size.show(); self.separator2.show(); } } }; } + // FIXME: REFACTOR ME fn determine_progess_bar(&self) { let id = WidgetExt::get_name(&self.container) .unwrap() @@ -204,10 +213,14 @@ impl EpisodeWidget { let progress_bar = self.progress.clone(); if let Some(prog) = m.get(&id) { - self.progress.show(); self.download.hide(); + self.progress.show(); + self.local_size.show(); + self.total_size.show(); + self.prog_separator.show(); self.cancel.show(); + // Setup a callback that will update the progress bar. timeout_add( 400, clone!(prog => move || { @@ -231,11 +244,36 @@ impl EpisodeWidget { glib::Continue(false) } else if !active { glib::Continue(false) - }else { + } else { glib::Continue(true) } }), ); + + let total_size = self.total_size.clone(); + // Setup a callback that will update the total_size label + // with the http ContentLength header number rather than + // relying to the RSS feed. + timeout_add( + 500, + clone!(prog, total_size => move || { + let total_bytes = { + let m = prog.lock().unwrap(); + m.get_total_size() + }; + + debug!("Total Size: {}", total_bytes); + if total_bytes != 0 { + let size = total_bytes.file_size(SIZE_OPTS.clone()); + if let Ok(s) = size { + total_size.set_text(&s); + } + glib::Continue(false) + } else { + glib::Continue(true) + } + }), + ); } } } From c54f29e82ad005fdd22f5d04500476e34f96004e Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 04:20:38 +0200 Subject: [PATCH 13/19] EpisodeWidget: Modulate callbacks. --- hammond-gtk/src/widgets/episode.rs | 116 ++++++++++++++++------------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 59dcf85..b6036ec 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -17,7 +17,7 @@ use app::Action; use manager; use std::sync::mpsc::Sender; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::path::Path; lazy_static! { @@ -212,6 +212,7 @@ impl EpisodeWidget { }; let progress_bar = self.progress.clone(); + let total_size = self.total_size.clone(); if let Some(prog) = m.get(&id) { self.download.hide(); self.progress.show(); @@ -221,59 +222,12 @@ impl EpisodeWidget { self.cancel.show(); // Setup a callback that will update the progress bar. - timeout_add( - 400, - clone!(prog => move || { - let fraction = { - let m = prog.lock().unwrap(); - m.get_fraction() - }; + update_progressbar_callback(prog.clone(), id, progress_bar); - // I hate floating points. - if (fraction >= 0.0) && (fraction <= 1.0) && (!fraction.is_nan()) { - progress_bar.set_fraction(fraction); - } - // info!("Fraction: {}", progress_bar.get_fraction()); - // info!("Fraction: {}", fraction); - let active = { - let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); - m.contains_key(&id) - }; - - if (fraction >= 1.0) && (!fraction.is_nan()){ - glib::Continue(false) - } else if !active { - glib::Continue(false) - } else { - glib::Continue(true) - } - }), - ); - - let total_size = self.total_size.clone(); // Setup a callback that will update the total_size label // with the http ContentLength header number rather than // relying to the RSS feed. - timeout_add( - 500, - clone!(prog, total_size => move || { - let total_bytes = { - let m = prog.lock().unwrap(); - m.get_total_size() - }; - - debug!("Total Size: {}", total_bytes); - if total_bytes != 0 { - let size = total_bytes.file_size(SIZE_OPTS.clone()); - if let Ok(s) = size { - total_size.set_text(&s); - } - glib::Continue(false) - } else { - glib::Continue(true) - } - }), - ); + update_total_size_callback(prog.clone(), total_size); } } } @@ -310,6 +264,68 @@ fn on_play_bttn_clicked(episode_id: i32) { } } +// Setup a callback that will update the progress bar. +fn update_progressbar_callback( + prog: Arc>, + episode_rowid: i32, + progress_bar: gtk::ProgressBar, +) { + timeout_add( + 400, + clone!(prog, progress_bar=> move || { + let fraction = { + let m = prog.lock().unwrap(); + m.get_fraction() + }; + + // I hate floating points. + if (fraction >= 0.0) && (fraction <= 1.0) && (!fraction.is_nan()) { + progress_bar.set_fraction(fraction); + } + // info!("Fraction: {}", progress_bar.get_fraction()); + // info!("Fraction: {}", fraction); + let active = { + let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); + m.contains_key(&episode_rowid) + }; + + if (fraction >= 1.0) && (!fraction.is_nan()){ + glib::Continue(false) + } else if !active { + glib::Continue(false) + } else { + glib::Continue(true) + } + }), + ); +} + +// Setup a callback that will update the total_size label +// with the http ContentLength header number rather than +// relying to the RSS feed. +fn update_total_size_callback(prog: Arc>, total_size: gtk::Label) { + timeout_add( + 500, + clone!(prog, total_size => move || { + let total_bytes = { + let m = prog.lock().unwrap(); + m.get_total_size() + }; + + debug!("Total Size: {}", total_bytes); + if total_bytes != 0 { + let size = total_bytes.file_size(SIZE_OPTS.clone()); + if let Ok(s) = size { + total_size.set_text(&s); + } + glib::Continue(false) + } else { + glib::Continue(true) + } + }), + ); +} + // fn on_delete_bttn_clicked(episode_id: i32) { // let mut ep = dbqueries::get_episode_from_rowid(episode_id) // .unwrap() From 68d7c621d318f4f54e0beb5c5d0769934b12dd73 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 06:15:41 +0200 Subject: [PATCH 14/19] EpisodeWidget: Update the local_size label. --- hammond-gtk/src/manager.rs | 4 ++++ hammond-gtk/src/widgets/episode.rs | 25 +++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 33aa7d2..81d87db 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -32,6 +32,10 @@ impl Progress { pub fn get_total_size(&self) -> u64 { self.total_bytes } + + pub fn get_downloaded(&self) -> u64 { + self.downloaded_bytes + } } impl Default for Progress { diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index b6036ec..8ec2133 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -206,23 +206,28 @@ impl EpisodeWidget { .parse::() .unwrap(); - let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); - if !m.contains_key(&id) { - return; + let prog_struct = { + let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); + if !m.contains_key(&id) { + return; + }; + m.get(&id).cloned() }; let progress_bar = self.progress.clone(); let total_size = self.total_size.clone(); - if let Some(prog) = m.get(&id) { + let local_size = self.local_size.clone(); + if let Some(prog) = prog_struct { self.download.hide(); self.progress.show(); self.local_size.show(); self.total_size.show(); + self.separator2.show(); self.prog_separator.show(); self.cancel.show(); // Setup a callback that will update the progress bar. - update_progressbar_callback(prog.clone(), id, progress_bar); + update_progressbar_callback(prog.clone(), id, progress_bar, local_size); // Setup a callback that will update the total_size label // with the http ContentLength header number rather than @@ -269,15 +274,19 @@ fn update_progressbar_callback( prog: Arc>, episode_rowid: i32, progress_bar: gtk::ProgressBar, + local_size: gtk::Label, ) { timeout_add( 400, - clone!(prog, progress_bar=> move || { - let fraction = { + clone!(prog, progress_bar => move || { + let (fraction, downloaded) = { let m = prog.lock().unwrap(); - m.get_fraction() + (m.get_fraction(), m.get_downloaded()) }; + // Update local_size label + downloaded.file_size(SIZE_OPTS.clone()).map(|x| local_size.set_text(&x)); + // I hate floating points. if (fraction >= 0.0) && (fraction <= 1.0) && (!fraction.is_nan()) { progress_bar.set_fraction(fraction); From 87a259e1a4df4f13bab0aff42b0c9191b912d6e3 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 07:21:38 +0200 Subject: [PATCH 15/19] Minor cleanup. --- hammond-gtk/src/widgets/episode.rs | 26 ++++++++++++++------------ hammond-gtk/src/widgets/show.rs | 22 +++++++++------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 8ec2133..b700daa 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -189,12 +189,11 @@ impl EpisodeWidget { fn set_total_size(&self, bytes: Option) { if let Some(size) = bytes { if size != 0 { - let s = size.file_size(SIZE_OPTS.clone()); - if let Ok(s) = s { + size.file_size(SIZE_OPTS.clone()).ok().map(|s| { self.total_size.set_text(&s); self.total_size.show(); self.separator2.show(); - } + }); } }; } @@ -250,16 +249,17 @@ fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender) { } fn on_play_bttn_clicked(episode_id: i32) { - let local_uri = dbqueries::get_episode_local_uri_from_id(episode_id).unwrap(); + let local_uri = dbqueries::get_episode_local_uri_from_id(episode_id) + .ok() + .and_then(|x| x); if let Some(uri) = local_uri { if Path::new(&uri).exists() { info!("Opening {}", uri); - let e = open::that(&uri); - if let Err(err) = e { + open::that(&uri).err().map(|err| { error!("Error while trying to open file: {}", uri); error!("Error: {}", err); - }; + }); } } else { error!( @@ -285,14 +285,18 @@ fn update_progressbar_callback( }; // Update local_size label - downloaded.file_size(SIZE_OPTS.clone()).map(|x| local_size.set_text(&x)); + downloaded.file_size(SIZE_OPTS.clone()).ok().map(|x| local_size.set_text(&x)); // I hate floating points. + // Update the progress_bar. if (fraction >= 0.0) && (fraction <= 1.0) && (!fraction.is_nan()) { progress_bar.set_fraction(fraction); } + // info!("Fraction: {}", progress_bar.get_fraction()); // info!("Fraction: {}", fraction); + + // Check if the download is still active let active = { let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); m.contains_key(&episode_rowid) @@ -323,10 +327,8 @@ fn update_total_size_callback(prog: Arc>, total_size: g debug!("Total Size: {}", total_bytes); if total_bytes != 0 { - let size = total_bytes.file_size(SIZE_OPTS.clone()); - if let Ok(s) = size { - total_size.set_text(&s); - } + // Update the total_size label + total_bytes.file_size(SIZE_OPTS.clone()).ok().map(|x| total_size.set_text(&x)); glib::Continue(false) } else { glib::Continue(true) diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 6470596..eb7fc24 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -82,24 +82,22 @@ impl ShowWidget { self.link.set_tooltip_text(Some(link.as_str())); self.link.connect_clicked(move |_| { info!("Opening link: {}", &link); - let _ = open::that(&link); + open::that(&link) + .err() + .map(|err| error!("Something went wrong: {}", err)); }); } /// Populate the listbox with the shows episodes. fn setup_listbox(&self, pd: &Podcast, sender: Sender) { let listbox = episodes_listbox(pd, sender.clone()); - if let Ok(l) = listbox { - self.episodes.add(&l); - } + listbox.ok().map(|l| self.episodes.add(&l)); } /// Set the show cover. fn set_cover(&self, pd: &Podcast) { let img = get_pixbuf_from_path(&pd.clone().into(), 128); - if let Some(i) = img { - self.cover.set_from_pixbuf(&i); - } + img.map(|i| self.cover.set_from_pixbuf(&i)); } /// Set the descripton text. @@ -126,19 +124,17 @@ fn on_unsub_button_clicked( unsub_button.hide(); // Spawn a thread so it won't block the ui. thread::spawn(clone!(pd => move || { - let res = dbqueries::remove_feed(&pd); - if res.is_ok() { + dbqueries::remove_feed(&pd).ok().map(|_| { info!("{} was removed succesfully.", pd.title()); - let dl_fold = downloader::get_download_folder(pd.title()); - if let Ok(fold) = dl_fold { + downloader::get_download_folder(pd.title()).ok().map(|fold| { let res3 = fs::remove_dir_all(&fold); // TODO: Show errors? if res3.is_ok() { info!("All the content at, {} was removed succesfully", &fold); } - }; - } + }); + }); })); shows.switch_podcasts_animated(); // Queue a refresh after the switch to avoid blocking the db. From ea70addbc6eb4096cb8a745f8c55d0d56f3d2267 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 09:21:07 +0200 Subject: [PATCH 16/19] Removed some unwrap()s. --- hammond-data/src/models/queryables.rs | 1 - hammond-gtk/src/manager.rs | 38 +++++++++++++++------------ hammond-gtk/src/views/episodes.rs | 5 +--- hammond-gtk/src/widgets/episode.rs | 26 +++++++++++------- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/hammond-data/src/models/queryables.rs b/hammond-data/src/models/queryables.rs index 99fc27c..53f2e53 100644 --- a/hammond-data/src/models/queryables.rs +++ b/hammond-data/src/models/queryables.rs @@ -613,7 +613,6 @@ impl<'a> Source { fn update_etag(&mut self, req: &reqwest::Response) -> Result<()> { let headers = req.headers(); - // let etag = headers.get_raw("ETag").unwrap(); let etag = headers.get::(); let lmod = headers.get::(); diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 81d87db..1cec780 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -68,29 +68,33 @@ pub fn add(id: i32, directory: &str, sender: Sender) { let prog = Arc::new(Mutex::new(Progress::default())); { - let mut m = ACTIVE_DOWNLOADS.write().unwrap(); - m.insert(id, prog.clone()); - } - { - let m = ACTIVE_DOWNLOADS.read().unwrap(); - info!("ACTIVE DOWNLOADS: {:#?}", m); + ACTIVE_DOWNLOADS + .write() + .ok() + .map(|mut m| m.insert(id, prog.clone())); } + // { + // let m = ACTIVE_DOWNLOADS.read().unwrap(); + // info!("ACTIVE DOWNLOADS: {:#?}", m); + // } let dir = directory.to_owned(); thread::spawn(move || { - let episode = dbqueries::get_episode_from_rowid(id).unwrap(); - let e = get_episode(&mut episode.into(), dir.as_str(), Some(prog)); - if let Err(err) = e { - error!("Error: {}", err); - }; + if let Ok(episode) = dbqueries::get_episode_from_rowid(id) { + get_episode(&mut episode.into(), dir.as_str(), Some(prog)) + .err() + .map(|err| { + error!("Error while trying to download an episode"); + error!("Error: {}", err); + }); - { - let mut m = ACTIVE_DOWNLOADS.write().unwrap(); - m.remove(&id); + { + ACTIVE_DOWNLOADS.write().ok().map(|mut x| x.remove(&id)); + } + + sender.send(Action::RefreshEpisodesView).unwrap(); + sender.send(Action::RefreshWidget).unwrap(); } - - sender.send(Action::RefreshEpisodesView).unwrap(); - sender.send(Action::RefreshWidget).unwrap(); }); } diff --git a/hammond-gtk/src/views/episodes.rs b/hammond-gtk/src/views/episodes.rs index c0b04a8..5bb44b9 100644 --- a/hammond-gtk/src/views/episodes.rs +++ b/hammond-gtk/src/views/episodes.rs @@ -205,10 +205,7 @@ impl EpisodesViewWidget { let image: gtk::Image = builder.get_object("cover").unwrap(); if let Ok(pd) = dbqueries::get_podcast_cover_from_id(episode.podcast_id()) { - let img = get_pixbuf_from_path(&pd, 64); - if let Some(i) = img { - image.set_from_pixbuf(&i); - } + get_pixbuf_from_path(&pd, 64).map(|img| image.set_from_pixbuf(&img)); } let ep = EpisodeWidget::new(episode, sender.clone()); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index b700daa..651d4c2 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -205,13 +205,15 @@ impl EpisodeWidget { .parse::() .unwrap(); - let prog_struct = { - let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); - if !m.contains_key(&id) { - return; - }; - m.get(&id).cloned() - }; + let prog_struct = || -> Option<_> { + if let Ok(m) = manager::ACTIVE_DOWNLOADS.read() { + if !m.contains_key(&id) { + return None; + }; + return m.get(&id).cloned(); + } + None + }(); let progress_bar = self.progress.clone(); let total_size = self.total_size.clone(); @@ -237,11 +239,15 @@ impl EpisodeWidget { } fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender) { - let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap(); - let download_fold = downloader::get_download_folder(&pd.title().to_owned()).unwrap(); + let download_fold = dbqueries::get_podcast_from_id(ep.podcast_id()) + .ok() + .map(|pd| downloader::get_download_folder(&pd.title().to_owned()).ok()) + .and_then(|x| x); // Start a new download. - manager::add(ep.rowid(), &download_fold, sender.clone()); + if let Some(fold) = download_fold { + manager::add(ep.rowid(), &fold, sender.clone()); + } // Update Views sender.send(Action::RefreshEpisodesView).unwrap(); From 0ba5e14d7fdc8564840a0d7d4a5796e89e241c5c Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 10:10:54 +0200 Subject: [PATCH 17/19] EpisodeWidget: Only update if it's visible. --- hammond-gtk/src/app.rs | 6 ++++++ hammond-gtk/src/content.rs | 29 ++++++++++++++++++++++++++--- hammond-gtk/src/manager.rs | 3 ++- hammond-gtk/src/widgets/episode.rs | 2 +- hammond-gtk/src/widgets/show.rs | 5 +++-- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index 262293b..53ca4e2 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -20,7 +20,10 @@ pub enum Action { RefreshAllViews, RefreshEpisodesView, RefreshEpisodesViewBGR, + RefreshShowsView, RefreshWidget, + RefreshWidgetIfVis, + RefreshWidgetIfSame(i32), HeaderBarShowTile(String), HeaderBarNormal, HeaderBarHideUpdateIndicator, @@ -137,7 +140,10 @@ impl App { } } Ok(Action::RefreshAllViews) => content.update(), + Ok(Action::RefreshShowsView) => content.update_shows_view(), Ok(Action::RefreshWidget) => content.update_widget(), + Ok(Action::RefreshWidgetIfVis) => content.update_widget_if_visible(), + Ok(Action::RefreshWidgetIfSame(id)) => content.update_widget_if_same(id), Ok(Action::RefreshEpisodesView) => content.update_episode_view(), Ok(Action::RefreshEpisodesViewBGR) => content.update_episode_view_if_baground(), Ok(Action::HeaderBarShowTile(title)) => headerbar.switch_to_back(&title), diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 57a8018..5d03ed3 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -64,6 +64,18 @@ impl Content { self.shows.update_widget(); } + pub fn update_widget_if_same(&self, pid: i32) { + self.shows.update_widget_if_same(pid); + } + + pub fn update_widget_if_visible(&self) { + if self.stack.get_visible_child_name() == Some("shows".to_string()) + && self.shows.get_stack().get_visible_child_name() == Some("widget".to_string()) + { + self.shows.update_widget(); + } + } + pub fn get_stack(&self) -> gtk::Stack { self.stack.clone() } @@ -186,12 +198,12 @@ impl ShowStack { let vis = self.stack.get_visible_child_name().unwrap(); let old = self.stack.get_child_by_name("widget").unwrap(); - let id = WidgetExt::get_name(&old).unwrap(); - if id == "GtkBox" { + let id = WidgetExt::get_name(&old); + if id == Some("GtkBox".to_string()) || id.is_none() { return; } - let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()); + let pd = dbqueries::get_podcast_from_id(id.unwrap().parse::().unwrap()); if let Ok(pd) = pd { self.replace_widget(&pd); self.stack.set_visible_child_name(&vis); @@ -199,6 +211,17 @@ impl ShowStack { } } + // Only update widget if it's podcast_id is equal to pid. + pub fn update_widget_if_same(&self, pid: i32) { + let old = self.stack.get_child_by_name("widget").unwrap(); + + let id = WidgetExt::get_name(&old); + if id != Some(pid.to_string()) || id.is_none() { + return; + } + self.update_widget(); + } + pub fn switch_podcasts_animated(&self) { self.stack .set_visible_child_full("podcasts", gtk::StackTransitionType::SlideRight); diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 1cec780..6f6d7e7 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -81,6 +81,7 @@ pub fn add(id: i32, directory: &str, sender: Sender) { let dir = directory.to_owned(); thread::spawn(move || { if let Ok(episode) = dbqueries::get_episode_from_rowid(id) { + let id = episode.podcast_id(); get_episode(&mut episode.into(), dir.as_str(), Some(prog)) .err() .map(|err| { @@ -93,7 +94,7 @@ pub fn add(id: i32, directory: &str, sender: Sender) { } sender.send(Action::RefreshEpisodesView).unwrap(); - sender.send(Action::RefreshWidget).unwrap(); + sender.send(Action::RefreshWidgetIfSame(id)).unwrap(); } }); } diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 651d4c2..56ea735 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -251,7 +251,7 @@ fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender) { // Update Views sender.send(Action::RefreshEpisodesView).unwrap(); - sender.send(Action::RefreshWidget).unwrap(); + sender.send(Action::RefreshWidgetIfVis).unwrap(); } fn on_play_bttn_clicked(episode_id: i32) { diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index eb7fc24..74d69a3 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -71,7 +71,6 @@ impl ShowWidget { self.unsub .connect_clicked(clone!(shows, pd, sender => move |bttn| { on_unsub_button_clicked(shows.clone(), &pd, bttn, sender.clone()); - sender.send(Action::HeaderBarNormal).unwrap(); })); self.setup_listbox(pd, sender.clone()); @@ -137,8 +136,10 @@ fn on_unsub_button_clicked( }); })); shows.switch_podcasts_animated(); + sender.send(Action::HeaderBarNormal).unwrap(); // Queue a refresh after the switch to avoid blocking the db. - sender.send(Action::RefreshAllViews).unwrap(); + sender.send(Action::RefreshShowsView).unwrap(); + sender.send(Action::RefreshEpisodesView).unwrap(); } #[allow(dead_code)] From d4e3bf696b3c09ed459150a36fd24e261cdc71bd Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 9 Jan 2018 10:52:52 +0200 Subject: [PATCH 18/19] EpisodeWidget: Fix updating. --- hammond-gtk/src/manager.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index 6f6d7e7..49fd2f9 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -68,20 +68,16 @@ pub fn add(id: i32, directory: &str, sender: Sender) { let prog = Arc::new(Mutex::new(Progress::default())); { - ACTIVE_DOWNLOADS - .write() - .ok() - .map(|mut m| m.insert(id, prog.clone())); + if let Ok(mut m) = ACTIVE_DOWNLOADS.write() { + m.insert(id, prog.clone()); + } } - // { - // let m = ACTIVE_DOWNLOADS.read().unwrap(); - // info!("ACTIVE DOWNLOADS: {:#?}", m); - // } let dir = directory.to_owned(); thread::spawn(move || { if let Ok(episode) = dbqueries::get_episode_from_rowid(id) { - let id = episode.podcast_id(); + let pid = episode.podcast_id(); + let id = episode.rowid(); get_episode(&mut episode.into(), dir.as_str(), Some(prog)) .err() .map(|err| { @@ -90,11 +86,19 @@ pub fn add(id: i32, directory: &str, sender: Sender) { }); { - ACTIVE_DOWNLOADS.write().ok().map(|mut x| x.remove(&id)); + if let Ok(mut m) = ACTIVE_DOWNLOADS.write() { + info!("Removed: {:?}", m.remove(&id)); + } } + // { + // if let Ok(m) = ACTIVE_DOWNLOADS.read() { + // debug!("ACTIVE DOWNLOADS: {:#?}", m); + // } + // } + sender.send(Action::RefreshEpisodesView).unwrap(); - sender.send(Action::RefreshWidgetIfSame(id)).unwrap(); + sender.send(Action::RefreshWidgetIfSame(pid)).unwrap(); } }); } From 7f8544373faca60c14d62c32a26d3a60594dd980 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 10 Jan 2018 02:14:49 +0200 Subject: [PATCH 19/19] EpisodesView: Show 50 episodes instead of 100. --- hammond-downloader/src/downloader.rs | 8 ++------ hammond-gtk/src/manager.rs | 3 ++- hammond-gtk/src/views/episodes.rs | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index ad29411..180e586 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -177,11 +177,7 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { return None; } - let cache_download_fold = format!( - "{}{}", - HAMMOND_CACHE.to_str().unwrap(), - pd.title().to_owned() - ); + let cache_download_fold = format!("{}{}", HAMMOND_CACHE.to_str()?, pd.title().to_owned()); // Weird glob magic. if let Ok(mut foo) = glob(&format!("{}/cover.*", cache_download_fold)) { @@ -196,7 +192,7 @@ pub fn cache_image(pd: &PodcastCoverQuery) -> Option { DirBuilder::new() .recursive(true) .create(&cache_download_fold) - .unwrap(); + .ok()?; match download_into(&cache_download_fold, "cover", &url, None) { Ok(path) => { diff --git a/hammond-gtk/src/manager.rs b/hammond-gtk/src/manager.rs index d482fbe..b6830d6 100644 --- a/hammond-gtk/src/manager.rs +++ b/hammond-gtk/src/manager.rs @@ -20,8 +20,9 @@ pub struct Progress { impl Progress { pub fn get_fraction(&self) -> f64 { - info!("Progress: {:?}", self); let ratio = self.downloaded_bytes as f64 / self.total_bytes as f64; + debug!("{:?}", self); + debug!("Ratio completed: {}", ratio); if ratio >= 1.0 { return 1.0; diff --git a/hammond-gtk/src/views/episodes.rs b/hammond-gtk/src/views/episodes.rs index 5bb44b9..dc36148 100644 --- a/hammond-gtk/src/views/episodes.rs +++ b/hammond-gtk/src/views/episodes.rs @@ -77,7 +77,7 @@ impl Default for EpisodesView { impl EpisodesView { pub fn new(sender: Sender) -> Arc { let view = EpisodesView::default(); - let episodes = dbqueries::get_episodes_widgets_with_limit(100).unwrap(); + let episodes = dbqueries::get_episodes_widgets_with_limit(50).unwrap(); let now_utc = Utc::now(); episodes.into_iter().for_each(|mut ep| {