From 7897070bb7b34c482fe6f569fb8c2e6bf1fb754c Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Wed, 1 Jul 2015 20:47:51 +0200 Subject: [PATCH] Add initial Spirc support. --- src/main.rs | 29 ++++++++++++++++++++++++++--- src/mercury.rs | 30 +++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index cbadbc88..72d57bfb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ #![crate_name = "librespot"] #![feature(plugin,zero_one,iter_arith,slice_position_elem,slice_bytes,bitset,mpsc_select,arc_weak,append)] +#![allow(unused_imports,dead_code)] #![plugin(protobuf_macros)] #[macro_use] extern crate lazy_static; + extern crate byteorder; extern crate crypto; extern crate gmp; @@ -35,19 +37,20 @@ use std::clone::Clone; use std::fs::File; use std::io::{Read, Write}; use std::path::Path; +use std::sync::mpsc; use metadata::{MetadataCache, AlbumRef, ArtistRef, TrackRef}; use session::{Config, Session}; use util::SpotifyId; use player::Player; +use mercury::{MercuryRequest, MercuryMethod}; +use librespot_protocol as protocol; fn main() { let mut args = std::env::args().skip(1); let mut appkey_file = File::open(Path::new(&args.next().unwrap())).unwrap(); let username = args.next().unwrap(); let password = args.next().unwrap(); - let track_uri = args.next().unwrap(); - let track_id = SpotifyId::from_base62(track_uri.split(':').nth(2).unwrap()); let mut appkey = Vec::new(); appkey_file.read_to_end(&mut appkey).unwrap(); @@ -63,8 +66,28 @@ fn main() { let mut cache = MetadataCache::new(session.metadata.clone()); + let (tx, rx) = mpsc::channel(); - print_track(&mut cache, track_id); + session.mercury.send(MercuryRequest{ + method: MercuryMethod::SUB, + uri: "hm://remote/user/lietar/v23".to_string(), + content_type: None, + callback: Some(tx) + }).unwrap(); + + for pkt in rx.iter() { + let frame : protocol::spirc::Frame = + protobuf::parse_from_bytes(pkt.payload.front().unwrap()).unwrap(); + + if frame.get_device_state().get_is_active() && + frame.has_state() { + let index = frame.get_state().get_playing_track_index(); + let ref track = frame.get_state().get_track()[index as usize]; + println!("{}", frame.get_device_state().get_name()); + print_track(&mut cache, SpotifyId::from_raw(track.get_gid())); + println!(""); + } + } loop { session.poll(); diff --git a/src/mercury.rs b/src/mercury.rs index abe1eb91..3b36f3db 100644 --- a/src/mercury.rs +++ b/src/mercury.rs @@ -23,7 +23,7 @@ pub struct MercuryRequest { pub method: MercuryMethod, pub uri: String, pub content_type: Option, - pub callback: MercuryCallback + pub callback: Option } #[derive(Debug)] @@ -32,17 +32,18 @@ pub struct MercuryResponse { pub payload: LinkedList> } -pub type MercuryCallback = Option>; +pub type MercuryCallback = mpsc::Sender; pub struct MercuryPending { parts: LinkedList>, partial: Option>, - callback: MercuryCallback, + callback: Option } pub struct MercuryManager { next_seq: u32, pending: HashMap, MercuryPending>, + subscriptions: HashMap, requests: mpsc::Receiver, packet_tx: mpsc::Sender, @@ -69,6 +70,7 @@ impl MercuryManager { (MercuryManager { next_seq: 0, pending: HashMap::new(), + subscriptions: HashMap::new(), requests: req_rx, packet_rx: pkt_rx, @@ -93,11 +95,15 @@ impl MercuryManager { data: data }).unwrap(); - self.pending.insert(seq.to_vec(), MercuryPending{ - parts: LinkedList::new(), - partial: None, - callback: req.callback, - }); + if req.method != MercuryMethod::SUB { + self.pending.insert(seq.to_vec(), MercuryPending{ + parts: LinkedList::new(), + partial: None, + callback: req.callback, + }); + } else if let Some(cb) = req.callback { + self.subscriptions.insert(req.uri, cb); + } } fn parse_part(mut s: &mut Read) -> Vec { @@ -117,7 +123,13 @@ impl MercuryManager { let header : protocol::mercury::Header = protobuf::parse_from_bytes(&header_data).unwrap(); - if let Some(ref ch) = pending.callback { + let callback = if cmd == 0xb5 { + self.subscriptions.get(header.get_uri()) + } else { + pending.callback.as_ref() + }; + + if let Some(ref ch) = callback { ch.send(MercuryResponse{ uri: header.get_uri().to_string(), payload: pending.parts