Something went wrong. Try again.
A terminal app to allow for easy voice recording
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687use anyhow::{anyhow, Result};use chrono::Local;use std::fs;use std::path::PathBuf;
pub fn get_voice_notes_dir() -> Result<PathBuf> { let dir = std::env::var("VOICE_NOTES") .map_err(|_| anyhow!("$VOICE_NOTES environment variable is not set.\nSet it with: export VOICE_NOTES=/path/to/notes"))?; Ok(PathBuf::from(dir))}
pub fn get_todays_dir() -> Result<PathBuf> { let base = get_voice_notes_dir()?; let today = Local::now().format("%Y-%m-%d").to_string(); let dir = base.join(today); fs::create_dir_all(&dir)?; Ok(dir)}
/// Determines the next recording path: $VOICE_NOTES/YYYY-MM-DD/HH-MM-SS_note-N.mp3pub fn next_recording_path() -> Result<PathBuf> { let dir = get_todays_dir()?;
let count = fs::read_dir(&dir)? .filter_map(|e| e.ok()) .filter(|e| { e.path() .extension() .and_then(|ext| ext.to_str()) .map(|ext| ext.eq_ignore_ascii_case("mp3")) .unwrap_or(false) }) .count();
let filename = format!("practice-{}.mp3", count + 1);
Ok(dir.join(filename))}
/// Returns (date_label, sorted_mp3_paths) pairs, newest dates first.pub fn list_recordings() -> Result<Vec<(String, Vec<PathBuf>)>> { let base = get_voice_notes_dir()?;
if !base.exists() { return Ok(vec![]); }
let mut entries: Vec<_> = fs::read_dir(&base)? .filter_map(|e| e.ok()) .filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false)) .collect();
// Newest dates first (reverse lexicographic on YYYY-MM-DD) entries.sort_by(|a, b| b.file_name().cmp(&a.file_name()));
let mut result = Vec::new();
for entry in entries { let date = entry.file_name().to_string_lossy().to_string();
let mut files: Vec<PathBuf> = fs::read_dir(entry.path())? .filter_map(|e| e.ok()) .filter(|e| { e.path() .extension() .and_then(|ext| ext.to_str()) .map(|ext| ext.eq_ignore_ascii_case("mp3")) .unwrap_or(false) }) .map(|e| e.path()) .collect();
files.sort_by(|a, b| { let mt = |p: &std::path::PathBuf| { std::fs::metadata(p).and_then(|m| m.modified()).ok() }; mt(b).cmp(&mt(a)) // newest modified time first });
if !files.is_empty() { result.push((date, files)); } }
Ok(result)}