Async update of the download and play buttons upon download finished.
This commit is contained in:
parent
28a10ac462
commit
51f52c3408
@ -56,7 +56,8 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
if args.dl >= 0 {
|
if args.dl >= 0 {
|
||||||
let db = hammond_data::establish_connection();
|
let db = hammond_data::establish_connection();
|
||||||
downloader::latest_dl(&db, args.dl as u32).unwrap();
|
let db = Arc::new(Mutex::new(db));
|
||||||
|
downloader::latest_dl(db, args.dl as u32).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.latest {
|
if args.latest {
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
|
||||||
|
|
||||||
use reqwest;
|
use reqwest;
|
||||||
use hyper::header::*;
|
use hyper::header::*;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
@ -5,7 +8,7 @@ use diesel::prelude::*;
|
|||||||
use std::fs::{rename, DirBuilder, File};
|
use std::fs::{rename, DirBuilder, File};
|
||||||
use std::io::{BufWriter, Read, Write};
|
use std::io::{BufWriter, Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::thread;
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use errors::*;
|
use errors::*;
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::dbqueries;
|
||||||
@ -58,22 +61,28 @@ pub fn download_to(target: &str, url: &str) -> Result<()> {
|
|||||||
|
|
||||||
// Initial messy prototype, queries load alot of not needed stuff.
|
// Initial messy prototype, queries load alot of not needed stuff.
|
||||||
// TODO: Refactor
|
// TODO: Refactor
|
||||||
pub fn latest_dl(connection: &SqliteConnection, limit: u32) -> Result<()> {
|
pub fn latest_dl(connection: Arc<Mutex<SqliteConnection>>, limit: u32) -> Result<()> {
|
||||||
let pds = dbqueries::get_podcasts(connection)?;
|
let pds = {
|
||||||
|
let tempdb = connection.lock().unwrap();
|
||||||
|
dbqueries::get_podcasts(&tempdb)?
|
||||||
|
};
|
||||||
|
|
||||||
let _: Vec<_> = pds.iter()
|
let _: Vec<_> = pds.iter()
|
||||||
.map(|x| -> Result<()> {
|
.map(|x| -> Result<()> {
|
||||||
let mut eps = if limit == 0 {
|
let mut eps = {
|
||||||
dbqueries::get_pd_episodes(connection, x)?
|
let tempdb = connection.lock().unwrap();
|
||||||
} else {
|
if limit == 0 {
|
||||||
dbqueries::get_pd_episodes_limit(connection, x, limit)?
|
dbqueries::get_pd_episodes(&tempdb, x)?
|
||||||
|
} else {
|
||||||
|
dbqueries::get_pd_episodes_limit(&tempdb, x, limit)?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let dl_fold = get_dl_folder(x.title())?;
|
let dl_fold = get_dl_folder(x.title())?;
|
||||||
|
|
||||||
// Download the episodes
|
// Download the episodes
|
||||||
eps.iter_mut().for_each(|ep| {
|
eps.iter_mut().for_each(|ep| {
|
||||||
let x = get_episode(connection, ep, &dl_fold);
|
let x = get_episode(connection.clone(), ep, &dl_fold);
|
||||||
if let Err(err) = x {
|
if let Err(err) = x {
|
||||||
error!("An Error occured while downloading an episode.");
|
error!("An Error occured while downloading an episode.");
|
||||||
error!("Error: {}", err);
|
error!("Error: {}", err);
|
||||||
@ -97,14 +106,22 @@ pub fn get_dl_folder(pd_title: &str) -> Result<String> {
|
|||||||
Ok(dl_fold)
|
Ok(dl_fold)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_episode(connection: &SqliteConnection, ep: &mut Episode, dl_folder: &str) -> Result<()> {
|
// TODO: Refactor
|
||||||
|
pub fn get_episode(
|
||||||
|
connection: Arc<Mutex<SqliteConnection>>,
|
||||||
|
ep: &mut Episode,
|
||||||
|
dl_folder: &str,
|
||||||
|
) -> Result<()> {
|
||||||
// Check if its alrdy downloaded
|
// Check if its alrdy downloaded
|
||||||
if ep.local_uri().is_some() {
|
if ep.local_uri().is_some() {
|
||||||
if Path::new(ep.local_uri().unwrap()).exists() {
|
if Path::new(ep.local_uri().unwrap()).exists() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
ep.set_local_uri(None);
|
{
|
||||||
ep.save_changes::<Episode>(connection)?;
|
let db = connection.lock().unwrap();
|
||||||
|
ep.set_local_uri(None);
|
||||||
|
ep.save_changes::<Episode>(&*db)?;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Unreliable and hacky way to extract the file extension from the url.
|
// FIXME: Unreliable and hacky way to extract the file extension from the url.
|
||||||
@ -113,28 +130,23 @@ pub fn get_episode(connection: &SqliteConnection, ep: &mut Episode, dl_folder: &
|
|||||||
// Construct the download path.
|
// Construct the download path.
|
||||||
// TODO: Check if its a valid path
|
// TODO: Check if its a valid path
|
||||||
let dlpath = format!("{}/{}.{}", dl_folder, ep.title().unwrap().to_owned(), ext);
|
let dlpath = format!("{}/{}.{}", dl_folder, ep.title().unwrap().to_owned(), ext);
|
||||||
|
let dlpath1 = dlpath.clone();
|
||||||
// info!("Downloading {:?} into: {}", y.title(), dlpath);
|
// info!("Downloading {:?} into: {}", y.title(), dlpath);
|
||||||
|
|
||||||
// If download succedes set episode local_uri to dlpath.
|
|
||||||
// This should be at the end after download is finished,
|
|
||||||
// but its handy atm while the gtk client doesnt yet have custom signals.
|
|
||||||
ep.set_local_uri(Some(&dlpath));
|
|
||||||
ep.save_changes::<Episode>(connection)?;
|
|
||||||
|
|
||||||
let uri = ep.uri().to_owned();
|
let uri = ep.uri().to_owned();
|
||||||
|
let res = download_to(&dlpath1, uri.as_str());
|
||||||
|
|
||||||
// This would not be needed in general but I want to be able to call
|
if let Err(err) = res {
|
||||||
// this function from the gtk client.
|
error!("Something whent wrong while downloading.");
|
||||||
// should get removed probably once custom callbacks are implemented.
|
error!("Error: {}", err);
|
||||||
thread::spawn(move || {
|
} else {
|
||||||
let res = download_to(&dlpath, uri.as_str());
|
info!("Download of {} finished.", uri);
|
||||||
if let Err(err) = res {
|
};
|
||||||
error!("Something whent wrong while downloading.");
|
|
||||||
error!("Error: {}", err);
|
// If download succedes set episode local_uri to dlpath.
|
||||||
} else {
|
ep.set_local_uri(Some(&dlpath));
|
||||||
info!("Download of {} finished.", uri);
|
let db = connection.lock().unwrap();
|
||||||
}
|
ep.save_changes::<Episode>(&*db)?;
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,13 +10,22 @@ use hammond_downloader::downloader;
|
|||||||
use dissolve::strip_html_tags;
|
use dissolve::strip_html_tags;
|
||||||
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use glib;
|
||||||
use gtk;
|
use gtk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::ContainerExt;
|
use gtk::ContainerExt;
|
||||||
|
|
||||||
|
thread_local!(
|
||||||
|
static GLOBAL: RefCell<Option<((gtk::Button,
|
||||||
|
gtk::Button,
|
||||||
|
Receiver<bool>))>> = RefCell::new(None));
|
||||||
|
|
||||||
|
// TODO: REFACTOR AND MODULATE ME.
|
||||||
fn epidose_widget(
|
fn epidose_widget(
|
||||||
connection: Arc<Mutex<SqliteConnection>>,
|
connection: Arc<Mutex<SqliteConnection>>,
|
||||||
episode: &mut Episode,
|
episode: &mut Episode,
|
||||||
@ -65,35 +74,67 @@ fn epidose_widget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pd_title_cloned = pd_title.to_owned();
|
// TODO: figure out how to use the gtk-clone macro,
|
||||||
|
// to make it less tedious.
|
||||||
|
let pd_title_clone = pd_title.to_owned();
|
||||||
let db = connection.clone();
|
let db = connection.clone();
|
||||||
let ep_clone = episode.clone();
|
let ep_clone = episode.clone();
|
||||||
let play_button_clone = play_button.clone();
|
let play_button_clone = play_button.clone();
|
||||||
dl_button.connect_clicked(move |dl| {
|
let dl_button_clone = dl_button.clone();
|
||||||
// ugly hack to bypass the borrowchecker
|
dl_button.connect_clicked(move |_| {
|
||||||
let pd_title = pd_title_cloned.clone();
|
on_dl_clicked(
|
||||||
let db_clone = db.clone();
|
db.clone(),
|
||||||
let mut ep_clone = ep_clone.clone();
|
&pd_title_clone,
|
||||||
|
&mut ep_clone.clone(),
|
||||||
// TODO: emit a signal and show notification when dl is finished and block play_bttn till
|
dl_button_clone.clone(),
|
||||||
// then.
|
play_button_clone.clone(),
|
||||||
thread::spawn(move || {
|
);
|
||||||
let dl_fold = downloader::get_dl_folder(&pd_title).unwrap();
|
|
||||||
let tempdb = db_clone.lock().unwrap();
|
|
||||||
let e = downloader::get_episode(&tempdb, &mut ep_clone, dl_fold.as_str());
|
|
||||||
drop(tempdb);
|
|
||||||
if let Err(err) = e {
|
|
||||||
error!("Error while trying to download: {}", ep_clone.uri());
|
|
||||||
error!("Error: {}", err);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
dl.hide();
|
|
||||||
play_button_clone.show();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ep
|
ep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: show notification when dl is finished and block play_bttn till then.
|
||||||
|
fn on_dl_clicked(
|
||||||
|
db: Arc<Mutex<SqliteConnection>>,
|
||||||
|
pd_title: &str,
|
||||||
|
ep: &mut Episode,
|
||||||
|
dl_bttn: gtk::Button,
|
||||||
|
play_bttn: gtk::Button,
|
||||||
|
) {
|
||||||
|
// Create a async channel.
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
|
||||||
|
// Pass the desired arguments into the Local Thread Storage.
|
||||||
|
GLOBAL.with(move |global| {
|
||||||
|
*global.borrow_mut() = Some((dl_bttn, play_bttn, receiver));
|
||||||
|
});
|
||||||
|
|
||||||
|
let pd_title = pd_title.to_owned();
|
||||||
|
let mut ep = ep.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let dl_fold = downloader::get_dl_folder(&pd_title).unwrap();
|
||||||
|
let e = downloader::get_episode(db, &mut ep, dl_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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive() -> glib::Continue {
|
||||||
|
GLOBAL.with(|global| {
|
||||||
|
if let Some((ref dl_bttn, ref play_bttn, ref reciever)) = *global.borrow() {
|
||||||
|
if reciever.try_recv().is_ok() {
|
||||||
|
dl_bttn.hide();
|
||||||
|
play_bttn.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
glib::Continue(false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn episodes_listbox(connection: Arc<Mutex<SqliteConnection>>, pd_title: &str) -> gtk::ListBox {
|
pub fn episodes_listbox(connection: Arc<Mutex<SqliteConnection>>, pd_title: &str) -> gtk::ListBox {
|
||||||
// TODO: handle unwraps.
|
// TODO: handle unwraps.
|
||||||
|
|||||||
@ -102,10 +102,11 @@ pub fn podcast_liststore(connection: &SqliteConnection) -> gtk::ListStore {
|
|||||||
// &Podcast){
|
// &Podcast){
|
||||||
// let old = stack.get_child_by_name("pdw").unwrap();
|
// let old = stack.get_child_by_name("pdw").unwrap();
|
||||||
// let pdw = pd_widget_from_diesel_model(&db.clone(), pd, &stack.clone());
|
// let pdw = pd_widget_from_diesel_model(&db.clone(), pd, &stack.clone());
|
||||||
|
// let vis = stack.get_visible_child_name().unwrap();
|
||||||
|
|
||||||
// stack.remove(&old);
|
// stack.remove(&old);
|
||||||
// stack.add_named(&pdw, "pdw");
|
// stack.add_named(&pdw, "pdw");
|
||||||
// stack.set_visible_child_full("pdw", StackTransitionType::None);
|
// stack.set_visible_child_name(&vis);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn pd_widget_from_diesel_model(db: Arc<Mutex<SqliteConnection>>, pd: &Podcast) -> gtk::Box {
|
pub fn pd_widget_from_diesel_model(db: Arc<Mutex<SqliteConnection>>, pd: &Podcast) -> gtk::Box {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user