2015-12-28 15:53:54 +00:00
|
|
|
use eventual::{Async, Future};
|
2015-12-28 00:29:53 +00:00
|
|
|
use protobuf;
|
2015-06-23 14:38:29 +00:00
|
|
|
|
|
|
|
use librespot_protocol as protocol;
|
|
|
|
use mercury::{MercuryRequest, MercuryMethod};
|
2015-12-28 15:55:01 +00:00
|
|
|
use util::{SpotifyId, FileId, StrChunksExt};
|
2015-07-02 17:24:25 +00:00
|
|
|
use session::Session;
|
2015-06-23 14:38:29 +00:00
|
|
|
|
2016-01-02 02:30:24 +00:00
|
|
|
pub use librespot_protocol::metadata::AudioFile_Format as FileFormat;
|
|
|
|
|
2015-12-28 15:55:01 +00:00
|
|
|
fn countrylist_contains(list: &str, country: &str) -> bool {
|
|
|
|
list.chunks(2).any(|cc| cc == country)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_restrictions<'s, I>(restrictions: I, country: &str, catalogue: &str) -> bool
|
2016-01-02 15:19:39 +00:00
|
|
|
where I: Iterator<Item = &'s protocol::metadata::Restriction>
|
|
|
|
{
|
|
|
|
restrictions.filter(|r| r.get_catalogue_str().contains(&catalogue.to_owned()))
|
|
|
|
.all(|r| {
|
|
|
|
!countrylist_contains(r.get_countries_forbidden(), country) &&
|
|
|
|
(!r.has_countries_allowed() ||
|
|
|
|
countrylist_contains(r.get_countries_allowed(), country))
|
|
|
|
})
|
2015-12-28 15:55:01 +00:00
|
|
|
}
|
|
|
|
|
2015-12-28 15:53:54 +00:00
|
|
|
pub trait MetadataTrait : Send + 'static {
|
2015-06-23 14:38:29 +00:00
|
|
|
type Message: protobuf::MessageStatic;
|
2015-12-28 15:53:54 +00:00
|
|
|
|
2015-06-23 14:38:29 +00:00
|
|
|
fn base_url() -> &'static str;
|
2015-12-29 12:13:26 +00:00
|
|
|
fn parse(msg: &Self::Message, session: &Session) -> Self;
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Track {
|
2015-12-28 15:53:54 +00:00
|
|
|
pub id: SpotifyId,
|
2015-06-23 14:38:29 +00:00
|
|
|
pub name: String,
|
|
|
|
pub album: SpotifyId,
|
2016-01-02 02:30:24 +00:00
|
|
|
pub files: Vec<(FileId, FileFormat)>,
|
2015-12-28 15:55:01 +00:00
|
|
|
pub alternatives: Vec<SpotifyId>,
|
|
|
|
pub available: bool,
|
2015-12-28 15:53:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Album {
|
|
|
|
pub id: SpotifyId,
|
|
|
|
pub name: String,
|
|
|
|
pub artists: Vec<SpotifyId>,
|
2016-01-02 15:19:39 +00:00
|
|
|
pub covers: Vec<FileId>,
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
|
2015-12-28 15:53:54 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Artist {
|
|
|
|
pub id: SpotifyId,
|
|
|
|
pub name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type MetadataRef<T> = Future<T, ()>;
|
|
|
|
pub type TrackRef = MetadataRef<Track>;
|
|
|
|
pub type AlbumRef = MetadataRef<Album>;
|
|
|
|
pub type ArtistRef = MetadataRef<Artist>;
|
|
|
|
|
2015-06-23 14:38:29 +00:00
|
|
|
impl MetadataTrait for Track {
|
|
|
|
type Message = protocol::metadata::Track;
|
2015-12-28 15:53:54 +00:00
|
|
|
|
|
|
|
fn base_url() -> &'static str {
|
|
|
|
"hm://metadata/3/track"
|
|
|
|
}
|
|
|
|
|
2015-12-29 12:13:26 +00:00
|
|
|
fn parse(msg: &Self::Message, session: &Session) -> Self {
|
2015-06-23 14:38:29 +00:00
|
|
|
Track {
|
2015-12-28 15:53:54 +00:00
|
|
|
id: SpotifyId::from_raw(msg.get_gid()),
|
2015-09-01 11:20:37 +00:00
|
|
|
name: msg.get_name().to_owned(),
|
2015-06-23 14:38:29 +00:00
|
|
|
album: SpotifyId::from_raw(msg.get_album().get_gid()),
|
2016-01-02 15:19:39 +00:00
|
|
|
files: msg.get_file()
|
|
|
|
.iter()
|
2016-01-20 10:31:43 +00:00
|
|
|
.filter(|file| file.has_file_id())
|
2016-01-02 15:19:39 +00:00
|
|
|
.map(|file| {
|
|
|
|
let mut dst = [0u8; 20];
|
|
|
|
dst.clone_from_slice(&file.get_file_id());
|
|
|
|
(FileId(dst), file.get_format())
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
alternatives: msg.get_alternative()
|
|
|
|
.iter()
|
|
|
|
.map(|alt| SpotifyId::from_raw(alt.get_gid()))
|
|
|
|
.collect(),
|
|
|
|
available: parse_restrictions(msg.get_restriction().iter(),
|
|
|
|
&session.0.data.read().unwrap().country,
|
|
|
|
"premium"),
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MetadataTrait for Album {
|
|
|
|
type Message = protocol::metadata::Album;
|
2015-12-28 15:53:54 +00:00
|
|
|
|
|
|
|
fn base_url() -> &'static str {
|
|
|
|
"hm://metadata/3/album"
|
|
|
|
}
|
|
|
|
|
2015-12-29 22:12:02 +00:00
|
|
|
fn parse(msg: &Self::Message, _: &Session) -> Self {
|
2015-06-23 14:38:29 +00:00
|
|
|
Album {
|
2015-12-28 15:53:54 +00:00
|
|
|
id: SpotifyId::from_raw(msg.get_gid()),
|
2015-09-01 11:20:37 +00:00
|
|
|
name: msg.get_name().to_owned(),
|
2016-01-02 15:19:39 +00:00
|
|
|
artists: msg.get_artist()
|
|
|
|
.iter()
|
|
|
|
.map(|a| SpotifyId::from_raw(a.get_gid()))
|
|
|
|
.collect(),
|
|
|
|
covers: msg.get_cover_group()
|
|
|
|
.get_image()
|
|
|
|
.iter()
|
2016-01-20 10:31:43 +00:00
|
|
|
.filter(|image| image.has_file_id())
|
2016-01-02 15:19:39 +00:00
|
|
|
.map(|image| {
|
|
|
|
let mut dst = [0u8; 20];
|
|
|
|
dst.clone_from_slice(&image.get_file_id());
|
|
|
|
FileId(dst)
|
|
|
|
})
|
|
|
|
.collect(),
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl MetadataTrait for Artist {
|
|
|
|
type Message = protocol::metadata::Artist;
|
2015-12-28 15:53:54 +00:00
|
|
|
|
2015-06-23 14:38:29 +00:00
|
|
|
fn base_url() -> &'static str {
|
|
|
|
"hm://metadata/3/artist"
|
|
|
|
}
|
|
|
|
|
2015-12-29 22:12:02 +00:00
|
|
|
fn parse(msg: &Self::Message, _: &Session) -> Self {
|
2015-12-28 15:53:54 +00:00
|
|
|
Artist {
|
|
|
|
id: SpotifyId::from_raw(msg.get_gid()),
|
|
|
|
name: msg.get_name().to_owned(),
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-28 15:53:54 +00:00
|
|
|
pub struct MetadataManager;
|
2015-06-23 14:38:29 +00:00
|
|
|
|
|
|
|
impl MetadataManager {
|
2015-07-02 17:24:25 +00:00
|
|
|
pub fn new() -> MetadataManager {
|
2015-12-28 15:53:54 +00:00
|
|
|
MetadataManager
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
|
2016-01-02 15:19:39 +00:00
|
|
|
pub fn get<T: MetadataTrait>(&mut self, session: &Session, id: SpotifyId) -> MetadataRef<T> {
|
2016-01-02 15:48:44 +00:00
|
|
|
let session = session.clone();
|
2015-12-28 15:53:54 +00:00
|
|
|
session.mercury(MercuryRequest {
|
2016-01-02 15:19:39 +00:00
|
|
|
method: MercuryMethod::GET,
|
|
|
|
uri: format!("{}/{}", T::base_url(), id.to_base16()),
|
|
|
|
content_type: None,
|
|
|
|
payload: Vec::new(),
|
|
|
|
})
|
|
|
|
.and_then(move |response| {
|
2016-01-02 15:48:44 +00:00
|
|
|
let data = response.payload.first().unwrap();
|
|
|
|
let msg: T::Message = protobuf::parse_from_bytes(data).unwrap();
|
2016-01-02 15:19:39 +00:00
|
|
|
|
2016-01-02 15:48:44 +00:00
|
|
|
Ok(T::parse(&msg, &session))
|
2016-01-02 15:19:39 +00:00
|
|
|
})
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
}
|