diff --git a/crabidy-server/armv7-unknown-linux-gnueabihf-Dockerfile b/crabidy-server/armv7-unknown-linux-gnueabihf-Dockerfile new file mode 100644 index 0000000..2a7af95 --- /dev/null +++ b/crabidy-server/armv7-unknown-linux-gnueabihf-Dockerfile @@ -0,0 +1,5 @@ +FROM ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:edge +RUN dpkg --add-architecture armhf +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y alsa:armhf librust-alsa-sys-dev:armhf libasound2-dev:armhf portaudio19-dev:armhf build-essential libpulse-dev:armhf libdbus-1-dev:armhf pkg-config apt-utils unzip +RUN curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v23.2/protoc-23.2-linux-x86_64.zip && unzip protoc-23.2-linux-x86_64.zip diff --git a/crabidy-server/src/lib.rs b/crabidy-server/src/lib.rs new file mode 100644 index 0000000..e991e83 --- /dev/null +++ b/crabidy-server/src/lib.rs @@ -0,0 +1,237 @@ +use crabidy_core::proto::crabidy::{Queue, Track}; +use rand::{seq::SliceRandom, thread_rng}; +use std::time::SystemTime; +use tracing::debug; + +#[derive(Clone)] +pub struct QueueManager { + created_at: SystemTime, + current_offset: usize, + play_order: Vec, + tracks: Vec, + pub repeat: bool, + pub shuffle: bool, +} + +impl From for Queue { + fn from(queue_manager: QueueManager) -> Self { + Self { + timestamp: queue_manager.created_at.elapsed().unwrap().as_secs(), + current_position: queue_manager.current_position() as u32, + tracks: queue_manager.tracks, + } + } +} + +impl QueueManager { + pub fn new() -> Self { + Self { + created_at: SystemTime::now(), + current_offset: 0, + play_order: Vec::new(), + tracks: Vec::new(), + repeat: false, + shuffle: false, + } + } + pub fn current_position(&self) -> usize { + if self.current_offset < self.play_order.len() { + self.play_order[self.current_offset] + } else { + 0 + } + } + + pub fn shuffle_on(&mut self) { + self.shuffle = true; + self.shuffle_before(self.current_offset); + self.shuffle_behind(self.current_offset); + } + + pub fn shuffle_off(&mut self) { + self.shuffle = false; + self.play_order = (0..self.tracks.len()).collect(); + } + + pub fn shuffle_all(&mut self) { + self.play_order.shuffle(&mut thread_rng()); + } + + pub fn shuffle_before(&mut self, pos: usize) { + self.play_order[..pos].shuffle(&mut thread_rng()); + } + + pub fn shuffle_behind(&mut self, pos: usize) { + self.play_order[pos + 1..].shuffle(&mut thread_rng()); + } + + pub fn current_track(&self) -> Option { + if self.current_position() < self.tracks.len() { + Some(self.tracks[self.current_position()].clone()) + } else { + None + } + } + + pub fn next_track(&mut self) -> Option { + let len = self.tracks.len(); + if self.current_offset < len - 1 { + self.current_offset += 1; + let current_pos = self.current_position(); + if current_pos < len { + Some(self.tracks[current_pos].clone()) + } else { + None + } + } else { + debug!("no more tracks"); + if self.repeat { + debug!("repeat"); + self.current_offset = 0; + if self.shuffle { + self.shuffle_all(); + } + return self.current_track(); + } + None + } + } + + pub fn prev_track(&mut self) -> Option { + if 0 < self.current_offset { + self.current_offset -= 1; + Some(self.tracks[self.current_position()].clone()) + } else { + None + } + } + + pub fn set_current_position(&mut self, current_position: u32) -> bool { + if current_position < self.tracks.len() as u32 { + if self.shuffle { + self.shuffle_all(); + } + let current_offset = self + .play_order + .iter() + .position(|&i| i == current_position as usize) + .unwrap(); + if self.shuffle { + self.play_order.swap(0, current_offset); + self.current_offset = 0; + } else { + self.current_offset = current_offset; + } + true + } else { + false + } + } + + pub fn replace_with_tracks(&mut self, tracks: &[Track]) -> Option { + self.current_offset = 0; + self.tracks = tracks.to_vec(); + self.play_order = (0..self.tracks.len()).collect(); + if self.shuffle { + self.shuffle_all(); + } + if 0 < self.tracks.len() as u32 { + Some(self.tracks[self.current_position()].clone()) + } else { + None + } + } + + pub fn append_tracks(&mut self, tracks: &[Track]) { + let len = self.tracks.len(); + let order_additions: Vec = (len..len + tracks.len()).collect(); + self.play_order.extend(order_additions); + self.tracks.extend(tracks.iter().cloned()); + if self.shuffle { + self.shuffle_behind(self.current_offset); + } + } + + pub fn queue_tracks(&mut self, tracks: &[Track]) { + let len = self.tracks.len(); + if len == 0 { + self.replace_with_tracks(tracks); + return; + } + let pos = self.current_position(); + let order_additions: Vec = (len..len + tracks.len()).collect(); + self.play_order.extend(order_additions); + let tail: Vec = self + .tracks + .splice((self.current_position() + 1).., tracks.to_vec()) + .collect(); + self.tracks.extend(tail); + self.play_order + .iter_mut() + .filter(|i| (pos as usize) < **i) + .for_each(|i| *i += len); + if self.shuffle { + self.shuffle_behind(self.current_offset); + } + } + + pub fn remove_tracks(&mut self, positions: &[u32]) -> Option { + let mut play_next = false; + for pos in positions { + if (self.tracks.len() as u32) < *pos { + return None; + }; + if *pos == self.current_position() as u32 { + play_next = true; + } + let offset = self + .play_order + .iter() + .position(|&i| i == *pos as usize) + .unwrap(); + if offset < self.current_offset { + self.current_offset -= 1; + } + self.tracks.remove(*pos as usize); + self.play_order.remove(offset); + self.play_order + .iter_mut() + .filter(|i| (*pos as usize) < **i) + .for_each(|i| *i -= 1); + } + if play_next { + self.current_track() + } else { + None + } + } + + pub fn insert_tracks(&mut self, position: u32, tracks: &[Track]) { + let len = self.tracks.len(); + let order_additions: Vec = (len..len + tracks.len()).collect(); + self.play_order.extend(order_additions); + let tail: Vec = self + .tracks + .splice((position as usize + 1).., tracks.to_vec()) + .collect(); + self.tracks.extend(tail); + if self.shuffle { + self.shuffle_behind(self.current_offset); + } + } +} + +#[cfg(test)] + +mod tests { + use super::*; + + #[test] + fn random_delete_before() {} + #[test] + fn random_delete_track() {} + #[test] + fn random_delete_after() {} + #[test] + fn random_select_track() {} +}