add support for getting genre from mpris (experimental)

master
Ondřej Hruška 5 years ago
parent ef78943940
commit 170b6ebc7b
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      Cargo.lock
  2. 1
      Cargo.toml
  3. 63
      src/brainz.rs
  4. 142
      src/main.rs

1
Cargo.lock generated

@ -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)",

@ -17,3 +17,4 @@ log = "0.4"
env_logger = "0.6"
regex = "1.1.0"
inotify = "0.7.0"
dbus = "0.6.4"

@ -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<bool, Error> {
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<bool, Error>
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;

@ -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<Box<RefArg>>> = 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);
}
}
}
}

Loading…
Cancel
Save