diff --git a/Cargo.lock b/Cargo.lock index f2838aa..f274c58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,8 @@ checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" [[package]] name = "atk" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a83b21d2aa75e464db56225e1bda2dd5993311ba1095acaa8fa03d1ae67026ba" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "atk-sys", "bitflags", @@ -22,9 +21,8 @@ dependencies = [ [[package]] name = "atk-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "glib-sys", "gobject-sys", @@ -58,9 +56,8 @@ checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" [[package]] name = "cairo-rs" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f859ade407c19810ae920b4fafab92189ed312adad490d08fb16b5f49f1e2207" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "bitflags", "cairo-sys-rs", @@ -71,9 +68,8 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c9c3928781e8a017ece15eace05230f04b647457d170d2d9641c94a444ff80" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "glib-sys", "libc", @@ -88,9 +84,9 @@ checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-expr" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" +checksum = "edae0b9625d1fce32f7d64b71784d9b1bf8469ec1a9c417e44aaf16a9cbd7571" dependencies = [ "smallvec", ] @@ -108,10 +104,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" [[package]] -name = "either" -version = "1.6.1" +name = "directories" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] [[package]] name = "field-offset" @@ -187,9 +197,8 @@ dependencies = [ [[package]] name = "gdk" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a453eae5ec10345b3a96ca1b547328bfc94edd40aa95b08f14bb4c35863db140" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "bitflags", "cairo-rs", @@ -203,9 +212,8 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534192cb8f01daeb8fab2c8d4baa8f9aae5b7a39130525779f5c2608e235b10f" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "gdk-pixbuf-sys", "gio", @@ -215,9 +223,8 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "gio-sys", "glib-sys", @@ -228,9 +235,8 @@ dependencies = [ [[package]] name = "gdk-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -256,9 +262,8 @@ dependencies = [ [[package]] name = "gio" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a4c12fcba7a6402ae843a0085ec16d3658a87901763b6a7f0a7c5d60e555a5" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "bitflags", "futures-channel", @@ -273,9 +278,8 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "glib-sys", "gobject-sys", @@ -286,9 +290,8 @@ dependencies = [ [[package]] name = "glib" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a930b7208e6e0ab839eea5f65ac2b82109f729621430d47fe905e2e09d33f4" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "bitflags", "futures-channel", @@ -305,9 +308,8 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "anyhow", "heck", @@ -320,9 +322,8 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "libc", "system-deps", @@ -330,9 +331,8 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "glib-sys", "libc", @@ -341,9 +341,8 @@ dependencies = [ [[package]] name = "gtk" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6603bb79ded6ac6f3bac203794383afa8b1d6a8656d34a93a88f0b22826cd46c" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "atk", "bitflags", @@ -364,9 +363,8 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -382,9 +380,8 @@ dependencies = [ [[package]] name = "gtk3-macros" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21de1da96dc117443fb03c2e270b2d34b7de98d0a79a19bbb689476173745b79" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk3-rs#dac484857793cebac5becc15fe605dd99f3453a4" dependencies = [ "anyhow", "heck", @@ -415,15 +412,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "itertools" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" -dependencies = [ - "either", -] - [[package]] name = "js-sys" version = "0.3.55" @@ -512,9 +500,8 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "pango" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc88307d9797976ea62722ff2ec5de3fae279c6e20100ed3f49ca1a4bf3f96" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "bitflags", "glib", @@ -525,9 +512,8 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe" +version = "0.15.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#eb0d2f89f1dc4f0bdb4ae011a46626fea946ea2d" dependencies = [ "glib-sys", "gobject-sys", @@ -675,6 +661,16 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -773,24 +769,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syn" version = "1.0.76" @@ -804,18 +782,13 @@ dependencies = [ [[package]] name = "system-deps" -version = "3.2.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" +checksum = "6c1889ab44c2a423ba9ba4d64cd04989b25c0280ca7ade813f05368418722a04" dependencies = [ - "anyhow", "cfg-expr", "heck", - "itertools", "pkg-config", - "strum", - "strum_macros", - "thiserror", "toml", "version-compare", ] @@ -1082,7 +1055,7 @@ name = "zdiu" version = "0.1.0" dependencies = [ "anyhow", - "glib", + "directories", "gtk", "json", "multipart", diff --git a/Cargo.toml b/Cargo.toml index 43f796e..13e82b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" lto = true [dependencies] -gtk = "0" -glib = "0" +gtk = { git = "https://github.com/gtk-rs/gtk3-rs" } anyhow = "1" +directories = "4.0" [dependencies.json] version = "0" diff --git a/src/discord.rs b/src/discord.rs index feb40a8..ae3a148 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -50,7 +50,7 @@ impl Read for CountingRead<'_, T, F> { } } -pub fn upload_discord(filename: &str, data: &[u8], webhook: &str, mut percent_callback: F) -> anyhow::Result<(String, String)> { +pub fn upload_discord(filename: &str, data: &[u8], webhook: &str, mut percent_callback: F) -> anyhow::Result { let mut cursor = io::Cursor::new(data); let mut mp = Multipart::new(); let counting_reader = CountingRead::new(&mut cursor, move |bytes| { @@ -63,7 +63,5 @@ pub fn upload_discord(filename: &str, data: &[u8], webhook: &str, .send(mpdata)?; let response_string = response.into_string()?; let mut rjson = json::parse(&response_string)?; - let url = rjson["attachments"][0]["url"].take_string().ok_or_else(|| DiscordJsonError::new(response_string.clone()))?; - let id = rjson["id"].take_string().ok_or_else(|| DiscordJsonError::new(response_string.clone()))?; - Ok((url, id)) + Ok(rjson["attachments"][0]["url"].take_string().ok_or_else(|| DiscordJsonError::new(response_string.clone()))?) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2fc3901..de76347 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,16 @@ use gtk::*; use gtk::prelude::*; use gtk::glib::clone; -use std::sync::{Mutex, Arc}; use glib::Sender; +use std::fs::File; +use std::fs; +use std::path::Path; +use std::io::{SeekFrom, Seek, Read}; +use anyhow::anyhow; +use crate::discord::upload_discord; mod discord; +const MAXBUF: u64 = 8_380_416; fn main() { let app = Application::builder().application_id("moe.lemonsh.zdiu").build(); @@ -19,11 +25,35 @@ fn errormsg>(text: &str, parent: Option<&P>) { } enum UiThreadTask { - UpdateProgress(f64), Finalize(String) + UpdateProgress(f64), Finalize(anyhow::Result) } -fn upload_file_task(tx: Sender) { +fn upload_file_task(tx: &Sender, mut file: File, size: u64, name: &str, webhook: &str) -> anyhow::Result { + let mut buffer = vec![0_u8; size as usize]; + file.read_exact(&mut buffer[..])?; + upload_discord(name, &buffer, webhook, move |fr| { + tx.send(UiThreadTask::UpdateProgress(fr)).unwrap(); + }) +} +fn lock_gui(file_upload_button: &FileChooserButton, clip_upload_button: &Button, webhook_control: &Button, progress: &ProgressBar) { + file_upload_button.set_sensitive(false); + clip_upload_button.set_sensitive(false); + webhook_control.set_sensitive(false); + progress.set_fraction(0.0); + progress.set_text(Some("Loading...")); +} + +fn open_limited_and_get_name(path: &Path) -> anyhow::Result<(File, u64, String)> { + let filename = path.file_name().unwrap().to_str().unwrap(); + let mut file_handle = File::open(path)?; + let filesize = file_handle.seek(SeekFrom::End(0))?; + file_handle.seek(SeekFrom::Start(0))?; + if filesize > MAXBUF { + Err(anyhow!("File is too big.")) + } else { + Ok((file_handle, filesize, filename.to_string())) + } } fn build_ui(app: &Application) { @@ -33,27 +63,119 @@ fn build_ui(app: &Application) { let file_upload_button: FileChooserButton = builder.object("file_upload_button").unwrap(); let clip_upload_button: Button = builder.object("clip_upload_button").unwrap(); - let settings_button: Button = builder.object("settings").unwrap(); let progress: ProgressBar = builder.object("upload_progress").unwrap(); let copy_button: Button = builder.object("copy_button").unwrap(); let output_field: Entry = builder.object("output_box").unwrap(); + let webhook_entry: Entry = builder.object("webhook_entry").unwrap(); + let webhook_control: Button = builder.object("webhook_control").unwrap(); - file_upload_button.connect_file_set(clone!(@strong tx, @weak file_upload_button, @weak clip_upload_button, @weak settings_button, @weak progress => move |b| { - file_upload_button.set_sensitive(false); - clip_upload_button.set_sensitive(false); - settings_button.set_sensitive(false); - let new_sender = tx.clone(); - std::thread::spawn(move || { upload_file_task(new_sender); }); + let projectdir = directories::ProjectDirs::from("moe", "lemonsh", "zdiu").unwrap(); + let configdir = projectdir.config_dir(); + if !configdir.is_dir() { + fs::create_dir_all(configdir).unwrap(); + } + let webhookpath = configdir.join("webhook.txt"); + if webhookpath.is_file() { + webhook_entry.set_text(fs::read_to_string(&webhookpath).unwrap().as_str()); + } + + file_upload_button.connect_file_set(clone!(@strong tx, @weak window, @weak webhook_entry, @weak clip_upload_button, @weak webhook_control, @weak progress => move |b| { + let webhook = webhook_entry.text().to_string(); + if webhook.is_empty() { + errormsg("Set a webhook first.", Some(&window)); + b.unselect_all(); + return; + } + let file = b.filename().unwrap(); + match open_limited_and_get_name(&file) { + Ok(o) => { + lock_gui(b, &clip_upload_button, &webhook_control, &progress); + let new_sender = tx.clone(); + std::thread::spawn(move || { + let result = upload_file_task(&new_sender, o.0, o.1, &o.2, &webhook); + new_sender.send(UiThreadTask::Finalize(result)).unwrap(); + }); + } + Err(e) => { + errormsg(e.to_string().as_str(), Some(&window)); + b.unselect_all(); + } + }; + })); + clip_upload_button.connect_clicked(clone!(@strong tx, @weak window, @weak webhook_entry, @weak file_upload_button, @weak webhook_control, @weak progress => move |b| { + let webhook = webhook_entry.text().to_string(); + if webhook.is_empty() { + errormsg("Set a webhook first.", Some(&window)); + return; + } + match gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD).wait_for_image() { + Some(p) => { + let pngbuffer = p.save_to_bufferv("png", &[]).unwrap(); + lock_gui(&file_upload_button, b, &webhook_control, &progress); + let new_sender = tx.clone(); + std::thread::spawn(move || { + let result = upload_discord("zdiupload.png", &pngbuffer, webhook.as_str(), |fr| { + new_sender.send(UiThreadTask::UpdateProgress(fr)).unwrap(); + }); + new_sender.send(UiThreadTask::Finalize(result)).unwrap(); + }); + } + None => { + errormsg("There are no images in the clipboard.", Some(&window)); + } + } })); copy_button.connect_clicked(clone!(@weak output_field => move |_| { - gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD).set_text(output_field.text().as_str()); + let text = output_field.text(); + if !text.is_empty() { + gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD).set_text(text.as_str()); + } + })); + webhook_control.connect_clicked(clone!(@weak window, @weak webhook_entry, @weak file_upload_button, @weak clip_upload_button => move |b| { + if webhook_entry.get_sensitive() { + file_upload_button.set_sensitive(true); + clip_upload_button.set_sensitive(true); + webhook_entry.set_sensitive(false); + webhook_entry.set_visibility(false); + b.set_label("Edit"); + if let Err(e) = fs::write(&webhookpath, webhook_entry.text().as_str()) { + errormsg(format!("Couldn't save webhook: {}", e).as_str(), Some(&window)); + } else { + println!("Saved webhook to '{:?}'", &webhookpath); + } + } else { + file_upload_button.set_sensitive(false); + clip_upload_button.set_sensitive(false); + webhook_entry.set_sensitive(true); + webhook_entry.set_visibility(true); + b.set_label("Save"); + } })); - output_field.set_text("AE"); - rx.attach(None, move |data| { + rx.attach(None, clone!(@strong window => move |data| { + match data { + UiThreadTask::UpdateProgress(p) => { + progress.set_fraction(p); + progress.set_text(Some(format!("{:.1}%", p*100.0).as_str())); + } + UiThreadTask::Finalize(u) => { + file_upload_button.set_sensitive(true); + clip_upload_button.set_sensitive(true); + webhook_control.set_sensitive(true); + progress.set_fraction(0.0); + progress.set_text(Some("0%")); + match u { + Ok(o) => { + output_field.set_text(o.as_str()); + } + Err(e) => { + errormsg(e.to_string().as_str(), Some(&window)); + } + } + } + } glib::Continue(true) - }); + })); window.set_application(Some(app)); window.present(); } - diff --git a/src/zdiu.glade b/src/zdiu.glade index ab42aa3..dbfe7ac 100644 --- a/src/zdiu.glade +++ b/src/zdiu.glade @@ -5,7 +5,7 @@ False - + True False @@ -27,7 +27,7 @@ 0 - 2 + 3 @@ -36,12 +36,11 @@ False 5 5 - 0% True 0 - 1 + 2 2 @@ -55,7 +54,64 @@ 1 - 2 + 3 + + + + + True + False + True + False + * + Webhook URL + password + + + 0 + 5 + + + + + Edit + True + True + True + + + 1 + 5 + + + + + True + False + + + 0 + 4 + 2 + + + + + True + False + center + 5 + zdiu + + + + + + + + 0 + 0 + 2 @@ -112,22 +168,7 @@ 0 - 0 - 2 - - - - - gtk-preferences - True - True - True - True - True - - - 0 - 3 + 1 2