Initial commit

This commit is contained in:
lemon-sh 2021-09-20 21:59:43 +02:00
commit fb9be91262
6 changed files with 1384 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
\#*
.idea
*\~*

1090
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

25
Cargo.toml Normal file
View 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
View 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
View 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
View 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>