Parse id3 tags from mpeg files
This commit is contained in:
parent
2cc7bf2bca
commit
4606a117f6
|
@ -124,10 +124,14 @@ export class TrackCard extends HTMLElement {
|
|||
trackName.name = this["name"];
|
||||
container.appendChild(trackName);
|
||||
}
|
||||
this["length"] && container.appendChild(document.createTextNode("1:23"));
|
||||
this["album"] &&
|
||||
container.appendChild(document.createTextNode("Shatter Me"));
|
||||
this["artist"] &&
|
||||
container.appendChild(document.createTextNode("Lindsey Stirling"));
|
||||
if (this["length"]) {
|
||||
container.appendChild(document.createTextNode(this["length"]));
|
||||
}
|
||||
if (this["album"]) {
|
||||
container.appendChild(document.createTextNode(this["album"]));
|
||||
}
|
||||
if (this["artist"]) {
|
||||
container.appendChild(document.createTextNode(this["artist"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ const updateTrackList = (tracks: TrackInfo[]) => {
|
|||
let track_formats = _.map(tracks, (info) => {
|
||||
let card: TrackCard = document.createElement("track-card");
|
||||
card.name = info.name || null;
|
||||
card.album = info.album || null;
|
||||
card.artist = info.artist || null;
|
||||
return card;
|
||||
});
|
||||
_.map(track_formats, (trackCard) => {
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
|
@ -77,6 +83,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
|
@ -118,6 +133,16 @@ dependencies = [
|
|||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flow"
|
||||
version = "0.1.0"
|
||||
|
@ -329,6 +354,17 @@ dependencies = [
|
|||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id3"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d7a833474b30425eb64132d1f9b727b4e39537418bcc3288497c8d2f5c8948"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"flate2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
|
@ -421,6 +457,15 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.5"
|
||||
|
@ -456,6 +501,7 @@ name = "music-player"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"flow",
|
||||
"id3",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"rusqlite",
|
||||
|
|
|
@ -7,8 +7,9 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
flow = { path = "../../flow" }
|
||||
mime = { version = "0.3" }
|
||||
id3 = { version = "1.6" }
|
||||
mime_guess = { version = "2.0" }
|
||||
mime = { version = "0.3" }
|
||||
rusqlite = { version = "0.28" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = { version = "1.0" }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::audio::{TrackId, TrackInfo};
|
||||
use id3::{Tag, TagLike};
|
||||
use std::{
|
||||
fs::{DirEntry, ReadDir},
|
||||
path::{Path, PathBuf},
|
||||
|
@ -7,10 +8,12 @@ use thiserror::Error;
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ScannerError {
|
||||
#[error("Cannot scan {0}")]
|
||||
CannotScan(PathBuf),
|
||||
#[error("Not found {0}")]
|
||||
NotFound(PathBuf),
|
||||
#[error("Cannot scan file")]
|
||||
CannotScan,
|
||||
#[error("File not found")]
|
||||
FileNotFound,
|
||||
#[error("Tag not found")]
|
||||
TagNotFound,
|
||||
#[error("IO error {0}")]
|
||||
IO(std::io::Error),
|
||||
}
|
||||
|
@ -21,6 +24,19 @@ impl From<std::io::Error> for ScannerError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<id3::Error> for ScannerError {
|
||||
fn from(err: id3::Error) -> ScannerError {
|
||||
match err.kind {
|
||||
id3::ErrorKind::Io(err) => ScannerError::IO(err),
|
||||
id3::ErrorKind::StringDecoding(_) => ScannerError::CannotScan,
|
||||
id3::ErrorKind::NoTag => ScannerError::TagNotFound,
|
||||
id3::ErrorKind::Parsing => ScannerError::CannotScan,
|
||||
id3::ErrorKind::InvalidInput => ScannerError::CannotScan,
|
||||
id3::ErrorKind::UnsupportedFeature => ScannerError::CannotScan,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MusicScanner: Send {
|
||||
fn scan<'a>(&'a self) -> Box<dyn Iterator<Item = Result<TrackInfo, ScannerError>> + 'a>;
|
||||
}
|
||||
|
@ -49,19 +65,10 @@ impl FileIterator {
|
|||
);
|
||||
let mimetype = mime_guess::from_path(path.clone())
|
||||
.first()
|
||||
.ok_or(ScannerError::CannotScan(path.clone()))?;
|
||||
.ok_or(ScannerError::CannotScan)?;
|
||||
match (mimetype.type_(), mimetype.subtype().as_str()) {
|
||||
(mime::AUDIO, "mpeg") => Ok(TrackInfo {
|
||||
id: TrackId::from(path.to_str().unwrap().to_owned()),
|
||||
album: None,
|
||||
artist: None,
|
||||
name: path
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(|s| s.to_owned()),
|
||||
track_number: None,
|
||||
filetype: mimetype,
|
||||
}),
|
||||
(mime::AUDIO, "mpeg") => TrackInfo::scan_id3(path, mimetype),
|
||||
|
||||
/*
|
||||
(mime::AUDIO, "ogg") => Ok(TrackInfo {
|
||||
id: TrackId::from(path.to_str().unwrap().to_owned()),
|
||||
|
@ -86,11 +93,30 @@ impl FileIterator {
|
|||
filetype: mimetype,
|
||||
}),
|
||||
*/
|
||||
_ => Err(ScannerError::CannotScan(path)),
|
||||
_ => Err(ScannerError::CannotScan),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TrackInfo {
|
||||
fn scan_id3(path: PathBuf, mimetype: mime::Mime) -> Result<TrackInfo, ScannerError> {
|
||||
let tags = Tag::read_from_path(path.clone()).map_err(ScannerError::from)?;
|
||||
|
||||
Ok(TrackInfo {
|
||||
id: TrackId::from(path.to_str().unwrap().to_owned()),
|
||||
album: tags.album().map(|s| s.to_owned()),
|
||||
artist: tags.artist().map(|s| s.to_owned()),
|
||||
name: tags.title().map(|s| s.to_owned()).or_else(|| {
|
||||
path.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(|s| s.to_owned())
|
||||
}),
|
||||
track_number: None,
|
||||
filetype: mimetype,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum EntryInfo {
|
||||
Dir(PathBuf),
|
||||
File(PathBuf),
|
||||
|
@ -136,7 +162,7 @@ impl Iterator for FileIterator {
|
|||
}
|
||||
Err(err) => {
|
||||
if err.kind() == std::io::ErrorKind::NotFound {
|
||||
Some(Err(ScannerError::NotFound(dir)))
|
||||
Some(Err(ScannerError::FileNotFound))
|
||||
} else {
|
||||
Some(Err(ScannerError::from(err)))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue