feat(library): extract and display album artwork
- Extract embedded artwork from audio files during scan - Save extracted artwork to cache directory (~/.cache/qbz/artwork) - Fallback to folder artwork (cover.jpg, folder.jpg, front.jpg, etc.) - Add get_artwork_cache_dir helper function - Artwork now displays in album cards and detail views
This commit is contained in:
1 parent
e8a61a45ce
commit
f6dbf2ee2a
3 files changed
+45
-2
No files matched your search
@@ -6,7 +6,7 @@ use tauri::State;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::library::{
|
||||
cue_to_tracks, CueParser, LibraryDatabase, LibraryError, LibraryScanner, LibraryStats,
|
||||
cue_to_tracks, get_artwork_cache_dir, CueParser, LibraryDatabase, LibraryScanner, LibraryStats,
|
||||
LocalAlbum, LocalArtist, LocalTrack, MetadataExtractor, ScanError, ScanProgress, ScanStatus,
|
||||
};
|
||||
|
||||
@@ -158,7 +158,15 @@ pub async fn library_scan(state: State<'_, LibraryState>) -> Result<(), String>
|
||||
}
|
||||
|
||||
match MetadataExtractor::extract(audio_path) {
|
||||
Ok(track) => {
|
||||
Ok(mut track) => {
|
||||
// Try to extract embedded artwork, fallback to folder artwork
|
||||
let artwork_cache = get_artwork_cache_dir();
|
||||
if let Some(artwork_path) = MetadataExtractor::extract_artwork(audio_path, &artwork_cache) {
|
||||
track.artwork_path = Some(artwork_path);
|
||||
} else if let Some(folder_art) = MetadataExtractor::find_folder_artwork(audio_path) {
|
||||
track.artwork_path = Some(folder_art);
|
||||
}
|
||||
|
||||
let db = state.db.lock().await;
|
||||
if let Err(e) = db.insert_track(&track) {
|
||||
all_errors.push(ScanError {
|
||||
|
||||
@@ -197,6 +197,31 @@ impl MetadataExtractor {
|
||||
}
|
||||
hash
|
||||
}
|
||||
|
||||
/// Look for folder artwork (cover.jpg, folder.jpg, etc.)
|
||||
/// Returns the path if found
|
||||
pub fn find_folder_artwork(audio_file_path: &Path) -> Option<String> {
|
||||
let parent_dir = audio_file_path.parent()?;
|
||||
|
||||
// Common artwork filenames in order of preference
|
||||
const ARTWORK_NAMES: &[&str] = &[
|
||||
"cover.jpg", "cover.jpeg", "cover.png",
|
||||
"folder.jpg", "folder.jpeg", "folder.png",
|
||||
"front.jpg", "front.jpeg", "front.png",
|
||||
"album.jpg", "album.jpeg", "album.png",
|
||||
"Cover.jpg", "Cover.jpeg", "Cover.png",
|
||||
"Folder.jpg", "Folder.jpeg", "Folder.png",
|
||||
];
|
||||
|
||||
for name in ARTWORK_NAMES {
|
||||
let artwork_path = parent_dir.join(name);
|
||||
if artwork_path.exists() {
|
||||
return Some(artwork_path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -32,6 +32,16 @@ pub fn get_db_path() -> PathBuf {
|
||||
data_dir.join("library.db")
|
||||
}
|
||||
|
||||
/// Get artwork cache directory
|
||||
pub fn get_artwork_cache_dir() -> PathBuf {
|
||||
let cache_dir = dirs::cache_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("."))
|
||||
.join("qbz")
|
||||
.join("artwork");
|
||||
std::fs::create_dir_all(&cache_dir).ok();
|
||||
cache_dir
|
||||
}
|
||||
|
||||
/// Initialize library state
|
||||
pub fn init_library_state() -> Result<LibraryState, LibraryError> {
|
||||
let db_path = get_db_path();
|
||||
|
||||
Reference in new issue
Block a user