add notify option

This commit is contained in:
Robin Appelman 2025-11-11 01:21:47 +01:00
commit ea24479757
7 changed files with 878 additions and 19 deletions

View file

@ -35,6 +35,8 @@ pub struct WatchConfig {
symlink: Option<String>,
#[serde(rename = "remove-duplicates", default)]
pub remove_duplicates: bool,
#[serde(default)]
pub notify: bool,
}
impl WatchConfig {

View file

@ -8,12 +8,13 @@ use main_error::MainResult;
use notify_debouncer_full::notify::event::{AccessKind, AccessMode, ModifyKind, RenameMode};
use notify_debouncer_full::notify::{EventKind, RecursiveMode};
use notify_debouncer_full::{new_debouncer, DebounceEventResult};
use notify_rust::{Hint, Notification};
use std::fs::{copy, create_dir_all, read_dir, remove_file, rename};
use std::io::ErrorKind;
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::sync::mpsc::channel;
use std::thread::sleep;
use std::thread::{sleep, spawn};
use std::time::Duration;
use tracing::{debug, error, info, instrument};
@ -94,6 +95,7 @@ fn main() -> MainResult {
&rules,
symlink.as_deref(),
config.watch.remove_duplicates,
config.watch.notify,
);
}
}
@ -107,6 +109,7 @@ fn handle_watch_event(
rules: &[Rule],
link_target: Option<&str>,
remove_duplicates: bool,
notify: bool,
) {
let handle_path = |path: &Path| {
// give originfox time to set xattr
@ -117,10 +120,14 @@ fn handle_watch_event(
}
match FileInfo::load(path) {
Ok(file) => maybe_link(
handle_file(&file, rules, remove_duplicates).as_deref(),
link_target,
),
Ok(file) => {
if let Some(new_path) = handle_file(&file, rules, remove_duplicates) {
maybe_link_target(&new_path, link_target);
if notify {
show_notification(new_path);
}
};
}
Err(error) => {
error!(%error, "failed to load file info");
}
@ -166,8 +173,47 @@ fn is_part(path: &Path) -> bool {
path.extension().and_then(|ext| ext.to_str()) == Some("part")
}
fn maybe_link(source: Option<&Path>, target: Option<&str>) {
if let (Some(source), Some(target)) = (source, target) {
fn show_notification(source: PathBuf) {
debug!(file = %source.display(), "showing notification for file");
match Notification::new()
.summary("Download moved")
.appname("Galton")
.body(&format!(
"<a href=\"{}\">{}</a>",
source.display(),
source.file_name().unwrap().to_string_lossy()
))
.hint(Hint::ActionIcons(true))
.hint(Hint::Category("transfer.complete".into()))
.action("document-open", "Open")
.action("folder-open", "Open Containing folder")
.show()
{
Ok(notification) => {
spawn(move || {
notification.wait_for_action(|action| match action {
"document-open" => {
if let Err(error) = open::that(&source) {
error!(%error, file = %source.display(), "failed to open file from notification");
}
}
"folder-open" => {
if let Err(error) = open::that(source.parent().unwrap()) {
error!(%error, file = %source.display(), "failed to open parent folder from notification");
}
}
_ => (),
});
});
}
Err(error) => {
error!(%error, "Failed to show notification");
}
}
}
fn maybe_link_target(source: &Path, target: Option<&str>) {
if let Some(target) = target {
if Path::new(target).is_symlink() {
if let Err(error) = remove_file(target) {
error!(%error, "failed to remove link target");