use json::JsonValue;
use time::{self, Timespec, Tm};
pub struct SpotifyStatusChange {
pub volume: bool,
pub online: bool,
pub version: bool,
pub running: bool,
pub playing: bool,
pub shuffle: bool,
pub server_time: bool,
pub play_enabled: bool,
pub prev_enabled: bool,
pub next_enabled: bool,
pub client_version: bool,
pub playing_position: bool,
pub open_graph_state: bool,
pub track: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SpotifyStatus {
volume: f32,
online: bool,
version: i32,
running: bool,
playing: bool,
shuffle: bool,
server_time: i64,
play_enabled: bool,
prev_enabled: bool,
next_enabled: bool,
client_version: String,
playing_position: f32,
open_graph_state: OpenGraphState,
track: Track,
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct OpenGraphState {
private_session: bool,
posting_disabled: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Track {
pub track: Resource,
pub album: Resource,
pub artist: Resource,
pub length: i32,
pub track_type: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Resource {
pub uri: String,
pub name: String,
pub location: ResourceLocation,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResourceLocation {
pub og: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleTrack {
pub name: String,
pub album: String,
pub artist: String,
}
#[inline]
fn get_json_str(json: &JsonValue) -> String {
match json.as_str() {
Some(val) => val.to_owned(),
None => String::default(),
}
}
impl SpotifyStatus {
pub fn track(&self) -> SimpleTrack {
SimpleTrack::from(&self.track)
}
pub fn full_track(&self) -> Track {
self.track.clone()
}
pub fn version(&self) -> String {
self.client_version.clone()
}
pub fn volume(&self) -> f32 {
self.volume
}
pub fn volume_percentage(&self) -> f32 {
(self.volume * 100_f32).trunc()
}
pub fn timestamp(&self) -> i64 {
self.server_time
}
pub fn time(&self) -> Tm {
time::at(Timespec::new(self.server_time, 0))
}
pub fn time_utc(&self) -> Tm {
time::at_utc(Timespec::new(self.server_time, 0))
}
pub fn shuffle_enabled(&self) -> bool {
self.shuffle
}
pub fn is_online(&self) -> bool {
self.online
}
pub fn is_private_session(&self) -> bool {
self.open_graph_state.private_session
}
}
impl SpotifyStatusChange {
pub fn new_true() -> SpotifyStatusChange {
SpotifyStatusChange {
volume: true,
online: true,
version: true,
running: true,
playing: true,
shuffle: true,
server_time: true,
play_enabled: true,
prev_enabled: true,
next_enabled: true,
client_version: true,
playing_position: true,
open_graph_state: true,
track: true,
}
}
}
impl From<JsonValue> for SpotifyStatus {
fn from(json: JsonValue) -> SpotifyStatus {
SpotifyStatus {
volume: json["volume"].as_f32().unwrap_or(0_f32),
online: json["online"] == true,
version: json["version"].as_i32().unwrap_or(0_i32),
running: json["running"] == true,
playing: json["playing"] == true,
shuffle: json["shuffle"] == true,
server_time: json["server_time"].as_i64().unwrap_or(0_i64),
play_enabled: json["play_enabled"] == true,
prev_enabled: json["prev_enabled"] == true,
next_enabled: json["next_enabled"] == true,
client_version: get_json_str(&json["client_version"]),
playing_position: json["playing_position"].as_f32().unwrap_or(0_f32),
open_graph_state: OpenGraphState::from(&json["open_graph_state"]),
track: Track::from(&json["track"]),
}
}
}
impl<'a> From<&'a JsonValue> for OpenGraphState {
fn from(json: &'a JsonValue) -> OpenGraphState {
OpenGraphState {
private_session: json["private_session"] == true,
posting_disabled: json["posting_disabled"] == true,
}
}
}
impl<'a> From<&'a JsonValue> for Track {
fn from(json: &'a JsonValue) -> Track {
Track {
track_type: get_json_str(&json["uri"]),
track: Resource::from(&json["track_resource"]),
album: Resource::from(&json["album_resource"]),
artist: Resource::from(&json["artist_resource"]),
length: json["length"].as_i32().unwrap_or(0_i32),
}
}
}
impl<'a> From<&'a JsonValue> for Resource {
fn from(json: &'a JsonValue) -> Resource {
Resource {
uri: get_json_str(&json["uri"]),
name: get_json_str(&json["name"]),
location: ResourceLocation::from(&json["location"]),
}
}
}
impl<'a> From<&'a JsonValue> for ResourceLocation {
fn from(json: &'a JsonValue) -> ResourceLocation {
ResourceLocation {
og: get_json_str(&json["og"]),
}
}
}
impl<'a> From<&'a Track> for SimpleTrack {
fn from(track: &'a Track) -> SimpleTrack {
SimpleTrack {
name: track.track.name.clone(),
album: track.album.name.clone(),
artist: track.artist.name.clone(),
}
}
}
impl<'a> From<&'a SpotifyStatus> for SimpleTrack {
fn from(status: &'a SpotifyStatus) -> SimpleTrack {
SimpleTrack::from(&status.track)
}
}
impl ::std::fmt::Display for SimpleTrack {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{} - {}", self.artist, self.name)
}
}
impl From<(SpotifyStatus, SpotifyStatus)> for SpotifyStatusChange {
fn from(set: (SpotifyStatus, SpotifyStatus)) -> SpotifyStatusChange {
let curr = set.0;
let last = set.1;
macro_rules! status_compare_field {
($field:ident) => {
curr.$field != last.$field
};
}
SpotifyStatusChange {
volume: status_compare_field!(volume),
online: status_compare_field!(online),
version: status_compare_field!(version),
running: status_compare_field!(running),
playing: status_compare_field!(playing),
shuffle: status_compare_field!(shuffle),
server_time: status_compare_field!(server_time),
play_enabled: status_compare_field!(play_enabled),
prev_enabled: status_compare_field!(prev_enabled),
next_enabled: status_compare_field!(next_enabled),
client_version: status_compare_field!(client_version),
playing_position: status_compare_field!(playing_position),
open_graph_state: status_compare_field!(open_graph_state),
track: status_compare_field!(track),
}
}
}