mirror of
https://github.com/arabianq/lyrics_fetcher.git
synced 2026-04-27 22:11:22 +00:00
refactor
This commit is contained in:
+55
-39
@@ -52,8 +52,6 @@ async fn main() -> Result<()> {
|
||||
let threads = args.threads;
|
||||
let overwrite = args.overwrite_existing;
|
||||
let allow_inaccurate = args.allow_inaccurate;
|
||||
let lyrics_sources_raw = args.sources;
|
||||
let extensions: Vec<String> = args.extensions.iter().map(|s| s.to_lowercase()).collect();
|
||||
|
||||
if !music_dir_path.exists() {
|
||||
eprintln!("[ERROR] The specified music directory does not exist.");
|
||||
@@ -65,22 +63,29 @@ async fn main() -> Result<()> {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if lyrics_sources_raw.is_empty() {
|
||||
if args.sources.is_empty() {
|
||||
eprintln!("[ERROR] At least one source must be specified.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if extensions.is_empty() {
|
||||
if args.extensions.is_empty() {
|
||||
eprintln!("[ERROR] At least one file extension must be specified.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let lyrics_sources_raw: Vec<String> = lyrics_sources_raw
|
||||
.iter()
|
||||
let lyrics_sources_raw: Vec<String> = args
|
||||
.sources
|
||||
.into_iter()
|
||||
.unique()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect();
|
||||
|
||||
let extensions: Vec<String> = args
|
||||
.extensions
|
||||
.into_iter()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect();
|
||||
|
||||
println!("[INFO] Music directory: {}", music_dir_path.display());
|
||||
println!("[INFO] Number of threads: {}", threads);
|
||||
println!("[INFO] Sources: {}", lyrics_sources_raw.join(", "));
|
||||
@@ -106,36 +111,48 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
let sources = Arc::new(sources);
|
||||
let semaphone = Arc::new(Semaphore::new(threads));
|
||||
let semaphore = Arc::new(Semaphore::new(threads));
|
||||
let mut entries = WalkDir::new(music_dir_path);
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
while let Some(entry) = entries.next().await {
|
||||
match entry {
|
||||
Ok(entry) => {
|
||||
if entry.file_type().await?.is_file()
|
||||
&& extensions.contains(
|
||||
&entry
|
||||
let entry = match entry {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
eprintln!("[ERROR] Failed to read directory entry: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let is_file = entry
|
||||
.file_type()
|
||||
.await
|
||||
.map(|ft| ft.is_file())
|
||||
.unwrap_or(false);
|
||||
if !is_file {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ext = entry
|
||||
.path()
|
||||
.extension()
|
||||
.unwrap_or_default()
|
||||
.to_string_lossy()
|
||||
.to_lowercase(),
|
||||
)
|
||||
{
|
||||
.to_lowercase();
|
||||
if !extensions.contains(&ext) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let file_path = entry.path().to_path_buf();
|
||||
let semaphone_clone = Arc::clone(&semaphone);
|
||||
let semaphore_clone = Arc::clone(&semaphore);
|
||||
let sources_clone = Arc::clone(&sources);
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
let _permit = semaphone_clone.acquire().await.unwrap();
|
||||
let _permit = semaphore_clone.acquire().await.unwrap();
|
||||
process_file(&file_path, sources_clone, overwrite, allow_inaccurate).await;
|
||||
});
|
||||
tasks.push(task);
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("[ERROR] Failed to read directory entry: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
for task in tasks {
|
||||
let _ = task.await;
|
||||
@@ -150,12 +167,19 @@ async fn process_file(
|
||||
overwrite: bool,
|
||||
allow_inaccurate: bool,
|
||||
) {
|
||||
let tag = Tag::async_read_from_path(&file_path).await;
|
||||
let mut tag = match Tag::async_read_from_path(file_path).await {
|
||||
Ok(tag) => tag,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"[ERROR] Failed to read ID3 tag for file '{}': {}",
|
||||
file_path.display(),
|
||||
e
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match tag {
|
||||
Ok(tag) => {
|
||||
let lyrics: Vec<&Lyrics> = tag.lyrics().collect();
|
||||
if !lyrics.is_empty() && !overwrite {
|
||||
if !overwrite && tag.lyrics().next().is_some() {
|
||||
println!(
|
||||
"[INFO] File '{}' already has lyrics, skipping (use --overwrite to force)",
|
||||
file_path.display()
|
||||
@@ -182,7 +206,6 @@ async fn process_file(
|
||||
source.name()
|
||||
);
|
||||
|
||||
let mut tag = tag.clone();
|
||||
tag.remove_all_lyrics();
|
||||
tag.remove_all_synchronised_lyrics();
|
||||
|
||||
@@ -192,30 +215,23 @@ async fn process_file(
|
||||
text: lyrics.to_string(),
|
||||
});
|
||||
|
||||
tag.write_to_path(&file_path, Version::Id3v24)
|
||||
.map_err(|e| {
|
||||
if let Err(e) = tag.write_to_path(file_path, Version::Id3v24) {
|
||||
eprintln!(
|
||||
"[ERROR] Failed to write tags into {}: {}",
|
||||
file_path.display(),
|
||||
e
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e) => eprintln!(
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"[ERROR] Failed to fetch lyrics for file '{}' from source '{}': {}",
|
||||
file_path.display(),
|
||||
source.name(),
|
||||
e
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!(
|
||||
"[ERROR] Failed to read ID3 tag for file '{}': {}",
|
||||
file_path.display(),
|
||||
e
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::sources::LyricsSource;
|
||||
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use anyhow::{Context, Ok, Result, anyhow};
|
||||
use async_trait::async_trait;
|
||||
use id3::{Tag, TagLike};
|
||||
use reqwest::Client;
|
||||
@@ -116,7 +116,7 @@ impl LyricsSource for GeniusSource {
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("No results found on Genius"))?
|
||||
} else {
|
||||
return Err(anyhow!("No accurate match found on Genius"));
|
||||
return Ok("".to_string());
|
||||
};
|
||||
|
||||
let lyrics_url = &selected.result.url;
|
||||
|
||||
Reference in New Issue
Block a user