A tool to sync music with your favorite devices
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

*: add more context to errors, move to lofty to parse music tags, make tag parsing routines TryFrom

Gee Sawra cf53f439 f459b5d6

+86 -36
+46 -4
Cargo.lock
··· 624 624 ] 625 625 626 626 [[package]] 627 + name = "data-encoding" 628 + version = "2.10.0" 629 + source = "registry+https://github.com/rust-lang/crates.io-index" 630 + checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" 631 + 632 + [[package]] 627 633 name = "der" 628 634 version = "0.7.9" 629 635 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1397 1403 ] 1398 1404 1399 1405 [[package]] 1406 + name = "lofty" 1407 + version = "0.22.4" 1408 + source = "registry+https://github.com/rust-lang/crates.io-index" 1409 + checksum = "ca260c51a9c71f823fbfd2e6fbc8eb2ee09834b98c00763d877ca8bfa85cde3e" 1410 + dependencies = [ 1411 + "byteorder", 1412 + "data-encoding", 1413 + "flate2", 1414 + "lofty_attr", 1415 + "log", 1416 + "ogg_pager", 1417 + "paste", 1418 + ] 1419 + 1420 + [[package]] 1421 + name = "lofty_attr" 1422 + version = "0.11.1" 1423 + source = "registry+https://github.com/rust-lang/crates.io-index" 1424 + checksum = "ed9983e64b2358522f745c1251924e3ab7252d55637e80f6a0a3de642d6a9efc" 1425 + dependencies = [ 1426 + "proc-macro2", 1427 + "quote", 1428 + "syn 2.0.114", 1429 + ] 1430 + 1431 + [[package]] 1400 1432 name = "log" 1401 - version = "0.4.21" 1433 + version = "0.4.29" 1402 1434 source = "registry+https://github.com/rust-lang/crates.io-index" 1403 - checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 1435 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 1404 1436 dependencies = [ 1405 1437 "value-bag", 1406 1438 ] ··· 1571 1603 checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" 1572 1604 dependencies = [ 1573 1605 "memchr", 1606 + ] 1607 + 1608 + [[package]] 1609 + name = "ogg_pager" 1610 + version = "0.7.0" 1611 + source = "registry+https://github.com/rust-lang/crates.io-index" 1612 + checksum = "e034c10fb5c1c012c1b327b85df89fb0ef98ae66ec28af30f0d1eed804a40c19" 1613 + dependencies = [ 1614 + "byteorder", 1574 1615 ] 1575 1616 1576 1617 [[package]] ··· 2675 2716 "indicatif", 2676 2717 "infer", 2677 2718 "libc", 2719 + "lofty", 2678 2720 "log", 2679 2721 "num_cpus", 2680 2722 "once_cell", ··· 2777 2819 2778 2820 [[package]] 2779 2821 name = "value-bag" 2780 - version = "1.9.0" 2822 + version = "1.12.0" 2781 2823 source = "registry+https://github.com/rust-lang/crates.io-index" 2782 - checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" 2824 + checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" 2783 2825 2784 2826 [[package]] 2785 2827 name = "vcpkg"
+1
Cargo.toml
··· 49 49 tempdir = "0.3.7" 50 50 infer = "0.19.0" 51 51 sysinfo = "0.37.2" 52 + lofty = "0.22.4"
+3 -4
src/cmd/add.rs
··· 167 167 continue; 168 168 } 169 169 170 - let tags = audiotags::Tag::new() 171 - .read_from_path(p.clone()) 172 - .with_context(|| format!("Cannot read tags from {}", p.clone()))?; 170 + let tags = lofty::read_from_path(p.clone()) 171 + .with_context(|| format!("could not read tags from {}", p.clone()))?; 173 172 174 173 let p_path = std::path::PathBuf::from(p.clone()); 175 174 let p_path = p_path.parent().unwrap(); ··· 179 178 path: p, 180 179 artwork_path: find_cover_image(&p_path), 181 180 } 182 - .into(); 181 + .try_into()?; 183 182 track.file_state = FileState::Copied; 184 183 185 184 log::info!("new track: {}", track);
+4 -1
src/fs.rs
··· 1 + use anyhow::Context; 1 2 use async_std::channel::{Receiver, Sender}; 2 3 3 4 /// Traverses the file system from the given path. ··· 53 54 fn is_music(name: &String) -> bool { 54 55 let formats = ["flac", "mp3", "ogg", "mp4", "m4a", "opus"]; 55 56 56 - let mime = infer::get_from_path(name).unwrap(); 57 + let mime = infer::get_from_path(name) 58 + .context(format!("could not infer extension from {}", name.clone())) 59 + .unwrap(); 57 60 match mime { 58 61 Some(mime) => { 59 62 let ext = mime.extension();
+32 -27
src/model.rs
··· 1 - use audiotags::AudioTag; 1 + use anyhow::{Context, anyhow}; 2 + use lofty::{ 3 + file::{AudioFile, TaggedFile, TaggedFileExt}, 4 + tag::Accessor, 5 + }; 2 6 use once_cell::sync::Lazy; 3 7 use rhai::{CustomType, TypeBuilder}; 4 8 ··· 24 28 } 25 29 26 30 pub struct RawTrack { 27 - pub tags: Box<dyn AudioTag + Send + Sync>, 31 + pub tags: TaggedFile, 28 32 pub path: String, 29 33 pub artwork_path: Option<String>, 30 34 } ··· 112 116 } 113 117 } 114 118 115 - impl From<RawTrack> for Track { 116 - fn from(track: RawTrack) -> Self { 117 - let disc = track.tags.disc(); 119 + impl TryFrom<RawTrack> for Track { 120 + type Error = anyhow::Error; 118 121 119 - // If no album artist has been found, use the artist tag. 120 - // If that's missing too, we have an Unknown album. 121 - let artist = match track.tags.album_artist() { 122 - Some(aa) => aa, 123 - None => track.tags.artist().unwrap_or("Unknown Album"), 124 - }; 122 + fn try_from(track: RawTrack) -> Result<Self, Self::Error> { 123 + let tags = track 124 + .tags 125 + .primary_tag() 126 + .ok_or(anyhow!("could not read track tags"))?; 127 + let length = track.tags.properties().duration(); 128 + let artist = tags.artist().unwrap_or("Uknown Artist".into()).to_string(); 129 + let title = tags.title().unwrap_or("Unknown Title".into()).to_string(); 130 + let album = tags.album().unwrap_or("Unknown Album".into()).to_string(); 131 + let genre = tags.genre().unwrap_or("Unknown Genre".into()).to_string(); 125 132 126 133 let mut t = Self { 127 134 id: 0, 128 135 track_id: Default::default(), 129 - title: track.tags.title().unwrap_or("Unknown Title").to_owned(), 130 - artist: artist.to_owned(), 131 - album: track 132 - .tags 133 - .album_title() 134 - .unwrap_or("Unknown Album") 135 - .to_owned(), 136 - number: track.tags.track_number().unwrap_or_default() as i64, 137 - file_path: track.path, 138 - disc_number: disc.0.unwrap_or_default() as i64, 139 - disc_total: disc.1.unwrap_or_default() as i64, 136 + title: title, 137 + artist: artist, 138 + album: album, 139 + number: tags.track().unwrap_or_default() as i64, 140 + file_path: track.path.clone(), 141 + disc_number: tags.disk().unwrap_or_default() as i64, 142 + disc_total: tags.disk_total().unwrap_or_default() as i64, 140 143 file_state: FileState::Unknown, 141 144 extension: String::new(), 142 - genre: track.tags.genre().unwrap_or("Unknown Genre").to_owned(), 143 - track_len: track.tags.duration().unwrap() as i64, 144 - year: track.tags.year().unwrap_or(1970) as usize, 145 + genre: genre, 146 + track_len: length.as_millis() as i64, 147 + year: tags.year().unwrap_or(1970) as usize, 145 148 artwork_path: track.artwork_path, 146 149 }; 147 150 148 151 t.track_id = track_hash(&t); 149 152 150 - let mime = infer::get_from_path(&t.file_path).unwrap().unwrap(); 153 + let mime = infer::get_from_path(&t.file_path)? 154 + .ok_or(anyhow!("unrecognized file")) 155 + .context(format!("{}", t.file_path.clone()))?; 151 156 t.extension = mime.extension().to_owned(); 152 157 153 - t 158 + Ok(t) 154 159 } 155 160 } 156 161