extern crate connectr;
use connectr::SpotifyResponse;
-//extern crate systray;
-
-//#[cfg(target_os = "windows")]
-//fn systray(player_state: PlayerState) {
-// let mut app;
-// match systray::Application::new() {
-// Ok(w) => app = w,
-// Err(e) => panic!("Can't create systray window.")
-// }
-// let mut w = &mut app.window;
-// let _ = w.set_icon_from_file(&"spotify.ico".to_string());
-// let _ = w.set_tooltip(&"Whatever".to_string());
-// let _ = w.add_menu_item(&"Print a thing".to_string(), |window| {
-// println!("Printing a thing!");
-// });
-// println!("Waiting on message!");
-// w.wait_for_message();
-//}
+use std::ptr;
+use std::thread::sleep;
+use std::time::Duration;
+use std::sync::mpsc::channel;
-fn require(response: SpotifyResponse) {
- match response.code.unwrap() {
- 200 ... 299 => (),
- _ => panic!("{}", response)
- }
+extern crate rustc_serialize;
+use rustc_serialize::json;
+
+#[derive(RustcDecodable, RustcEncodable, Debug)]
+enum CallbackAction {
+ SelectDevice,
+ PlayPause,
+ Preset,
+}
+
+#[derive(RustcDecodable, RustcEncodable, Debug)]
+struct MenuCallbackCommand {
+ action: CallbackAction,
+ sender: u64,
+ data: String,
+}
+
+#[cfg(target_os = "macos")]
+use connectr::osx;
+#[cfg(target_os = "macos")]
+use connectr::osx::TStatusBar;
+#[cfg(target_os = "macos")]
+use connectr::osx::MenuItem;
+
+struct MenuItems {
+ device: Vec<MenuItem>,
+ play: MenuItem,
+ preset: Vec<MenuItem>,
+}
+struct ConnectrApp {
+ menu: MenuItems,
}
fn main() {
+ let mut app = ConnectrApp {
+ menu: MenuItems {
+ device: Vec::<MenuItem>::new(),
+ play: ptr::null_mut(),
+ preset: Vec::<MenuItem>::new(),
+ }
+ };
+ let (tx,rx) = channel::<String>();
let mut spotify = connectr::SpotifyConnectr::new();
spotify.connect();
+ spotify.set_target_device(None);
+ let mut status = osx::OSXStatusBar::new(tx);
let device_list = spotify.request_device_list();
- let player_state = spotify.request_player_state();
+
+ status.add_label("DEVICES:");
+ status.add_separator();
println!("Visible Devices:");
for dev in device_list {
println!("{}", dev);
+ let id = dev.id.clone();
+ let cb: osx::NSCallback = Box::new(move |sender, tx| {
+ let cmd = MenuCallbackCommand {
+ action: CallbackAction::SelectDevice,
+ sender: sender,
+ data: id.to_owned(),
+ };
+ let _ = tx.send(json::encode(&cmd).unwrap());
+ });
+ let item = status.add_item(&dev.name, cb, dev.is_active);
+ app.menu.device.push(item);
}
println!("");
+ let player_state = spotify.request_player_state();
println!("Playback State:\n{}", player_state);
+ let play_str = format!("{: ^50}\n{: ^50}\n{: ^50}",
+ &player_state.item.name,
+ &player_state.item.artists[0].name,
+ &player_state.item.album.name);
+ status.set_tooltip(&play_str);
- let ctx = connectr::PlayContext::new()
- .context_uri("spotify:user:mrmekon:playlist:4XqYlbPdDUsranzjicPCgf")
- .offset_position(2)
- .build();
-
- spotify.set_target_device(None);
- require(spotify.play(Some(&ctx)));
- require(spotify.pause());
- require(spotify.next());
- require(spotify.previous());
- require(spotify.seek(5000));
- require(spotify.volume(10));
- require(spotify.shuffle(true));
- require(spotify.repeat(connectr::SpotifyRepeat::Context));
- require(spotify.transfer_multi(vec!["1a793f2a23989a1c35d05b2fd1ff00e9a67e7134".to_string()], false));
- require(spotify.transfer("1a793f2a23989a1c35d05b2fd1ff00e9a67e7134".to_string(), false));
+ status.add_label("");
+ status.add_label("ACTIONS:");
+ status.add_separator();
+ {
+ let play_str = match player_state.is_playing {
+ true => "PAUSE",
+ false => "PLAY",
+ };
+ let cb: osx::NSCallback = Box::new(move |sender, tx| {
+ let is_playing = &player_state.is_playing;
+ let cmd = MenuCallbackCommand {
+ action: CallbackAction::PlayPause,
+ sender: sender,
+ data: is_playing.to_string(),
+ };
+ let _ = tx.send(json::encode(&cmd).unwrap());
+ });
+ app.menu.play = status.add_item(&play_str, cb, false);
+ }
- let player_state = spotify.request_player_state();
- println!("Final state:\n{}", player_state);
+ status.add_label("");
+ status.add_label("PRESETS:");
+ status.add_separator();
+ {
+ for uri in vec!["spotify:user:mrmekon:playlist:4c8eKK6kKrcdt1HToEX7Jc",
+ "spotify:user:spotify:playlist:37i9dQZEVXcOmDhsenkuCu"] {
+ let cb: osx::NSCallback = Box::new(move |sender, tx| {
+ let cmd = MenuCallbackCommand {
+ action: CallbackAction::Preset,
+ sender: sender,
+ data: uri.to_owned(),
+ };
+ let _ = tx.send(json::encode(&cmd).unwrap());
+ });
+ let item = status.add_item(uri, cb, false);
+ app.menu.preset.push(item);
+ }
+ }
loop {
- spotify.await_once(true);
+ spotify.await_once(false);
+ if let Ok(s) = rx.try_recv() {
+ println!("Received {}", s);
+ let cmd: MenuCallbackCommand = json::decode(&s).unwrap();
+ match cmd.action {
+ CallbackAction::SelectDevice => {
+ let device = &app.menu.device;
+ for item in device {
+ status.unsel_item(*item as u64);
+ }
+ status.sel_item(cmd.sender);
+ // Spotify is broken. Must be 'true', always starts playing.
+ require(spotify.transfer(cmd.data, true));
+ },
+ CallbackAction::PlayPause => {
+ let player_state = spotify.request_player_state();
+ match player_state.is_playing {
+ true => {require(spotify.pause());},
+ false => {require(spotify.play(None));},
+ }
+ //let player_state = spotify.request_player_state();
+ let play_str = match player_state.is_playing {
+ false => "PAUSE",
+ true => "PLAY",
+ };
+ status.update_item(app.menu.play, play_str);
+ },
+ CallbackAction::Preset => {
+ play_uri(&mut spotify, None, Some(&cmd.data));
+ }
+ }
+ }
+ status.run(false);
+ sleep(Duration::from_millis(10));
+ }
+}
+
+fn require(response: SpotifyResponse) {
+ match response.code.unwrap() {
+ 200 ... 299 => (),
+ _ => panic!("{}", response)
}
+ println!("Response: {}", response.code.unwrap());
}
+
+fn play_uri(spotify: &mut connectr::SpotifyConnectr, device: Option<&str>, uri: Option<&str>) {
+ match device {
+ Some(dev) => { spotify.set_target_device(Some(dev.to_string())); },
+ None => { spotify.set_target_device(None); },
+ }
+ match uri {
+ Some(s) => {
+ let ctx = connectr::PlayContext::new()
+ .context_uri(s)
+ .offset_position(0)
+ .build();
+ require(spotify.play(Some(&ctx)));
+ }
+ None => {
+ println!("Transfer!");
+ require(spotify.play(None));
+ }
+ };
+}
+
+// spotify.set_target_device(None);
+// require(spotify.pause());
+// require(spotify.next());
+// require(spotify.previous());
+// require(spotify.seek(5000));
+// require(spotify.volume(10));
+// require(spotify.shuffle(true));
+// require(spotify.repeat(connectr::SpotifyRepeat::Context));
+// require(spotify.transfer_multi(vec!["1a793f2a23989a1c35d05b2fd1ff00e9a67e7134".to_string()], false));
+// require(spotify.transfer("1a793f2a23989a1c35d05b2fd1ff00e9a67e7134".to_string(), false));
+pub mod rustnsobject;
+
+extern crate objc;
+extern crate objc_foundation;
+extern crate cocoa;
+
+pub use self::rustnsobject::NSCallback;
+
+use objc::runtime::{Class, Object};
+
+use self::cocoa::base::{nil, YES};
+use self::cocoa::appkit::NSStatusBar;
+use self::cocoa::foundation::{NSAutoreleasePool,NSString};
+use self::cocoa::appkit::{NSApp,
+ NSApplication,
+ NSApplicationActivationPolicyAccessory,
+ NSMenu,
+ NSMenuItem,
+ NSImage,
+ NSVariableStatusItemLength,
+ NSStatusItem,
+ NSButton};
+
+use self::rustnsobject::{NSObj, NSObjTrait, NSObjCallbackTrait};
+
+use std::sync::mpsc::Sender;
+
+use std::thread::sleep;
+use std::time::Duration;
+
+extern crate objc_id;
+use self::objc_id::Id;
+
+pub type MenuItem = *mut Object;
+
+pub struct OSXStatusBar {
+ object: NSObj,
+ app: *mut objc::runtime::Object,
+ status_bar_item: *mut objc::runtime::Object,
+ menu_bar: *mut objc::runtime::Object,
+}
+pub trait TStatusBar {
+ type S: TStatusBar;
+ fn new(tx: Sender<String>) -> Self::S;
+ fn add_separator(&mut self);
+ fn add_label(&mut self, label: &str);
+ fn add_item(&mut self, item: &str, callback: NSCallback, selected: bool) -> *mut Object;
+ fn update_item(&mut self, item: *mut Object, label: &str);
+ fn sel_item(&mut self, sender: u64);
+ fn unsel_item(&mut self, sender: u64);
+ fn set_tooltip(&self, text: &str);
+ fn run(&mut self, block: bool);
+}
+
+impl TStatusBar for OSXStatusBar {
+ type S = OSXStatusBar;
+ fn new(tx: Sender<String>) -> OSXStatusBar {
+ let mut bar;
+ unsafe {
+ let _ = NSAutoreleasePool::new(nil);
+ let app = NSApp();
+ let status_bar = NSStatusBar::systemStatusBar(nil);
+ bar = OSXStatusBar {
+ app: app,
+ //status_bar_item: status_bar.statusItemWithLength_(NSSquareStatusItemLength),
+ status_bar_item: status_bar.statusItemWithLength_(NSVariableStatusItemLength),
+ menu_bar: NSMenu::new(nil).autorelease(),
+ object: NSObj::alloc(tx).setup(),
+ };
+ bar.app.setActivationPolicy_(NSApplicationActivationPolicyAccessory);
+ msg_send![bar.status_bar_item, setHighlightMode:YES];
+ let img = NSString::alloc(nil).init_str("spotify.png");
+ let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
+ NSButton::setTitle_(bar.status_bar_item, NSString::alloc(nil).init_str("connectr"));
+ bar.status_bar_item.button().setImage_(icon);
+ bar.status_bar_item.setMenu_(bar.menu_bar);
+ bar.object.cb_fn = Some(Box::new(
+ move |s, sender| {
+ let cb = s.get_value(sender);
+ cb(sender, &s.tx);
+ }
+ ));
+ }
+ bar
+ }
+ fn set_tooltip(&self, text: &str) {
+ unsafe {
+ let img = NSString::alloc(nil).init_str(text);
+ let _ = msg_send![self.status_bar_item.button(), setToolTip: img];
+ }
+ }
+ fn add_label(&mut self, label: &str) {
+ unsafe {
+ let txt = NSString::alloc(nil).init_str(label);
+ let quit_key = NSString::alloc(nil).init_str("");
+ let app_menu_item = NSMenuItem::alloc(nil)
+ .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key)
+ .autorelease();
+ self.menu_bar.addItem_(app_menu_item);
+ }
+ }
+ fn add_separator(&mut self) {
+ unsafe {
+ let cls = Class::get("NSMenuItem").unwrap();
+ let sep: *mut Object = msg_send![cls, separatorItem];
+ self.menu_bar.addItem_(sep);
+ }
+ }
+ fn add_item(&mut self, item: &str, callback: NSCallback, selected: bool) -> *mut Object {
+ unsafe {
+ let txt = NSString::alloc(nil).init_str(item);
+ let quit_key = NSString::alloc(nil).init_str("");
+ let app_menu_item = NSMenuItem::alloc(nil)
+ .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key)
+ .autorelease();
+ self.object.add_callback(app_menu_item, callback);
+ let objc = self.object.take_objc();
+ let _: () = msg_send![app_menu_item, setTarget: objc];
+ if selected {
+ let _: () = msg_send![app_menu_item, setState: 1];
+ }
+ let item: *mut Object = app_menu_item;
+ self.menu_bar.addItem_(app_menu_item);
+ item
+ }
+ }
+ fn update_item(&mut self, item: *mut Object, label: &str) {
+ unsafe {
+ let ns_label = NSString::alloc(nil).init_str(label);
+ let _: () = msg_send![item, setTitle: ns_label];
+ }
+ }
+ fn sel_item(&mut self, sender: u64) {
+ let target: *mut Object = sender as *mut Object;
+ unsafe {
+ let _: () = msg_send![target, setState: 1];
+ }
+ }
+ fn unsel_item(&mut self, sender: u64) {
+ let target: *mut Object = sender as *mut Object;
+ unsafe {
+ let _: () = msg_send![target, setState: 0];
+ }
+ }
+ fn run(&mut self, block: bool) {
+ //unsafe {
+ //self.app.run();
+ //}
+ let _ = unsafe {NSAutoreleasePool::new(nil)};
+ unsafe { let _: () = msg_send![self.app, finishLaunching]; }
+ loop {
+ sleep(Duration::from_millis(50));
+ unsafe {
+ let _ = NSAutoreleasePool::new(nil);
+ let cls = Class::get("NSDate").unwrap();
+ let date: Id<Object> = msg_send![cls, distantPast];
+ let mode = NSString::alloc(nil).init_str("kCFRunLoopDefaultMode");
+ let event: Id<Object> = msg_send![self.app, nextEventMatchingMask: -1
+ untilDate: date inMode:mode dequeue: YES];
+ let _ = msg_send![self.app, sendEvent: event];
+ let _ = msg_send![self.app, updateWindows];
+ }
+ if !block { break; }
+ }
+ }
+}
+// Copied from rustc-objc-foundation project by SSheldon, examples/custom_class.rs
+// https://github.com/SSheldon/rust-objc-foundation/blob/master/examples/custom_class.rs
+// Covered by MIT License: https://en.wikipedia.org/wiki/MIT_License
+
+extern crate objc;
+extern crate objc_foundation;
+extern crate objc_id;
+
+use std::sync::{Once, ONCE_INIT};
+
+use objc::Message;
+use objc::declare::ClassDecl;
+use objc::runtime::{Class, Object, Sel};
+use self::objc_foundation::{INSObject, NSObject};
+
+use std::collections::BTreeMap;
+
+use self::objc_id::Id;
+use self::objc_id::WeakId;
+use self::objc_id::Shared;
+
+use std::sync::mpsc::{channel, Sender, Receiver};
+
+pub struct RustWrapperClass {
+ pub objc: Id<ObjcSubclass, Shared>,
+ pub value: u64,
+ pub cb_fn: Option<Box<Fn(&mut RustWrapperClass, u64)>>,
+ pub channel: (Sender<u32>, Receiver<u32>),
+ pub map: BTreeMap<u64, NSCallback>,
+ pub tx: Sender<String>,
+}
+
+pub type NSObj = Box<RustWrapperClass>;
+pub type NSObjc = Id<ObjcSubclass, Shared>;
+
+pub trait NSObjCallbackTrait {
+ fn set_value(&mut self, u64, NSCallback);
+ fn get_value(&self, u64) -> &NSCallback;
+}
+
+impl NSObjCallbackTrait for RustWrapperClass {
+ fn set_value(&mut self, key: u64, val: NSCallback) {
+ self.map.insert(key, val);
+ }
+ fn get_value(&self, key: u64) -> &NSCallback {
+ self.map.get(&key).unwrap()
+ }
+}
+
+pub trait NSObjTrait {
+ fn alloc(tx: Sender<String>) -> NSObj;
+ fn setup(self) -> NSObj;
+ fn selector(&self) -> Sel;
+ fn take_objc(&mut self) -> NSObjc;
+ fn add_callback(&mut self, *const Object, NSCallback);
+}
+
+impl NSObjTrait for NSObj {
+ fn add_callback(&mut self, item: *const Object, cb: NSCallback) {
+ let sender: u64 = item as u64;
+ self.set_value(sender, cb);
+ }
+ fn alloc(tx: Sender<String>) -> NSObj {
+ let objc = ObjcSubclass::new().share();
+ let rust = Box::new(RustWrapperClass {
+ objc: objc,
+ value: 716,
+ channel: channel(),
+ map: BTreeMap::<u64,NSCallback>::new(),
+ cb_fn: None,
+ tx: tx,
+ });
+ unsafe {
+ let ptr: u64 = &*rust as *const RustWrapperClass as u64;
+ let _ = msg_send![rust.objc, setRustData: ptr];
+ }
+ return rust
+ }
+ fn setup(self) -> NSObj {
+ self
+ }
+ fn selector(&self) -> Sel {
+ sel!(cb:)
+ }
+ fn take_objc(&mut self) -> NSObjc {
+ let weak = WeakId::new(&self.objc);
+ weak.load().unwrap()
+ }
+}
+
+pub type NSObjCallback<T> = Box<Fn(&mut T, u64)>;
+pub type NSCallback = Box<Fn(u64, &Sender<String>)>;
+
+impl NSObjCallbackTrait for NSObj {
+ fn set_value(&mut self, key: u64, val: NSCallback) {
+ self.map.insert(key, val);
+ }
+ fn get_value(&self, key: u64) -> &NSCallback {
+ self.map.get(&key).unwrap()
+ }
+}
+
+// ObjcSubclass is a subclass of the objective-c NSObject base class.
+// This is registered with the objc runtime, so instances of this class
+// are "owned" by objc, and have no associated Rust data.
+//
+// This can be wrapped with a RustWrapperClass, which is a proper Rust struct
+// with its own storage, and holds an instance of ObjcSubclass.
+//
+// An ObjcSubclass can "talk" to its Rust wrapper class through function
+// pointers, as long as the storage is on the heap with a Box and the underlying
+// memory address doesn't change. The NSObj type wraps RustWrapperClass up
+// in a Box. The functions in the NSObjTrait trait operate on the boxed struct,
+// while keeping its storage location on the heap persistent.
+//
+pub enum ObjcSubclass {}
+impl ObjcSubclass {}
+
+unsafe impl Message for ObjcSubclass { }
+
+static OBJC_SUBCLASS_REGISTER_CLASS: Once = ONCE_INIT;
+
+impl INSObject for ObjcSubclass {
+ fn class() -> &'static Class {
+ OBJC_SUBCLASS_REGISTER_CLASS.call_once(|| {
+ let superclass = NSObject::class();
+ let mut decl = ClassDecl::new("ObjcSubclass", superclass).unwrap();
+ decl.add_ivar::<u64>("_rustdata");
+
+ extern fn objc_cb(this: &mut Object, _cmd: Sel, sender: u64) {
+ unsafe {
+ let ptr: u64 = *this.get_ivar("_rustdata");
+ let rustdata: &mut RustWrapperClass = &mut *(ptr as *mut RustWrapperClass);
+ if let Some(ref cb) = rustdata.cb_fn {
+ // Ownership? Fuck ownership!
+ let mut rustdata: &mut RustWrapperClass = &mut *(ptr as *mut RustWrapperClass);
+ cb(rustdata, sender);
+ }
+ }
+ }
+ extern fn objc_set_rust_data(this: &mut Object, _cmd: Sel, ptr: u64) {
+ unsafe {this.set_ivar("_rustdata", ptr);}
+ }
+ extern fn objc_get_rust_data(this: &Object, _cmd: Sel) -> u64 {
+ unsafe {*this.get_ivar("_rustdata")}
+ }
+
+ unsafe {
+ let f: extern fn(&mut Object, Sel, u64) = objc_cb;
+ decl.add_method(sel!(cb:), f);
+ let f: extern fn(&mut Object, Sel, u64) = objc_set_rust_data;
+ decl.add_method(sel!(setRustData:), f);
+ let f: extern fn(&Object, Sel) -> u64 = objc_get_rust_data;
+ decl.add_method(sel!(rustData), f);
+ }
+
+ decl.register();
+ });
+
+ Class::get("ObjcSubclass").unwrap()
+ }
+}
+// Copied from rustc-objc-foundation project by SSheldon, examples/custom_class.rs
+// https://github.com/SSheldon/rust-objc-foundation/blob/master/examples/custom_class.rs
+// Covered by MIT License: https://en.wikipedia.org/wiki/MIT_License
+
+#[macro_use]
+extern crate objc;
+extern crate objc_foundation;
+
+use std::sync::{Once, ONCE_INIT};
+
+use objc::Message;
+use objc::declare::ClassDecl;
+use objc::runtime::{Class, Object, Sel};
+use objc_foundation::{INSObject, NSObject};
+
+pub enum RustNSObject { }
+
+impl RustNSObject {
+ fn number(&self) -> u32 {
+ unsafe {
+ let obj = &*(self as *const _ as *const Object);
+ *obj.get_ivar("_number")
+ }
+ }
+
+ fn set_number(&mut self, number: u32) {
+ unsafe {
+ let obj = &mut *(self as *mut _ as *mut Object);
+ obj.set_ivar("_number", number);
+ }
+ }
+}
+
+unsafe impl Message for RustNSObject { }
+
+static RUSTNSOBJECT_REGISTER_CLASS: Once = ONCE_INIT;
+
+impl INSObject for RustNSObject {
+ fn class() -> &'static Class {
+ RUSTNSOBJECT_REGISTER_CLASS.call_once(|| {
+ let superclass = NSObject::class();
+ let mut decl = ClassDecl::new("RustNSObject", superclass).unwrap();
+ decl.add_ivar::<u32>("_number");
+
+ // Add ObjC methods for getting and setting the number
+ extern fn my_object_set_number(this: &mut Object, _cmd: Sel, number: u32) {
+ unsafe { this.set_ivar("_number", number); }
+ }
+
+ extern fn my_object_get_number(this: &Object, _cmd: Sel) -> u32 {
+ unsafe { *this.get_ivar("_number") }
+ }
+
+ unsafe {
+ let set_number: extern fn(&mut Object, Sel, u32) = my_object_set_number;
+ decl.add_method(sel!(setNumber:), set_number);
+ let get_number: extern fn(&Object, Sel) -> u32 = my_object_get_number;
+ decl.add_method(sel!(number), get_number);
+ }
+
+ decl.register();
+ });
+
+ Class::get("RustNSObject").unwrap()
+ }
+}
+
+fn main() {
+ let mut obj = RustNSObject::new();
+
+ obj.set_number(7);
+ println!("Number: {}", unsafe {
+ let number: u32 = msg_send![obj, number];
+ number
+ });
+
+ unsafe {
+ let _: () = msg_send![obj, setNumber:12u32];
+ }
+ println!("Number: {}", obj.number());
+}
use super::spotify_api;
use super::http::HttpResponse;
+pub type DeviceId = String;
+pub type SpotifyResponse = HttpResponse;
+
pub fn parse_spotify_token(json: &str) -> (String, String, u64) {
let json_data = Json::from_str(&json).unwrap();
let obj = json_data.as_object().unwrap();
}
#[derive(RustcDecodable, RustcEncodable, Debug)]
+pub struct ConnectPlaybackArtist {
+ pub name: String,
+ pub uri: String,
+}
+
+#[derive(RustcDecodable, RustcEncodable, Debug)]
+pub struct ConnectPlaybackAlbum {
+ pub name: String,
+ pub uri: String,
+}
+
+#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct ConnectPlaybackItem {
- duration_ms: u32,
- name: String,
- uri: String,
+ pub duration_ms: u32,
+ pub name: String,
+ pub uri: String,
+ pub album: ConnectPlaybackAlbum,
+ pub artists: Vec<ConnectPlaybackArtist>,
}
#[derive(RustcDecodable, RustcEncodable, Debug)]
parse_spotify_token(&json_response)
}
-pub type DeviceId = String;
-
#[derive(RustcDecodable, RustcEncodable)]
pub struct PlayContextOffset {
pub position: Option<u32>,
}
}
-pub type SpotifyResponse = HttpResponse;
-
pub enum SpotifyRepeat {
Off,
Track,
.build();
http::http(spotify_api::REPEAT, &query, "", http::HttpMethod::PUT, self.bearer_token())
}
- pub fn transfer_multi(&self, devices: Vec<String>, play: bool) -> SpotifyResponse {
+ pub fn transfer_multi(&mut self, devices: Vec<String>, play: bool) -> SpotifyResponse {
+ let device = devices[0].clone();
let body = json::encode(&DeviceIdList {device_ids: devices, play: play}).unwrap();
+ self.set_target_device(Some(device));
http::http(spotify_api::PLAYER, "", &body, http::HttpMethod::PUT, self.bearer_token())
}
- pub fn transfer(&self, device: String, play: bool) -> SpotifyResponse {
- let body = json::encode(&DeviceIdList {device_ids: vec![device], play: play}).unwrap();
+ pub fn transfer(&mut self, device: String, play: bool) -> SpotifyResponse {
+ let body = json::encode(&DeviceIdList {device_ids: vec![device.clone()], play: play}).unwrap();
+ self.set_target_device(Some(device));
http::http(spotify_api::PLAYER, "", &body, http::HttpMethod::PUT, self.bearer_token())
}
}