Browse Source

Add initial Spirc support.

Paul Lietar 9 years ago
parent
commit
7897070bb7
2 changed files with 48 additions and 13 deletions
  1. 27 4
      src/main.rs
  2. 21 9
      src/mercury.rs

+ 27 - 4
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());
 
-
-    print_track(&mut cache, track_id);
+    let (tx, rx) = mpsc::channel();
+
+    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();

+ 21 - 9
src/mercury.rs

@@ -23,7 +23,7 @@ pub struct MercuryRequest {
     pub method: MercuryMethod,
     pub uri: String,
     pub content_type: Option<String>,
-    pub callback: MercuryCallback
+    pub callback: Option<MercuryCallback>
 }
 
 #[derive(Debug)]
@@ -32,17 +32,18 @@ pub struct MercuryResponse {
     pub payload: LinkedList<Vec<u8>>
 }
 
-pub type MercuryCallback = Option<mpsc::Sender<MercuryResponse>>;
+pub type MercuryCallback = mpsc::Sender<MercuryResponse>;
 
 pub struct MercuryPending {
     parts: LinkedList<Vec<u8>>,
     partial: Option<Vec<u8>>,
-    callback: MercuryCallback,
+    callback: Option<MercuryCallback>
 }
 
 pub struct MercuryManager {
     next_seq: u32,
     pending: HashMap<Vec<u8>, MercuryPending>,
+    subscriptions: HashMap<String, MercuryCallback>,
 
     requests: mpsc::Receiver<MercuryRequest>,
     packet_tx: mpsc::Sender<Packet>,
@@ -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<u8> {
@@ -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