mirror of
https://github.com/librespot-org/librespot.git
synced 2024-11-08 16:45:43 +00:00
spirc: Keep track of player status
This commit is contained in:
parent
df11960946
commit
c1ce87dbbd
1 changed files with 169 additions and 36 deletions
203
src/main.rs
203
src/main.rs
|
@ -48,6 +48,7 @@ use util::version::version_string;
|
|||
use player::Player;
|
||||
use mercury::{MercuryRequest, MercuryMethod};
|
||||
use librespot_protocol as protocol;
|
||||
use librespot_protocol::spirc::PlayStatus;
|
||||
|
||||
fn main() {
|
||||
let mut args = std::env::args().skip(1);
|
||||
|
@ -83,6 +84,8 @@ fn main() {
|
|||
can_play: true,
|
||||
is_active: false,
|
||||
became_active_at: 0,
|
||||
|
||||
state: PlayerState::new()
|
||||
}.run();
|
||||
|
||||
/*
|
||||
|
@ -118,6 +121,88 @@ fn print_track(cache: &mut MetadataCache, track_id: SpotifyId) {
|
|||
}
|
||||
}
|
||||
|
||||
struct PlayerState {
|
||||
status: PlayStatus,
|
||||
|
||||
context_uri: String,
|
||||
index: u32,
|
||||
queue: Vec<SpotifyId>,
|
||||
|
||||
repeat: bool,
|
||||
shuffle: bool,
|
||||
|
||||
position_ms: u32,
|
||||
position_measured_at: i64,
|
||||
|
||||
last_command_ident: String,
|
||||
last_command_msgid: u32,
|
||||
}
|
||||
|
||||
impl PlayerState {
|
||||
fn new() -> PlayerState {
|
||||
PlayerState {
|
||||
status: PlayStatus::kPlayStatusPause,
|
||||
|
||||
context_uri: String::new(),
|
||||
index: 0,
|
||||
queue: Vec::new(),
|
||||
|
||||
repeat: false,
|
||||
shuffle: false,
|
||||
|
||||
position_ms: 0,
|
||||
position_measured_at: 0,
|
||||
|
||||
last_command_ident: String::new(),
|
||||
last_command_msgid: 0
|
||||
}
|
||||
}
|
||||
|
||||
fn import(&mut self, state: &protocol::spirc::State) {
|
||||
//println!("{:?}", state);
|
||||
self.status = state.get_status();
|
||||
|
||||
self.context_uri = state.get_context_uri().to_string();
|
||||
self.index = state.get_playing_track_index();
|
||||
self.queue = state.get_track().iter().filter(|t| {
|
||||
t.has_gid()
|
||||
}).map(|t| {
|
||||
SpotifyId::from_raw(t.get_gid())
|
||||
}).collect();
|
||||
|
||||
self.repeat = state.get_repeat();
|
||||
self.shuffle = state.get_shuffle();
|
||||
|
||||
self.position_ms = state.get_position_ms();
|
||||
self.position_measured_at = SpircManager::now();
|
||||
}
|
||||
|
||||
fn export(&self) -> protocol::spirc::State {
|
||||
protobuf_init!(protocol::spirc::State::new(), {
|
||||
status: self.status,
|
||||
|
||||
context_uri: self.context_uri.to_string(),
|
||||
playing_track_index: self.index,
|
||||
track: self.queue.iter().map(|t| {
|
||||
protobuf_init!(protocol::spirc::TrackRef::new(), {
|
||||
gid: t.to_raw().to_vec()
|
||||
})
|
||||
}).collect(),
|
||||
|
||||
shuffle: self.shuffle,
|
||||
repeat: self.repeat,
|
||||
|
||||
position_ms: self.position_ms,
|
||||
position_measured_at: self.position_measured_at as u64,
|
||||
|
||||
playing_from_fallback: true,
|
||||
|
||||
last_command_ident: self.last_command_ident.clone(),
|
||||
last_command_msgid: self.last_command_msgid
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct SpircManager {
|
||||
session: Session,
|
||||
username: String,
|
||||
|
@ -132,6 +217,8 @@ struct SpircManager {
|
|||
can_play: bool,
|
||||
is_active: bool,
|
||||
became_active_at: i64,
|
||||
|
||||
state: PlayerState
|
||||
}
|
||||
|
||||
impl SpircManager {
|
||||
|
@ -140,7 +227,7 @@ impl SpircManager {
|
|||
|
||||
self.session.mercury.send(MercuryRequest{
|
||||
method: MercuryMethod::SUB,
|
||||
uri: format!("hm://remote/user/{}/v23", self.username).to_string(),
|
||||
uri: format!("hm://remote/user/{}/v23", self.username),
|
||||
content_type: None,
|
||||
callback: Some(tx),
|
||||
payload: Vec::new()
|
||||
|
@ -148,23 +235,22 @@ impl SpircManager {
|
|||
|
||||
self.notify(None);
|
||||
|
||||
for pkt in rx.iter() {
|
||||
let frame : protocol::spirc::Frame =
|
||||
protobuf::parse_from_bytes(pkt.payload.front().unwrap()).unwrap();
|
||||
let rx = rx.into_iter().map(|pkt| {
|
||||
protobuf::parse_from_bytes::<protocol::spirc::Frame>(pkt.payload.front().unwrap()).unwrap()
|
||||
});
|
||||
|
||||
println!("{:?} {} {} {}",
|
||||
for frame in rx {
|
||||
println!("{:?} {} {} {} {}",
|
||||
frame.get_typ(),
|
||||
frame.get_device_state().get_name(),
|
||||
frame.get_ident(),
|
||||
frame.get_device_state().get_became_active_at());
|
||||
|
||||
if frame.get_ident() == self.ident ||
|
||||
(frame.get_recipient().len() > 0 &&
|
||||
!frame.get_recipient().contains(&self.ident)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.handle(frame);
|
||||
frame.get_seq_nr(),
|
||||
frame.get_state_update_id());
|
||||
if frame.get_ident() != self.ident &&
|
||||
(frame.get_recipient().len() == 0 ||
|
||||
frame.get_recipient().contains(&self.ident)) {
|
||||
self.handle(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,37 +261,79 @@ impl SpircManager {
|
|||
}
|
||||
protocol::spirc::MessageType::kMessageTypeLoad => {
|
||||
self.is_active = true;
|
||||
self.became_active_at = {
|
||||
let ts = time::now_utc().to_timespec();
|
||||
ts.sec * 1000 + ts.nsec as i64 / 1000000
|
||||
};
|
||||
println!("{:?} {}", frame, self.became_active_at);
|
||||
self.notify(None)
|
||||
self.became_active_at = SpircManager::now();
|
||||
|
||||
self.state.import(frame.get_state());
|
||||
|
||||
self.state.last_command_ident = frame.get_ident().to_string();
|
||||
self.state.last_command_msgid = frame.get_seq_nr();
|
||||
|
||||
self.state_update_id = SpircManager::now();
|
||||
self.notify(None);
|
||||
}
|
||||
protocol::spirc::MessageType::kMessageTypePlay => {
|
||||
self.state.status = PlayStatus::kPlayStatusPlay;
|
||||
self.state.position_measured_at = SpircManager::now();
|
||||
|
||||
self.state.last_command_ident = frame.get_ident().to_string();
|
||||
self.state.last_command_msgid = frame.get_seq_nr();
|
||||
|
||||
self.state_update_id = SpircManager::now();
|
||||
self.notify(None);
|
||||
}
|
||||
protocol::spirc::MessageType::kMessageTypePause => {
|
||||
self.state.status = PlayStatus::kPlayStatusPause;
|
||||
self.state.position_measured_at = SpircManager::now();
|
||||
|
||||
self.state.last_command_ident = frame.get_ident().to_string();
|
||||
self.state.last_command_msgid = frame.get_seq_nr();
|
||||
|
||||
self.state_update_id = SpircManager::now();
|
||||
self.notify(None);
|
||||
}
|
||||
protocol::spirc::MessageType::kMessageTypeSeek => {
|
||||
self.state.position_ms = frame.get_position();
|
||||
self.state.position_measured_at = SpircManager::now();
|
||||
|
||||
self.state.last_command_ident = frame.get_ident().to_string();
|
||||
self.state.last_command_msgid = frame.get_seq_nr();
|
||||
|
||||
self.state_update_id = SpircManager::now();
|
||||
self.notify(None);
|
||||
}
|
||||
protocol::spirc::MessageType::kMessageTypeNotify => {
|
||||
if frame.get_device_state().get_is_active() {
|
||||
//println!("{:?}", frame.get_state());
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn notify(&mut self, recipient: Option<&str>) {
|
||||
let device_state = self.device_state();
|
||||
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
|
||||
version: 1,
|
||||
ident: self.ident.clone(),
|
||||
protocol_version: "2.0.0".to_string(),
|
||||
seq_nr: { self.seq_nr += 1; self.seq_nr },
|
||||
typ: protocol::spirc::MessageType::kMessageTypeNotify,
|
||||
device_state: self.device_state(),
|
||||
recipient: protobuf::RepeatedField::from_vec(
|
||||
recipient.map(|r| vec![r.to_string()] ).unwrap_or(vec![])
|
||||
),
|
||||
state_update_id: self.state_update_id
|
||||
});
|
||||
|
||||
if self.is_active {
|
||||
pkt.set_state(self.state.export());
|
||||
}
|
||||
|
||||
self.session.mercury.send(MercuryRequest{
|
||||
method: MercuryMethod::SEND,
|
||||
uri: format!("hm://remote/user/{}", self.username).to_string(),
|
||||
uri: format!("hm://remote/user/{}", self.username),
|
||||
content_type: None,
|
||||
callback: None,
|
||||
payload: vec![
|
||||
protobuf_init!(protocol::spirc::Frame::new(), {
|
||||
version: 1,
|
||||
ident: self.ident.clone(),
|
||||
protocol_version: "2.0.0".to_string(),
|
||||
seq_nr: { self.seq_nr += 1; self.seq_nr },
|
||||
typ: protocol::spirc::MessageType::kMessageTypeNotify,
|
||||
device_state: device_state,
|
||||
recipient: protobuf::RepeatedField::from_vec(
|
||||
recipient.map(|r| vec![r.to_string()] ).unwrap_or(vec![])
|
||||
)
|
||||
}).write_to_bytes().unwrap()
|
||||
]
|
||||
payload: vec![ pkt.write_to_bytes().unwrap() ]
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
|
@ -268,5 +396,10 @@ impl SpircManager {
|
|||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn now() -> i64 {
|
||||
let ts = time::now_utc().to_timespec();
|
||||
ts.sec * 1000 + ts.nsec as i64 / 1000000
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue