feat: better error handling

errors during the upload are now shown in a separate user-friendly alert
dialog, and you can also choose to upload the file to no folder
This commit is contained in:
uku 2025-05-11 23:21:28 +02:00
parent 601ee85b5f
commit 94562b995a
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
4 changed files with 174 additions and 36 deletions

View file

@ -1,12 +1,14 @@
mod gobject;
mod relm;
mod zipline;
use std::{borrow::Cow, path::PathBuf, time::Duration};
use color_eyre::eyre::{OptionExt, Result, bail};
use gobject::GtkZiplineFolder;
use relm::{Dialog, DialogInput};
use relm4::{
ComponentParts, RelmApp, SimpleComponent,
Component, ComponentController, ComponentParts, Controller, RelmApp, SimpleComponent,
adw::{self, prelude::*},
gtk::{self, gio, glib::clone},
};
@ -40,6 +42,7 @@ enum Message {
SetPath(PathBuf),
SetFolder(ZiplineFolder),
StartTheProcess,
Nothing,
}
struct Widgets {
@ -50,7 +53,8 @@ struct Widgets {
struct Tyrolienne {
config: Config,
video_path: Option<PathBuf>,
folder: ZiplineFolder,
folder: Option<ZiplineFolder>,
dialog: Controller<Dialog>,
}
impl Tyrolienne {
@ -84,7 +88,10 @@ impl SimpleComponent for Tyrolienne {
let model = Tyrolienne {
config,
video_path: None,
folder: folders[0].clone(),
folder: None,
dialog: Dialog::builder()
.launch(root.clone())
.forward(sender.input_sender(), |_| Message::Nothing),
};
let file_picker_row = adw::ActionRow::builder()
@ -116,10 +123,12 @@ impl SimpleComponent for Tyrolienne {
}
));
let gtk_folders = folders
let mut gtk_folders = folders
.iter()
.map(GtkZiplineFolder::from_folder)
.collect::<Vec<_>>();
gtk_folders.insert(0, GtkZiplineFolder::none());
let store = gio::ListStore::new::<GtkZiplineFolder>();
store.extend_from_slice(&gtk_folders);
@ -186,9 +195,18 @@ impl SimpleComponent for Tyrolienne {
fn update(&mut self, message: Self::Input, _sender: relm4::ComponentSender<Self>) {
match message {
Message::Nothing => {}
Message::SetPath(path) => self.video_path = Some(path),
Message::SetFolder(folder) => self.folder = folder,
Message::StartTheProcess => the_process(self).unwrap(),
Message::SetFolder(folder) => {
self.folder = (folder.id != GtkZiplineFolder::NONE_ID).then_some(folder)
}
Message::StartTheProcess => match the_process(self) {
Ok(url) => tracing::info!("{url}"),
Err(e) => self.dialog.emit(DialogInput::Show {
heading: "An error occurred".into(),
body: e.to_string(),
}),
},
}
}
@ -247,17 +265,25 @@ fn get_config() -> Result<Config> {
Ok(config)
}
fn the_process(app: &Tyrolienne) -> Result<()> {
tracing::info!("uploading to folder '{}'...", app.folder.name);
fn the_process(app: &Tyrolienne) -> Result<String> {
if let Some(folder) = app.folder.as_ref() {
tracing::info!("uploading to folder '{}'...", folder.name);
} else {
tracing::info!("uploading video...");
}
let res = zipline::upload_file(&app.config, &app.folder, app.video_path.as_ref().unwrap())?;
let res = zipline::upload_file(
&app.config,
app.folder.as_ref(),
app.video_path.as_ref().unwrap(),
)?;
let zp_file = &res.files[0];
tracing::info!("recalculating thumbnails...");
zipline::recalc_thumbnails(&app.config)?;
std::thread::sleep(Duration::from_secs(5));
std::thread::sleep(Duration::from_secs(2));
tracing::info!("fetching thumbnail url...");
@ -267,12 +293,9 @@ fn the_process(app: &Tyrolienne) -> Result<()> {
.ok_or_eyre("could not get thumbnail url")?;
// TODO get w&h from video
let autocomp_url = format!(
Ok(format!(
"https://autocompressor.net/av1?v={}&i={}&w=1920&h=1080",
Encoded(&zp_file.url),
Encoded(&thumbnail_url)
);
tracing::info!("url: {autocomp_url}");
Ok(())
))
}