Initial commit
This commit is contained in:
commit
fb9be91262
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
\#*
|
||||
.idea
|
||||
*\~*
|
1090
Cargo.lock
generated
Normal file
1090
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
25
Cargo.toml
Normal file
25
Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "zdiu"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
gtk = "0"
|
||||
glib = "0"
|
||||
anyhow = "1"
|
||||
|
||||
[dependencies.json]
|
||||
version = "0"
|
||||
|
||||
[dependencies.ureq]
|
||||
version = "2"
|
||||
default-features = false
|
||||
features = [ "tls" ]
|
||||
|
||||
[dependencies.multipart]
|
||||
version = "0"
|
||||
default-features = false
|
||||
features = [ "client" ]
|
69
src/discord.rs
Normal file
69
src/discord.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use std::io::Read;
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use multipart::client::lazy::Multipart;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DiscordJsonError {
|
||||
invalid_json: String
|
||||
}
|
||||
|
||||
impl Display for DiscordJsonError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Discord API sent invalid JSON: {}", self.invalid_json)
|
||||
}
|
||||
}
|
||||
|
||||
impl DiscordJsonError {
|
||||
fn new(invalid_json: String) -> Self {
|
||||
Self { invalid_json }
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for DiscordJsonError {}
|
||||
|
||||
struct CountingRead<'a, T, F> {
|
||||
inner_stream: &'a mut T,
|
||||
current_progress: u64,
|
||||
progress_callback: F
|
||||
}
|
||||
|
||||
impl<'a, T: Read, F: FnMut(u64)> CountingRead<'a, T, F> {
|
||||
fn new(inner_stream: &'a mut T, progress_callback: F) -> Self {
|
||||
Self {
|
||||
inner_stream,
|
||||
current_progress: 0,
|
||||
progress_callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read, F: FnMut(u64)> Read for CountingRead<'_, T, F> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let result = self.inner_stream.read(buf);
|
||||
if let Ok(o) = result {
|
||||
self.current_progress += o as u64;
|
||||
(self.progress_callback)(self.current_progress);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upload_discord<F: FnMut(f64)>(filename: &str, data: &[u8], webhook: &str, mut percent_callback: F) -> anyhow::Result<(String, String)> {
|
||||
let mut cursor = io::Cursor::new(data);
|
||||
let mut mp = Multipart::new();
|
||||
let counting_reader = CountingRead::new(&mut cursor, move |bytes| {
|
||||
(percent_callback)(bytes as f64 / data.len() as f64);
|
||||
});
|
||||
mp.add_stream("file", counting_reader, Some(filename.to_string()), None);
|
||||
let mpdata = mp.prepare()?;
|
||||
let response = ureq::post(webhook)
|
||||
.set("Content-Type", &format!("multipart/form-data; boundary={}", mpdata.boundary()))
|
||||
.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))
|
||||
}
|
59
src/main.rs
Normal file
59
src/main.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use gtk::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::glib::clone;
|
||||
use std::sync::{Mutex, Arc};
|
||||
use glib::Sender;
|
||||
|
||||
mod discord;
|
||||
|
||||
fn main() {
|
||||
let app = Application::builder().application_id("moe.lemonsh.zdiu").build();
|
||||
app.connect_activate(build_ui);
|
||||
app.run();
|
||||
}
|
||||
|
||||
fn errormsg<P: IsA<Window>>(text: &str, parent: Option<&P>) {
|
||||
let dialog = MessageDialog::new(parent, DialogFlags::MODAL, MessageType::Error, ButtonsType::Ok, text);
|
||||
dialog.run();
|
||||
dialog.close();
|
||||
}
|
||||
|
||||
enum UiThreadTask {
|
||||
UpdateProgress(f64), Finalize(String)
|
||||
}
|
||||
|
||||
fn upload_file_task(tx: Sender<UiThreadTask>) {
|
||||
|
||||
}
|
||||
|
||||
fn build_ui(app: &Application) {
|
||||
let builder = gtk::Builder::from_string(include_str!("zdiu.glade"));
|
||||
let window: ApplicationWindow = builder.object("window").unwrap();
|
||||
let (tx, rx) = glib::MainContext::channel::<UiThreadTask>(glib::PRIORITY_DEFAULT);
|
||||
|
||||
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();
|
||||
|
||||
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); });
|
||||
}));
|
||||
copy_button.connect_clicked(clone!(@weak output_field => move |_| {
|
||||
gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD).set_text(output_field.text().as_str());
|
||||
}));
|
||||
output_field.set_text("AE");
|
||||
|
||||
rx.attach(None, move |data| {
|
||||
glib::Continue(true)
|
||||
});
|
||||
window.set_application(Some(app));
|
||||
window.present();
|
||||
}
|
||||
|
137
src/zdiu.glade
Normal file
137
src/zdiu.glade
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.2 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkApplicationWindow" id="window">
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<!-- n-columns=2 n-rows=4 -->
|
||||
<object class="GtkGrid" id="main_container">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">15</property>
|
||||
<property name="margin-end">15</property>
|
||||
<property name="margin-top">15</property>
|
||||
<property name="margin-bottom">15</property>
|
||||
<property name="row-spacing">5</property>
|
||||
<property name="column-spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="output_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="width-chars">25</property>
|
||||
<property name="caps-lock-warning">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkProgressBar" id="upload_progress">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="text" translatable="yes">0%</property>
|
||||
<property name="show-text">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="copy_button">
|
||||
<property name="label" translatable="yes">Copy</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=4 n-rows=1 -->
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="clip_upload_button">
|
||||
<property name="label" translatable="yes">Image from clipboard</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">3</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">or</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Upload</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFileChooserButton" id="file_upload_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="title" translatable="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="settings">
|
||||
<property name="label">gtk-preferences</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="use-stock">True</property>
|
||||
<property name="always-show-image">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
Loading…
Reference in a new issue