mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-28 17:21:52 +00:00
Use new hm endpoint for playlists
This commit is contained in:
parent
da171c05ba
commit
8c6f5b7c28
4 changed files with 87 additions and 21 deletions
|
@ -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();
|
||||||
|
|
|
@ -80,7 +80,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");
|
||||||
|
@ -118,7 +119,7 @@ pub struct Album {
|
||||||
|
|
||||||
#[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>,
|
||||||
|
@ -221,13 +222,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 {
|
||||||
|
|
||||||
|
@ -248,6 +261,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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue