diff --git a/Cargo.lock b/Cargo.lock index 7cc7738..1860c0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -956,6 +956,7 @@ dependencies = [ name = "rapblock" version = "0.1.0" dependencies = [ + "dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 350de86..b0b4e49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,4 @@ log = "0.4" env_logger = "0.6" regex = "1.1.0" inotify = "0.7.0" +dbus = "0.6.4" diff --git a/src/brainz.rs b/src/brainz.rs index a5d1daa..6b1b776 100644 --- a/src/brainz.rs +++ b/src/brainz.rs @@ -30,6 +30,38 @@ struct MBArtist { const VERSION: &'static str = env!("CARGO_PKG_VERSION"); +/// Check genre; returns true if it's OK +pub fn check_genre(config: &crate::Config, genre: &String) -> bool { + if config.whitelist.tag.contains(genre) { + info!("+ Whitelisted tag \"{}\"", genre); + return true; + } + + if config.blacklist.tag.contains(genre) { + info!("- Blacklisted tag \"{}\"", genre); + return false; + } else { + for substr in config.blacklist.tag_partial.iter() { + let re = Regex::new(&format!(r"\b{}\b", regex::escape(substr))); + + let matches = match re { + Ok(re) => re.is_match(genre), + Err(_) => genre.contains(substr), + }; + + if matches { + info!( + "- Blacklisted tag \"{}\" - due to substring \"{}\"", + genre, substr + ); + return false; + } + } + } + + true +} + pub fn check_artist(config: &crate::Config, artist: &str) -> Result { let query = utf8_percent_encode(&format!("\"{}\"", artist), DEFAULT_ENCODE_SET).to_string(); let url = format!( @@ -89,36 +121,7 @@ pub fn check_artist(config: &crate::Config, artist: &str) -> Result info!("Artist #{} - \"{}\" has tags: {:?}", an + 1, a.name, as_vec); 'tags: for tag in as_vec { - if config.whitelist.tag.contains(tag) { - info!("+ Whitelisted tag \"{}\"", tag); - continue 'tags; - } - - let mut blacklisted = false; - if config.blacklist.tag.contains(&tag) { - info!("- Blacklisted tag \"{}\"", tag); - blacklisted = true; - } else { - 'blacklist: for t in config.blacklist.tag_partial.iter() { - let re = Regex::new(&format!(r"\b{}\b", regex::escape(t))); - - let matches = match re { - Ok(re) => re.is_match(tag), - Err(_) => tag.contains(t), - }; - - if matches { - info!( - "- Blacklisted tag \"{}\" - due to substring \"{}\"", - tag, t - ); - blacklisted = true; - break 'blacklist; - } - } - } - - if blacklisted { + if !check_genre(config, tag) { confidence = true; passed = false; break 'artists; diff --git a/src/main.rs b/src/main.rs index f39c4b8..b568c22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,8 @@ use std::time::Duration; use mpris::Event; use std::collections::HashSet; use failure::Error; +use dbus::arg::Variant; +use dbus::arg::RefArg; mod brainz; mod config_file; @@ -167,6 +169,9 @@ fn main() -> Result<(), Error> { break 'event_loop; } Event::TrackChanged(mut metadata) => { + ::std::thread::sleep(Duration::from_millis(250)); + metadata = player.get_metadata().unwrap_or(metadata); + let mut title = metadata.title().unwrap_or(""); info!("--- new track : {} ---", title); @@ -185,71 +190,104 @@ fn main() -> Result<(), Error> { } } - let mut artists = HashSet::new(); + let mut skip = !config.allow_by_default; + let mut confidence = false; - if let Some(aa) = metadata.artists() { - for a in aa { - artists.insert(a); - } - } - if let Some(aa) = metadata.album_artists() { - for a in aa { - artists.insert(a); + debug!("MPRIS meta: {:#?}", metadata); + + // try to get genre from the 'rest' map in the metadata struct + #[allow(deprecated)] // 2.0.0 will provide some nicer API, hopefully + let rest = metadata.rest(); + let meta_genre : Option<&Variant>> = rest.get("xesam:genre"); + match meta_genre { + Some(variant) => { + let b : &RefArg = variant.0.as_ref(); + if let Some(s) = b.as_str() { + info!("Using genre from MPRIS metadata: {}", s); + skip = !brainz::check_genre(&config, &s.to_string().to_lowercase()); + confidence = true; + } else if let Some(list) = b.as_iter() { + debug!("MPRIS contains array of genres"); + for item in list { + if let Some(s) = item.as_str() { + info!("Using genre from MPRIS metadata: {}", s); + skip = !brainz::check_genre(&config, &s.to_string().to_lowercase()); + confidence = true; + } + } + } + }, + None => { + debug!("No MPRIS genre"); } - } + }; - let mut skip = false; - let mut confidence = false; - 'artists_loop: for (an, a) in artists - .iter() - .take(config.max_artists_per_track as usize) - .enumerate() - { - info!("Checking artist #{}: {}", an + 1, a); - if let Some(resolution) = artist_cache.get(a.as_str()) { - confidence = true; - if !resolution { - info!("~ result cached: BAD"); - skip = true; - break 'artists_loop; + if !confidence { + let mut artists = HashSet::new(); + + if let Some(aa) = metadata.artists() { + for a in aa { + artists.insert(a); } - info!("~ result cached: GOOD"); - continue 'artists_loop; } - - if config.whitelist.artist.contains(a) { - info!("+ Whitelisted artist!"); - // there may be other co-artists that spoil the song -> don't break yet - artist_cache.insert(a.to_string(), true); - confidence = true; - continue 'artists_loop; + if let Some(aa) = metadata.album_artists() { + for a in aa { + artists.insert(a); + } } - if config.blacklist.artist.contains(a) { - info!("- Blacklisted artist!"); - skip = true; - artist_cache.insert(a.to_string(), false); - confidence = true; - break 'artists_loop; - } + let artists_e = artists + .iter() + .take(config.max_artists_per_track as usize) + .enumerate(); - let verdict = brainz::check_artist(&config, &a); - match verdict { - Ok(allow) => { + 'artists_loop: for (an, a) in artists_e { + info!("Checking artist #{}: {}", an + 1, a); + if let Some(resolution) = artist_cache.get(*a) { confidence = true; - artist_cache.insert(a.to_string(), allow); - if allow { - info!("Artist passed"); - } else { + if !resolution { + info!("~ result cached: BAD"); skip = true; break 'artists_loop; } + info!("~ result cached: GOOD"); + continue 'artists_loop; } - Err(e) => { - warn!("Something went wrong: {}", e); - // probably no tags, or not found - use the default action - artist_cache - .insert(a.to_string(), config.allow_by_default); + + if config.whitelist.artist.contains(a) { + info!("+ Whitelisted artist!"); + // there may be other co-artists that spoil the song -> don't break yet + artist_cache.insert(a.to_string(), true); + confidence = true; + continue 'artists_loop; + } + + if config.blacklist.artist.contains(a) { + info!("- Blacklisted artist!"); + skip = true; + artist_cache.insert(a.to_string(), false); + confidence = true; + break 'artists_loop; + } + + let verdict = brainz::check_artist(&config, &a); + match verdict { + Ok(allow) => { + confidence = true; + artist_cache.insert(a.to_string(), allow); + if allow { + info!("Artist passed"); + } else { + skip = true; + break 'artists_loop; + } + } + Err(e) => { + warn!("Something went wrong: {}", e); + // probably no tags, or not found - use the default action + artist_cache + .insert(a.to_string(), config.allow_by_default); + } } } }