diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index be0a8b80..605a02b0 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -120,6 +120,7 @@ pub enum SpircCommand { Shutdown, Shuffle(bool), Repeat(bool), + RepeatOne(bool), Disconnect, SetPosition(u32), SetVolume(u16), @@ -134,6 +135,7 @@ pub struct SpircLoadCommand { pub start_playing: bool, pub shuffle: bool, pub repeat: bool, + pub repeat_one: bool, pub playing_track_index: u32, pub tracks: Vec, } @@ -149,6 +151,7 @@ impl From for State { }); state.set_shuffle(command.shuffle); state.set_repeat(command.repeat); + state.set_repeat_one(command.repeat_one); state.set_playing_track_index(command.playing_track_index); state.track = command.tracks; state @@ -168,6 +171,7 @@ pub struct Spirc { fn initial_state() -> State { let mut frame = protocol::spirc::State::new(); frame.set_repeat(false); + frame.set_repeat_one(false); frame.set_shuffle(false); frame.set_status(PlayStatus::kPlayStatusStop); frame.set_position_ms(0); @@ -430,6 +434,9 @@ impl Spirc { pub fn repeat(&self, repeat: bool) -> Result<(), Error> { Ok(self.commands.send(SpircCommand::Repeat(repeat))?) } + pub fn repeat_one(&self, repeat_one: bool) -> Result<(), Error> { + Ok(self.commands.send(SpircCommand::RepeatOne(repeat_one))?) + } pub fn set_volume(&self, volume: u16) -> Result<(), Error> { Ok(self.commands.send(SpircCommand::SetVolume(volume))?) } @@ -634,6 +641,10 @@ impl SpircTask { self.state.set_repeat(repeat); self.notify(None) } + SpircCommand::RepeatOne(repeat_one) => { + self.state.set_repeat_one(repeat_one); + self.notify(None) + } SpircCommand::SetPosition(position) => { self.handle_seek(position); self.notify(None) @@ -930,6 +941,22 @@ impl SpircTask { self.notify(None) } + MessageType::kMessageTypeRepeatOne => { + let repeat_one = update.state.repeat_one(); + if repeat_one && !self.state.repeat() { + self.state.set_repeat(true); + self.player.emit_repeat_changed_event(true); + } else if !repeat_one && self.state.repeat() { + self.state.set_repeat(false); + self.player.emit_repeat_changed_event(false); + } + self.state.set_repeat_one(repeat_one); + + self.player.emit_repeat_one_changed_event(repeat_one); + + self.notify(None) + } + MessageType::kMessageTypeShuffle => { let shuffle = update.state.shuffle(); self.state.set_shuffle(shuffle); diff --git a/contrib/event_handler_example.py b/contrib/event_handler_example.py index f419e7d6..fd520ad2 100644 --- a/contrib/event_handler_example.py +++ b/contrib/event_handler_example.py @@ -26,6 +26,9 @@ elif player_event == 'shuffle_changed': elif player_event == 'repeat_changed': json_dict['repeat'] = os.environ['REPEAT'] +elif player_event == 'repeat_one_changed': + json_dict['repeat_one'] = os.environ['REPEAT_ONE'] + elif player_event == 'auto_play_changed': json_dict['auto_play'] = os.environ['AUTO_PLAY'] diff --git a/playback/src/player.rs b/playback/src/player.rs index 16275053..3d1b9141 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -127,6 +127,7 @@ enum PlayerCommand { EmitFilterExplicitContentChangedEvent(bool), EmitShuffleChangedEvent(bool), EmitRepeatChangedEvent(bool), + EmitRepeatOneChangedEvent(bool), EmitAutoPlayChangedEvent(bool), } @@ -223,6 +224,9 @@ pub enum PlayerEvent { RepeatChanged { repeat: bool, }, + RepeatOneChanged { + repeat_one: bool, + }, AutoPlayChanged { auto_play: bool, }, @@ -481,7 +485,6 @@ impl Player { player_id, play_request_id_generator: SeqGenerator::new(0), }; - // While PlayerInternal is written as a future, it still contains blocking code. // It must be run by using block_on() in a dedicated thread. let runtime = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime"); @@ -614,6 +617,10 @@ impl Player { self.command(PlayerCommand::EmitRepeatChangedEvent(repeat)); } + pub fn emit_repeat_one_changed_event(&self, repeat_one: bool) { + self.command(PlayerCommand::EmitRepeatOneChangedEvent(repeat_one)); + } + pub fn emit_auto_play_changed_event(&self, auto_play: bool) { self.command(PlayerCommand::EmitAutoPlayChangedEvent(auto_play)); } @@ -2338,6 +2345,10 @@ impl fmt::Debug for PlayerCommand { .debug_tuple("EmitRepeatChangedEvent") .field(&repeat) .finish(), + PlayerCommand::EmitRepeatOneChangedEvent(repeat_one) => f + .debug_tuple("EmitRepeatOneChangedEvent") + .field(&repeat_one) + .finish(), PlayerCommand::EmitAutoPlayChangedEvent(auto_play) => f .debug_tuple("EmitAutoPlayChangedEvent") .field(&auto_play) diff --git a/protocol/proto/spirc.proto b/protocol/proto/spirc.proto index acaeae1f..b07a0bbf 100644 --- a/protocol/proto/spirc.proto +++ b/protocol/proto/spirc.proto @@ -33,6 +33,7 @@ enum MessageType { kMessageTypeVolume = 0x1b; kMessageTypeShuffle = 0x1c; kMessageTypeRepeat = 0x1d; + kMessageTypeRepeatOne = 0x1e; kMessageTypeVolumeDown = 0x1f; kMessageTypeVolumeUp = 0x20; kMessageTypeReplace = 0x21; @@ -92,6 +93,7 @@ message State { optional string context_description = 0x8; optional bool shuffle = 0xd; optional bool repeat = 0xe; + optional bool repeat_one = 0xf; optional string last_command_ident = 0x14; optional uint32 last_command_msgid = 0x15; optional bool playing_from_fallback = 0x18;