Use new hm endpoint for playlists

This commit is contained in:
HEnquist 2019-08-06 21:58:50 +02:00 committed by henenq
parent 9faaaae6d2
commit e6295a6f9c
4 changed files with 87 additions and 21 deletions

View file

@ -18,7 +18,7 @@ use librespot::core::session::Session;
use librespot::core::spotify_id::SpotifyId; use librespot::core::spotify_id::SpotifyId;
use librespot::playback::config::PlayerConfig; use librespot::playback::config::PlayerConfig;
use librespot::playback::config::Bitrate; use librespot::playback::config::Bitrate;
use librespot::metadata::{FileFormat, Metadata, PlaylistMeta, Track, Album, Artist, Playlist}; use librespot::metadata::{FileFormat, Metadata, Track, Album, Artist, Playlist};
/* /*
@ -60,15 +60,13 @@ fn main() {
player_config.bitrate = Bitrate::Bitrate320; player_config.bitrate = Bitrate::Bitrate320;
let args: Vec<_> = env::args().collect(); let args: Vec<_> = env::args().collect();
if args.len() != 5 { if args.len() != 4 {
println!("Usage: {} USERNAME PASSWORD PLAYLIST PLISTUSER", args[0]); println!("Usage: {} USERNAME PASSWORD PLAYLIST", args[0]);
} }
let username = args[1].to_owned(); let username = args[1].to_owned();
let password = args[2].to_owned(); let password = args[2].to_owned();
let credentials = Credentials::with_password(username, password); let credentials = Credentials::with_password(username, password);
let plist_owner = args[4].to_string();
let mut uri_split = args[3].split(":"); let mut uri_split = args[3].split(":");
let uri_parts: Vec<&str> = uri_split.collect(); let uri_parts: Vec<&str> = uri_split.collect();
println!("{}, {}, {}",uri_parts[0], uri_parts[1], uri_parts[2]); println!("{}, {}, {}",uri_parts[0], uri_parts[1], uri_parts[2]);
@ -79,7 +77,7 @@ fn main() {
.run(Session::connect(session_config, credentials, None, handle)) .run(Session::connect(session_config, credentials, None, handle))
.unwrap(); .unwrap();
let plist = core.run(Playlist::get(&session, plist_uri, plist_owner, 0, 100)).unwrap(); let plist = core.run(Playlist::get(&session, plist_uri)).unwrap();
println!("{:?}",plist); println!("{:?}",plist);
for track_id in plist.tracks { for track_id in plist.tracks {
let plist_track = core.run(Track::get(&session, track_id)).unwrap(); let plist_track = core.run(Track::get(&session, track_id)).unwrap();

View file

@ -154,7 +154,8 @@ pub trait PlaylistMeta: Send + Sized + 'static {
fn get(session: &Session, id: SpotifyId, user: String, start: i32, len: i32) -> Box<Future<Item = Self, Error = MercuryError>> { fn get(session: &Session, id: SpotifyId, user: String, start: i32, len: i32) -> Box<Future<Item = Self, Error = MercuryError>> {
//let uri = format!("hm://playlist/{}?from={}&length={}",id.to_base62(), 0, 100); //let uri = format!("hm://playlist/{}?from={}&length={}",id.to_base62(), 0, 100);
let uri = format!("hm://playlist/user/{}/playlist/{}?from={}&length={}", user, id.to_base62(), start, len); //let uri = format!("hm://playlist/user/{}/playlist/{}?from={}&length={}", user, id.to_base62(), start, len);
let uri = format!("hm://playlist/v2/playlist/{}", id.to_base62());
println!("request uri: {}", uri); println!("request uri: {}", uri);
let request = session.mercury().get(uri); let request = session.mercury().get(uri);
println!("a"); println!("a");
@ -215,7 +216,7 @@ pub struct Show {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Playlist { pub struct Playlist {
//pub id: SpotifyId, pub user: String,
pub length: i32, pub length: i32,
pub name: String, pub name: String,
pub tracks: Vec<SpotifyId>, pub tracks: Vec<SpotifyId>,
@ -318,13 +319,25 @@ impl Metadata for Album {
} }
} }
impl PlaylistMeta for Playlist { impl Metadata for Playlist {
type Message = protocol::playlist4changes::SelectedListContent; type Message = protocol::playlist4changes::SelectedListContent;
fn base_url() -> &'static str { fn base_url() -> &'static str {
"hm://playlist/'?from=' + from + '&length=' + length" "hm://playlist/v2/playlist"
} }
fn get(session: &Session, id: SpotifyId) -> Box<Future<Item = Self, Error = MercuryError>> {
let uri = format!("{}/{}", Self::base_url(), id.to_base62());
let request = session.mercury().get(uri);
let session = session.clone();
Box::new(request.and_then(move |response| {
let data = response.payload.first().expect("Empty payload");
let msg: Self::Message = protobuf::parse_from_bytes(data).unwrap();
Ok(Self::parse(&msg, &session))
}))
}
fn parse(msg: &Self::Message, _: &Session) -> Self { fn parse(msg: &Self::Message, _: &Session) -> Self {
@ -345,6 +358,7 @@ impl PlaylistMeta for Playlist {
name: msg.get_attributes().get_name().to_owned(), name: msg.get_attributes().get_name().to_owned(),
length: msg.get_length(), length: msg.get_length(),
tracks: tracks, tracks: tracks,
user: msg.get_owner_username().to_string(),
} }
} }
} }

View file

@ -71,6 +71,7 @@ message ListChanges {
message SelectedListContent { message SelectedListContent {
optional bytes revision = 0x1; optional bytes revision = 0x1;
optional int32 length = 0x2; optional int32 length = 0x2;
optional string owner_username =0x10;
optional ListAttributes attributes = 0x3; optional ListAttributes attributes = 0x3;
optional ListChecksum checksum = 0x4; optional ListChecksum checksum = 0x4;
optional ListItems contents = 0x5; optional ListItems contents = 0x5;

View file

@ -2748,6 +2748,7 @@ pub struct SelectedListContent {
// message fields // message fields
revision: ::protobuf::SingularField<::std::vec::Vec<u8>>, revision: ::protobuf::SingularField<::std::vec::Vec<u8>>,
length: ::std::option::Option<i32>, length: ::std::option::Option<i32>,
owner_username: ::protobuf::SingularField<::std::string::String>,
attributes: ::protobuf::SingularPtrField<super::playlist4meta::ListAttributes>, attributes: ::protobuf::SingularPtrField<super::playlist4meta::ListAttributes>,
checksum: ::protobuf::SingularPtrField<super::playlist4meta::ListChecksum>, checksum: ::protobuf::SingularPtrField<super::playlist4meta::ListChecksum>,
contents: ::protobuf::SingularPtrField<super::playlist4content::ListItems>, contents: ::protobuf::SingularPtrField<super::playlist4content::ListItems>,
@ -2830,6 +2831,42 @@ impl SelectedListContent {
self.length = ::std::option::Option::Some(v); self.length = ::std::option::Option::Some(v);
} }
// optional string owner_username = 16;
pub fn get_owner_username(&self) -> &str {
match self.owner_username.as_ref() {
Some(v) => &v,
None => "",
}
}
pub fn clear_owner_username(&mut self) {
self.owner_username.clear();
}
pub fn has_owner_username(&self) -> bool {
self.owner_username.is_some()
}
// Param is passed by value, moved
pub fn set_owner_username(&mut self, v: ::std::string::String) {
self.owner_username = ::protobuf::SingularField::some(v);
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_owner_username(&mut self) -> &mut ::std::string::String {
if self.owner_username.is_none() {
self.owner_username.set_default();
}
self.owner_username.as_mut().unwrap()
}
// Take field
pub fn take_owner_username(&mut self) -> ::std::string::String {
self.owner_username.take().unwrap_or_else(|| ::std::string::String::new())
}
// optional .ListAttributes attributes = 3; // optional .ListAttributes attributes = 3;
@ -3188,6 +3225,9 @@ impl ::protobuf::Message for SelectedListContent {
let tmp = is.read_int32()?; let tmp = is.read_int32()?;
self.length = ::std::option::Option::Some(tmp); self.length = ::std::option::Option::Some(tmp);
}, },
16 => {
::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.owner_username)?;
},
3 => { 3 => {
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.attributes)?; ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.attributes)?;
}, },
@ -3247,6 +3287,9 @@ impl ::protobuf::Message for SelectedListContent {
if let Some(v) = self.length { if let Some(v) = self.length {
my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
} }
if let Some(ref v) = self.owner_username.as_ref() {
my_size += ::protobuf::rt::string_size(16, &v);
}
if let Some(ref v) = self.attributes.as_ref() { if let Some(ref v) = self.attributes.as_ref() {
let len = v.compute_size(); let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
@ -3299,6 +3342,9 @@ impl ::protobuf::Message for SelectedListContent {
if let Some(v) = self.length { if let Some(v) = self.length {
os.write_int32(2, v)?; os.write_int32(2, v)?;
} }
if let Some(ref v) = self.owner_username.as_ref() {
os.write_string(16, &v)?;
}
if let Some(ref v) = self.attributes.as_ref() { if let Some(ref v) = self.attributes.as_ref() {
os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?; os.write_raw_varint32(v.get_cached_size())?;
@ -3398,6 +3444,11 @@ impl ::protobuf::Message for SelectedListContent {
|m: &SelectedListContent| { &m.length }, |m: &SelectedListContent| { &m.length },
|m: &mut SelectedListContent| { &mut m.length }, |m: &mut SelectedListContent| { &mut m.length },
)); ));
fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"owner_username",
|m: &SelectedListContent| { &m.owner_username },
|m: &mut SelectedListContent| { &mut m.owner_username },
));
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::playlist4meta::ListAttributes>>( fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::playlist4meta::ListAttributes>>(
"attributes", "attributes",
|m: &SelectedListContent| { &m.attributes }, |m: &SelectedListContent| { &m.attributes },
@ -3477,6 +3528,7 @@ impl ::protobuf::Clear for SelectedListContent {
fn clear(&mut self) { fn clear(&mut self) {
self.revision.clear(); self.revision.clear();
self.length = ::std::option::Option::None; self.length = ::std::option::Option::None;
self.owner_username.clear();
self.attributes.clear(); self.attributes.clear();
self.checksum.clear(); self.checksum.clear();
self.contents.clear(); self.contents.clear();
@ -3534,17 +3586,18 @@ static file_descriptor_proto_data: &'static [u8] = b"\
eltaB\0\x12\x20\n\x16wantResultingRevisions\x18\x03\x20\x01(\x08B\0\x12\ eltaB\0\x12\x20\n\x16wantResultingRevisions\x18\x03\x20\x01(\x08B\0\x12\
\x18\n\x0ewantSyncResult\x18\x04\x20\x01(\x08B\0\x12\x19\n\x04dump\x18\ \x18\n\x0ewantSyncResult\x18\x04\x20\x01(\x08B\0\x12\x19\n\x04dump\x18\
\x05\x20\x01(\x0b2\t.ListDumpB\0\x12\x10\n\x06nonces\x18\x06\x20\x03(\ \x05\x20\x01(\x0b2\t.ListDumpB\0\x12\x10\n\x06nonces\x18\x06\x20\x03(\
\x05B\0:\0\"\x87\x03\n\x13SelectedListContent\x12\x12\n\x08revision\x18\ \x05B\0:\0\"\xa1\x03\n\x13SelectedListContent\x12\x12\n\x08revision\x18\
\x01\x20\x01(\x0cB\0\x12\x10\n\x06length\x18\x02\x20\x01(\x05B\0\x12%\n\ \x01\x20\x01(\x0cB\0\x12\x10\n\x06length\x18\x02\x20\x01(\x05B\0\x12\x18\
\nattributes\x18\x03\x20\x01(\x0b2\x0f.ListAttributesB\0\x12!\n\x08check\ \n\x0eowner_username\x18\x10\x20\x01(\tB\0\x12%\n\nattributes\x18\x03\
sum\x18\x04\x20\x01(\x0b2\r.ListChecksumB\0\x12\x1e\n\x08contents\x18\ \x20\x01(\x0b2\x0f.ListAttributesB\0\x12!\n\x08checksum\x18\x04\x20\x01(\
\x05\x20\x01(\x0b2\n.ListItemsB\0\x12\x15\n\x04diff\x18\x06\x20\x01(\x0b\ \x0b2\r.ListChecksumB\0\x12\x1e\n\x08contents\x18\x05\x20\x01(\x0b2\n.Li\
2\x05.DiffB\0\x12\x1b\n\nsyncResult\x18\x07\x20\x01(\x0b2\x05.DiffB\0\ stItemsB\0\x12\x15\n\x04diff\x18\x06\x20\x01(\x0b2\x05.DiffB\0\x12\x1b\n\
\x12\x1c\n\x12resultingRevisions\x18\x08\x20\x03(\x0cB\0\x12\x17\n\rmult\ \nsyncResult\x18\x07\x20\x01(\x0b2\x05.DiffB\0\x12\x1c\n\x12resultingRev\
ipleHeads\x18\t\x20\x01(\x08B\0\x12\x12\n\x08upToDate\x18\n\x20\x01(\x08\ isions\x18\x08\x20\x03(\x0cB\0\x12\x17\n\rmultipleHeads\x18\t\x20\x01(\
B\0\x12-\n\rresolveAction\x18\x0c\x20\x03(\x0b2\x14.ClientResolveActionB\ \x08B\0\x12\x12\n\x08upToDate\x18\n\x20\x01(\x08B\0\x12-\n\rresolveActio\
\0\x12\x1e\n\x06issues\x18\r\x20\x03(\x0b2\x0c.ClientIssueB\0\x12\x10\n\ n\x18\x0c\x20\x03(\x0b2\x14.ClientResolveActionB\0\x12\x1e\n\x06issues\
\x06nonces\x18\x0e\x20\x03(\x05B\0:\0B\0b\x06proto2\ \x18\r\x20\x03(\x0b2\x0c.ClientIssueB\0\x12\x10\n\x06nonces\x18\x0e\x20\
\x03(\x05B\0:\0B\0b\x06proto2\
"; ";
static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {