Skip to content

Instantly share code, notes, and snippets.

@RoxasShadow
Last active August 29, 2015 14:21
Show Gist options
  • Save RoxasShadow/f40564880a2f1a0b93ef to your computer and use it in GitHub Desktop.
Save RoxasShadow/f40564880a2f1a0b93ef to your computer and use it in GitHub Desktop.
Somehow I'm playing with Rust / Moved at https://github.com/RoxasShadow/rustfm
extern crate hyper;
extern crate rustc_serialize;
use std::io::Read;
use std::env;
use hyper::Client;
use hyper::header::Connection;
use rustc_serialize::json::Json;
use rustc_serialize::json::Decoder as JsonDecoder;
use rustc_serialize::{Decoder, Decodable};
struct Image {
size: String,
url: String
}
impl Image {
fn to_string(&self) -> String {
return format!("{}: {}", self.size, self.url);
}
}
impl Decodable for Image {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Image, D::Error> {
decoder.read_struct("root", 0, |decoder| {
let url : String = try!(decoder.read_struct_field("#text", 0, |decoder| Decodable::decode(decoder)));
Ok(Image {
size: try!(decoder.read_struct_field("size", 0, |decoder| Decodable::decode(decoder))),
url: url
})
})
}
}
#[allow(dead_code)]
struct Artist {
name: String,
listeners: u32,
mbid: String,
url: String,
images: Vec<Image>
}
impl Decodable for Artist {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Artist, D::Error> {
decoder.read_struct("root", 0, |decoder| {
Ok(Artist {
name: try!(decoder.read_struct_field("name", 0, |decoder| Decodable::decode(decoder))),
listeners: try!(decoder.read_struct_field("listeners", 0, |decoder| Decodable::decode(decoder))),
mbid: try!(decoder.read_struct_field("mbid", 0, |decoder| Decodable::decode(decoder))),
url: try!(decoder.read_struct_field("url", 0, |decoder| Decodable::decode(decoder))),
images: try!(decoder.read_struct_field("image", 0, |decoder| Decodable::decode(decoder))),
})
})
}
}
impl Artist {
fn from_json(artist: Json) -> Artist {
let mut decoder = JsonDecoder::new(artist);
let artist_obj : Artist = match Decodable::decode(&mut decoder) {
Ok(artist) => artist,
Err(err) => panic!(err)
};
return artist_obj;
}
fn to_string(&self) -> String {
return format!("Name: {}\nListeners: {}\nURL: {}\nImages: \n{}",
self.name,
self.listeners,
self.url,
self.images.iter()
.filter(|i| !i.url.is_empty())
.map(|i| format!(" {}", i.to_string()))
.collect::<Vec<String>>().connect("\n")
);
}
}
struct LastFM<'a> {
api_key: &'a str
}
#[allow(dead_code)]
struct SearchResults<'a, T> {
query: &'a str,
results: Vec<T>
}
impl<'a> LastFM<'a> {
fn new(api_key: &'a str) -> LastFM {
return LastFM { api_key: api_key };
}
fn request(&self, query: &str) -> Option<Json> {
let mut client = Client::new();
let url = format!(
"http://ws.audioscrobbler.com/2.0/?method=artist.search&artist={}&api_key={}&format=json",
query,
self.api_key
);
let mut res = client.get(&url)
.header(Connection::close())
.send().unwrap();
let mut body = String::new();
res.read_to_string(&mut body).unwrap();
let json = &Json::from_str(&body).unwrap();
return json.as_object().unwrap()
.get("results").map(|r| r.clone());
}
fn search_artists(&self, query: &'a str) -> SearchResults<Artist> {
let response = self.request(query).unwrap();
let response_obj = response.as_object().unwrap();
let artists = match response_obj.get("artistmatches").unwrap().as_object() {
Some(artist_matches) => artist_matches.get("artist").unwrap().as_array().unwrap(),
None => panic!("No results :(")
};
return SearchResults {
query: query,
results: artists.iter().map(|a|
Artist::from_json(a.clone())
).collect()
};
}
}
fn main() {
let args : Vec<_> = env::args().collect();
if args.len() == 1 {
panic!("artist's name is required");
}
let last_fm = LastFM::new("572b13444704f89c67b07a713d5e5de1");
let search = last_fm.search_artists(&args[1]);
for artist in search.results.iter() {
println!("{}", &artist.to_string());
println!("");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment