harpocrates_musik_player

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

library.rs (2720B)


      1 use std::{
      2     collections::BTreeMap,
      3     fs,
      4     path::{Path, PathBuf},
      5 };
      6 
      7 #[derive(Debug, Clone)]
      8 pub struct Library {
      9     pub artists: BTreeMap<String, BTreeMap<String, Vec<Track>>>,
     10 }
     11 
     12 #[derive(Debug, Clone)]
     13 pub struct Track {
     14     pub title: String,
     15     pub path: PathBuf,
     16 }
     17 
     18 pub struct LibraryItem {
     19     pub artist: String,
     20     pub album: String,
     21     pub title: String,
     22     pub path: PathBuf,
     23 }
     24 
     25 impl Library {
     26     pub fn build(items: Vec<LibraryItem>) -> Self {
     27         let mut artists = BTreeMap::new();
     28         for item in items {
     29             artists
     30                 .entry(item.artist)
     31                 .or_insert_with(BTreeMap::new)
     32                 .entry(item.album)
     33                 .or_insert_with(Vec::new)
     34                 .push(Track {
     35                     title: item.title,
     36                     path: item.path,
     37                 });
     38         }
     39         Self { artists }
     40     }
     41 }
     42 
     43 pub fn scan_library(path: &str) -> Vec<LibraryItem> {
     44     let mut items = Vec::new();
     45     if path.is_empty() {
     46         return items;
     47     }
     48     let root = Path::new(path);
     49     if root.exists() && root.is_dir() {
     50         visit_dirs(root, &mut items);
     51     }
     52     items
     53 }
     54 
     55 fn visit_dirs(dir: &Path, items: &mut Vec<LibraryItem>) {
     56     if let Ok(entries) = fs::read_dir(dir) {
     57         for entry in entries.flatten() {
     58             let path = entry.path();
     59             if path.is_dir() {
     60                 visit_dirs(&path, items);
     61             } else if path.is_file() && is_music_file(&path) {
     62                 let title = path
     63                     .file_stem()
     64                     .unwrap_or_default()
     65                     .to_string_lossy()
     66                     .to_string();
     67 
     68                 let album = path
     69                     .parent()
     70                     .and_then(|p| p.file_name())
     71                     .map(|n| n.to_string_lossy().to_string())
     72                     .unwrap_or_else(|| "Unknown Album".to_string());
     73 
     74                 let artist = path
     75                     .parent()
     76                     .and_then(|p| p.parent())
     77                     .and_then(|p| p.file_name())
     78                     .map(|n| n.to_string_lossy().to_string())
     79                     .unwrap_or_else(|| "Unknown Artist".to_string());
     80 
     81                 items.push(LibraryItem {
     82                     artist,
     83                     album,
     84                     title,
     85                     path,
     86                 });
     87             }
     88         }
     89     }
     90 }
     91 
     92 fn is_music_file(path: &PathBuf) -> bool {
     93     let ext = path
     94         .extension()
     95         .and_then(|s| s.to_str())
     96         .unwrap_or("")
     97         .to_lowercase();
     98     matches!(ext.as_str(), "flac" | "mp3" | "ogg" | "wav")
     99 }