Rust daemon that skips rap songs in (not only) Spotify radios via MPRIS and MusicBrainz
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rapblock/src/brainz.rs

87 lines
2.6 KiB

5 years ago
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use failure::Error;
use std::io::Read;
use std::time::Duration;
#[derive(Serialize, Deserialize, Debug)]
struct MBArtistQueryResult {
created : String,
count: i32,
offset: i32,
artists: Option<Vec<MBArtist>>,
}
#[derive(Serialize, Deserialize, Debug)]
struct Tag {
count: i32, // negative doesn't make sense, but it sometimes occurs
name: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct MBArtist {
id: String,
score: i32,
name: String,
#[serde(rename="sort-name")]
sort_name: String,
tags: Option<Vec<Tag>>
}
lazy_static! {
static ref BAD_GENRES : Vec<&'static str> = vec![
"hip hop", "hip-hop", "hiphop", "rnb", "rap", "rapper",
"hardcore hip hop", "new york hip hop", "east coast hip hop",
"pop rap"
];
}
pub fn artist_sucks(artist : &str) -> Result<bool, Error> {
let query = utf8_percent_encode(&format!("\"{}\"", artist), DEFAULT_ENCODE_SET).to_string();
let url = format!("https://musicbrainz.org/ws/2/artist?query={}&fmt=json&inc=tags", query);
info!("Querying MusicBrainz for artist \"{}\", query URL: {}", artist, url);
let mut resp = String::new();
reqwest::Client::builder()
.timeout(Duration::from_millis(2000))
.build()?
.get(&url)
.header(reqwest::header::USER_AGENT, "Bad Spotify Song Skipper/0.0.1 ( ondra@ondrovo.com )")
.header(reqwest::header::ACCEPT, "text/json")
.send()?
.read_to_string(&mut resp)?;
debug!("Resp: {}", resp);
let result : MBArtistQueryResult = serde_json::from_str(&resp)?;
info!("Response OK");
debug!("{:#?}", result);
if result.count == 0 {
// not found, let's hope it's OK
warn!("No results!");
return Err(failure::err_msg("Artist not found"));
} else {
info!("Got {} results", result.count);
let artists = result.artists.as_ref().unwrap();
if artists[0].tags.is_some() {
let tags = artists[0].tags.as_ref().unwrap();
let as_vec : Vec<&String> = tags.iter().map(|t| &t.name).collect();
debug!("First artist has tags: {:?}", tags);
for tag in as_vec {
if BAD_GENRES.contains(&tag.as_str()) {
info!("Found a bad tag: {}", tag);
return Ok(true);
}
}
info!("All tags OK");
return Ok(false);
} else {
warn!("No tags, can't determine genre");
return Err(failure::err_msg("Artist found, but has no tags"));
}
}
}