PixelAddict & Cluster
Hey Cluster, I’ve got this wild idea for a portable photo‑journaling tool that auto‑tags shots with GPS and lets you run a tiny server to sync to your laptop—thought we could code it in Rust and keep the UI minimal like your favorite editor. Wanna brainstorm?
Sure, but if you want to stay true to minimalism ditch full GUI libs and go terminal‑based, maybe use crossterm or tui‑rs. GPS tags can be pulled from exif, and a tiny server can live in the same binary using warp or tiny‑http. Keep dependencies lean, no heavy frameworks, and test each crate before pulling it in.
Nice plan, that keeps the stack tight and the spirit lean. I’ll pull a crossterm demo and test warp for the API loop first, then we can hook it into the EXIF parser. Let’s keep it simple, no bloat. Ready to dive?
Yeah, hit the code. Just keep an eye on memory, no dangling pointers, and remember to keep the dependencies as clean as my editor. Let's see that demo run.
use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use warp::Filter;
use exif::{Reader, Tag};
use crossterm::{
cursor,
execute,
style::{Color, Print, ResetColor, SetForegroundColor},
terminal::{Clear, ClearType},
};
use std::process::Command;
#[tokio::main]
async fn main() {
// Terminal UI
execute!(std::io::stdout(), Clear(ClearType::All), cursor::MoveTo(0, 0)).unwrap();
execute!(
std::io::stdout(),
SetForegroundColor(Color::Blue),
Print("Photo Journal CLI"),
ResetColor
)
.unwrap();
// Load a sample image and extract EXIF GPS
let mut buf = Vec::new();
File::open("sample.jpg").unwrap().read_to_end(&mut buf).unwrap();
let exif = Reader::new().read_raw(&buf).unwrap();
let gps_lat = exif.get_field(Tag::GPSLatitude, exif::In::PRIMARY).map(|f| f.display_value().to_string());
let gps_lon = exif.get_field(Tag::GPSLongitude, exif::In::PRIMARY).map(|f| f.display_value().to_string());
println!("GPS: {:?}, {:?}", gps_lat, gps_lon);
// Start a tiny HTTP server to sync photos
let photo_route = warp::path("photo")
.and(warp::post())
.and(warp::body::bytes())
.map(|bytes: bytes::Bytes| {
std::fs::write("uploaded.jpg", &bytes).unwrap();
warp::reply::with_status("ok", warp::http::StatusCode::OK)
});
let routes = photo_route;
let addr: SocketAddr = ([127, 0, 0, 1], 3030).into();
println!("Server running at http://{}/photo", addr);
warp::serve(routes).run(addr).await;
}
Nice, you got the core pieces. Just be careful with the EXIF parsing – if the image has no GPS tags the `unwrap` will crash. Maybe guard that and return a 400 instead of panicking. Also remember to spawn the server on a separate task if you want the UI loop to continue. Keep that tight.