123 lines
4.9 KiB
Rust
123 lines
4.9 KiB
Rust
use std::path::PathBuf;
|
|
use anyhow::Result;
|
|
use notify::{Watcher, RecursiveMode, Event, EventKind};
|
|
use tokio::sync::mpsc;
|
|
|
|
mod services;
|
|
use services::sermon_converter::VideoConverter;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<()> {
|
|
let watch_path = PathBuf::from("/home/rockvilleav/Sync/Sermons");
|
|
let output_path = PathBuf::from("/media/archive/jellyfin/sermons");
|
|
|
|
// Ensure directories exist
|
|
if !watch_path.exists() {
|
|
println!("Creating watch directory: {}", watch_path.display());
|
|
std::fs::create_dir_all(&watch_path)?;
|
|
}
|
|
if !output_path.exists() {
|
|
println!("Creating output directory: {}", output_path.display());
|
|
std::fs::create_dir_all(&output_path)?;
|
|
}
|
|
|
|
println!("Starting sermon converter service...");
|
|
println!("Watching directory: {}", watch_path.display());
|
|
println!("Output directory: {}", output_path.display());
|
|
|
|
let converter = VideoConverter::new(output_path);
|
|
|
|
// Process existing files first
|
|
println!("Checking for existing files...");
|
|
if let Ok(entries) = std::fs::read_dir(&watch_path) {
|
|
for entry in entries {
|
|
if let Ok(entry) = entry {
|
|
let path = entry.path();
|
|
if path.to_string_lossy().contains(".syncthing.") {
|
|
println!("Skipping temporary file: {}", path.display());
|
|
continue;
|
|
}
|
|
if let Some(ext) = path.extension() {
|
|
if ext == "mp4" {
|
|
println!("Processing existing MP4 file: {}", path.display());
|
|
if let Err(e) = converter.process_file(path).await {
|
|
eprintln!("Error processing existing file: {}", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set up file watcher
|
|
let (tx, mut rx) = mpsc::channel(100);
|
|
|
|
let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| {
|
|
let tx = tx.clone();
|
|
match res {
|
|
Ok(event) => {
|
|
match &event.kind {
|
|
EventKind::Create(_) => println!("File created: {:?}", event.paths),
|
|
EventKind::Modify(notify::event::ModifyKind::Name(mode)) => {
|
|
match mode {
|
|
notify::event::RenameMode::From => println!("File renamed from: {:?}", event.paths),
|
|
notify::event::RenameMode::To => println!("File renamed to: {:?}", event.paths),
|
|
notify::event::RenameMode::Both => println!("File renamed: {:?}", event.paths),
|
|
_ => println!("Other rename event: {:?}", event),
|
|
}
|
|
},
|
|
_ => println!("Other file event: {:?}", event),
|
|
}
|
|
|
|
if let Err(e) = tx.blocking_send(event) {
|
|
eprintln!("Error sending event: {}", e);
|
|
}
|
|
}
|
|
Err(e) => eprintln!("Watch error: {}", e),
|
|
}
|
|
})?;
|
|
|
|
watcher.watch(&watch_path, RecursiveMode::NonRecursive)?;
|
|
println!("Watcher started successfully");
|
|
|
|
while let Some(event) = rx.recv().await {
|
|
match event.kind {
|
|
EventKind::Create(_) |
|
|
EventKind::Modify(notify::event::ModifyKind::Name(notify::event::RenameMode::To)) => {
|
|
for path in event.paths {
|
|
// Skip temporary and non-MP4 files
|
|
if path.to_string_lossy().contains(".syncthing.") {
|
|
println!("Skipping temporary Syncthing file: {}", path.display());
|
|
continue;
|
|
}
|
|
|
|
if let Some(ext) = path.extension() {
|
|
if ext == "mp4" {
|
|
println!("New MP4 file detected: {}", path.display());
|
|
// Wait a short time to ensure file is fully written
|
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
|
|
|
println!("Starting processing for: {}", path.display());
|
|
if let Err(e) = converter.process_file(path.clone()).await {
|
|
eprintln!("Error processing file {}: {}", path.display(), e);
|
|
} else {
|
|
println!("Successfully processed: {}", path.display());
|
|
}
|
|
} else {
|
|
println!("Ignoring non-MP4 file: {}", path.display());
|
|
}
|
|
} else {
|
|
println!("Ignoring file without extension: {}", path.display());
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
// Log other events at debug level
|
|
println!("Ignoring event: {:?}", event);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|