updated functions and refactor

This commit is contained in:
shinya 2026-01-30 17:20:53 +01:00
parent 6dd66b582b
commit 87508b6908
5 changed files with 108 additions and 19 deletions

View File

@ -1,5 +1,5 @@
[package]
name = "lrclib-downloader"
name = "lrcli"
version = "0.1.0"
edition = "2024"

View File

@ -1 +0,0 @@

View File

@ -1,15 +1,63 @@
use crate::lrclib;
use serde_json::Value;
use std::collections::HashMap;
use std::fs;
use std::io::{self, Write};
use std::time::Duration;
pub fn get_lyrics_text(artist_name: &str, track_name: &str, album_name: &str, duration: Duration) {
match lrclib::get_lyrics(artist_name, track_name, album_name, duration) {
Some(lyrics_json) => match serde_json::from_str::<serde_json::Value>(&lyrics_json) {
Ok(parsed) => {
let sync_lyrics = &parsed["syncedLyrics"];
println!("{sync_lyrics}\n");
}
Err(e) => eprintln!("Failed to parse lyrics JSON: {e}"),
},
None => eprintln!("Failed to fetch lyrics for {track_name}"),
const CONFIG_PATH: &str = "/tmp/lrcli.json";
type Config = HashMap<String, HashMap<String, String>>;
pub fn get_lyrics_text(
artist_name: &str,
track_name: &str,
album_name: &str,
duration: Duration,
) -> Result<Value, String> {
let lyrics_json = lrclib::get_lyrics(artist_name, track_name, album_name, duration)
.ok_or_else(|| format!("Failed to fetch lyrics for {track_name}"))?;
let parsed: Value = serde_json::from_str(&lyrics_json)
.map_err(|e| format!("Failed to parse lyrics JSON: {e}"))?;
let synced_lyrics = parsed
.get("syncedLyrics")
.ok_or_else(|| "Missing `syncedLyrics` field".to_string())?;
Ok(synced_lyrics.clone())
}
pub fn load_config() -> io::Result<Config> {
match fs::read_to_string(CONFIG_PATH) {
Ok(contents) => {
let cfg: Config = serde_json::from_str(&contents)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(cfg)
}
Err(err) if err.kind() == io::ErrorKind::NotFound => {
Ok(HashMap::new()) // no file yet → empty config
}
Err(err) => Err(err),
}
}
pub fn save_config(config: &Config) -> io::Result<()> {
let json = serde_json::to_string_pretty(config)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let mut file = fs::File::create(CONFIG_PATH)?;
file.write_all(json.as_bytes())?;
Ok(())
}
pub fn add_song(directory: &str, filename: &str, status: &str) -> io::Result<()> {
let mut config = load_config()?;
let dir_entry = config
.entry(directory.to_string())
.or_insert_with(HashMap::new);
dir_entry.insert(filename.to_string(), status.to_string());
save_config(&config)
}

View File

@ -1,19 +1,31 @@
use clap::Parser;
use std::path::PathBuf;
use core::time;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
mod json_parsing;
mod lrclib;
mod music;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
#[command(
version,
about = "Download synced lyrics (LRC) for music files using LRCLIB",
long_about = "Fetches time-synced lyrics from LRCLIB for one or more audio files. \
Supports batch downloads, directory processing, and watching for newly added tracks."
)]
struct Args {
/// One or more audio files to fetch lyrics for
#[arg(short, long, num_args = 1..)]
file: Option<Vec<PathBuf>>,
/// Target directory for downloaded lyrics.
/// When specified, lyrics will be saved alongside files in this directory
#[arg(short, long)]
directory: Option<PathBuf>,
/// Watch the directory for new audio files and fetch lyrics automatically.
/// Requires --directory
#[arg(short, long)]
watch: bool,
}
@ -37,7 +49,14 @@ fn main() {
eprintln!("Failed to process directory {}: {e}", directory.display());
}
} else {
println!("Watch directory for new files")
let sleep = time::Duration::from_secs(10);
watch(directory, sleep);
}
}
}
fn watch(path: &Path, wait: Duration) {
loop {
thread::sleep(wait);
}
}

View File

@ -37,19 +37,42 @@ pub fn get_song_file(path: &Path) -> Result<(), MusicError> {
return Ok(());
}
let info = get_song_info(path)?;
let pathbuf = path.to_path_buf();
let absolute_path = fs::canonicalize(&pathbuf).unwrap();
let info = get_song_info(&absolute_path)?;
println!("Track: {}", info.track_name);
println!("Artist: {}", info.artist_name);
println!("Album: {}", info.album_name);
println!("Duration: {:?}\n", info.duration);
json_parsing::get_lyrics_text(
match json_parsing::get_lyrics_text(
&info.artist_name,
&info.track_name,
&info.album_name,
info.duration,
);
) {
Ok(lyrics) => {
json_parsing::add_song(
absolute_path.parent().unwrap().to_str().unwrap(),
absolute_path.file_name().unwrap().to_str().unwrap(),
"Synchronized",
);
println!("{lyrics}")
}
Err(e) => {
json_parsing::add_song(
absolute_path.parent().unwrap().to_str().unwrap(),
absolute_path.file_name().unwrap().to_str().unwrap(),
"NotFound",
);
eprintln!(
"Failed to fetch lyrics for {}, error: {e}",
pathbuf.to_str().unwrap()
)
}
};
Ok(())
}