summary history branches tags files
commit:c0f430f71f5e92b4b4a0fb86615db7e4c823393b
author:Trevor Bentley
committer:Trevor Bentley
date:Tue Apr 11 16:37:40 2017 +0200
parents:423432c99d662652deebda3183e2718d7909a710
Added http query builder.  Added seek command.
diff --git a/src/lib.rs b/src/lib.rs
line changes: +4/-1
index 3f683d4..29381c7
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,11 +7,14 @@ pub use webapi::*;
 extern crate rustc_serialize;
 
 pub mod spotify_api {
-    pub const SCOPES: &'static [&'static str] = &["user-read-private", "streaming", "user-read-playback-state"];
+    pub const SCOPES: &'static [&'static str] = &[
+        "user-read-private", "streaming", "user-read-playback-state"
+    ];
     pub const AUTHORIZE: &'static str = "https://accounts.spotify.com/en/authorize";
     pub const TOKEN: &'static str = "https://accounts.spotify.com/api/token";
     pub const DEVICES: &'static str = "https://api.spotify.com/v1/me/player/devices";
     pub const PLAYER_STATE: &'static str = "https://api.spotify.com/v1/me/player";
     pub const PLAY: &'static str = "https://api.spotify.com/v1/me/player/play";
     pub const PAUSE: &'static str = "https://api.spotify.com/v1/me/player/pause";
+    pub const SEEK: &'static str = "https://api.spotify.com/v1/me/player/seek";
 }

diff --git a/src/main.rs b/src/main.rs
line changes: +1/-0
index 2ffdb49..e8a2713
--- a/src/main.rs
+++ b/src/main.rs
@@ -53,4 +53,5 @@ fn main() {
     spotify.set_target_device(None);
     require(spotify.play(Some(&ctx)));
     require(spotify.pause());
+    require(spotify.seek(5000));
 }

diff --git a/src/webapi/mod.rs b/src/webapi/mod.rs
line changes: +49/-10
index 281b20b..0f2cefb
--- a/src/webapi/mod.rs
+++ b/src/webapi/mod.rs
@@ -1,4 +1,5 @@
 use std::fmt;
+use std::collections::BTreeMap;
 
 extern crate rustc_serialize;
 use self::rustc_serialize::{Decodable, Decoder, json};
@@ -78,8 +79,14 @@ impl fmt::Display for PlayerState {
 }
 
 pub fn request_oauth_tokens(auth_code: &str, settings: &settings::Settings) -> (String, String) {
-    let query = format!("grant_type=authorization_code&code={}&redirect_uri=http://127.0.0.1:{}&client_id={}&client_secret={}",
-                        auth_code, settings.port, settings.client_id, settings.secret);
+    let query = QueryString::new()
+        .add("grant_type", "authorization_code")
+        .add("code", auth_code)
+        .add("redirect_uri", format!("http://127.0.0.1:{}", settings.port))
+        .add("client_id", settings.client_id.clone())
+        .add("client_secret", settings.secret.clone())
+        .build();
+
     let json_response = http::http(spotify_api::TOKEN, &query, "", http::HttpMethod::POST, None).unwrap();
     parse_spotify_token(&json_response)
 }
@@ -160,10 +167,33 @@ impl PlayContext {
     }
 }
 
-fn device_id_query(device: &Option<DeviceId>) -> String {
-    match device {
-        &Some(ref x) => format!("device_id={}", x),
-        &None => "".to_string()
+struct QueryString {
+    map: BTreeMap<String,String>,
+}
+impl QueryString {
+    fn new() -> QueryString { QueryString { map: BTreeMap::<String,String>::new() } }
+    fn add_opt(&mut self, key: &str, value: Option<String>) -> &mut QueryString {
+        match value {
+            Some(v) => { self.map.insert(key.to_string(), v); },
+            None => {},
+        }
+        self
+    }
+    fn add<A>(&mut self, key: &str, value: A) -> &mut QueryString
+        where A: ToString {
+        self.map.insert(key.to_string(), value.to_string());
+        self
+    }
+    fn build(&self) -> String {
+        let mut s = String::new();
+        for (key, val) in &self.map {
+            match s.len() {
+                0 => { } // '?' inserted in HTTP layer
+                _ => { s = s + "&"; }
+            }
+            s = s + &format!("{}={}", key, val);
+        }
+        s
     }
 }
 
@@ -190,18 +220,20 @@ impl SpotifyConnectr {
         self.refresh_token = refresh_token;
     }
     pub fn request_device_list(&self) -> ConnectDeviceList {
-        let json_response = http::http(spotify_api::DEVICES, "", "", http::HttpMethod::GET, Some(&self.access_token)).unwrap();
+        let json_response = http::http(spotify_api::DEVICES, "", "",
+                                       http::HttpMethod::GET, Some(&self.access_token)).unwrap();
         json::decode(&json_response).unwrap()
     }
     pub fn request_player_state(&self) -> PlayerState {
-        let json_response = http::http(spotify_api::PLAYER_STATE, "", "", http::HttpMethod::GET, Some(&self.access_token)).unwrap();
+        let json_response = http::http(spotify_api::PLAYER_STATE, "", "",
+                                       http::HttpMethod::GET, Some(&self.access_token)).unwrap();
         json::decode(&json_response).unwrap()
     }
     pub fn set_target_device(&mut self, device: Option<DeviceId>) {
         self.device = device;
     }
     pub fn play(&self, context: Option<&PlayContext>) -> SpotifyResponse {
-        let query = device_id_query(&self.device);
+        let query = QueryString::new().add_opt("device_id", self.device.clone()).build();
         let body = match context {
             Some(x) => json::encode(x).unwrap(),
             None => String::new(),
@@ -209,7 +241,14 @@ impl SpotifyConnectr {
         http::http(spotify_api::PLAY, &query, &body, http::HttpMethod::PUT, Some(&self.access_token))
     }
     pub fn pause(&self) -> SpotifyResponse {
-        let query = device_id_query(&self.device);
+        let query = QueryString::new().add_opt("device_id", self.device.clone()).build();
         http::http(spotify_api::PAUSE, &query, "", http::HttpMethod::PUT, Some(&self.access_token))
     }
+    pub fn seek(&self, position: u32) -> SpotifyResponse {
+        let query = QueryString::new()
+            .add_opt("device_id", self.device.clone())
+            .add("position_ms", position)
+            .build();
+        http::http(spotify_api::SEEK, &query, "", http::HttpMethod::PUT, Some(&self.access_token))
+    }
 }