mirror of
https://github.com/Dummi26/musicdb.git
synced 2025-12-14 11:56:16 +01:00
Added song duration support
This commit is contained in:
@@ -359,6 +359,11 @@ impl Database {
|
||||
Command::RemoveArtist(artist) => {
|
||||
_ = self.remove_artist(artist);
|
||||
}
|
||||
Command::SetSongDuration(id, duration) => {
|
||||
if let Some(song) = self.get_song_mut(&id) {
|
||||
song.duration_millis = duration;
|
||||
}
|
||||
}
|
||||
Command::InitComplete => {
|
||||
self.client_is_init = true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::{collections::VecDeque, ops::AddAssign};
|
||||
|
||||
use rand::seq::{IteratorRandom, SliceRandom};
|
||||
|
||||
@@ -98,6 +98,60 @@ impl Queue {
|
||||
QueueContent::Shuffle { inner, state: _ } => inner.len(),
|
||||
}
|
||||
}
|
||||
pub fn duration_total(&self, db: &Database) -> QueueDuration {
|
||||
let mut dur = QueueDuration::new_total();
|
||||
self.add_duration(&mut dur, db);
|
||||
dur
|
||||
}
|
||||
// remaining time, including current song
|
||||
pub fn duration_remaining(&self, db: &Database) -> QueueDuration {
|
||||
let mut dur = QueueDuration::new_remaining();
|
||||
self.add_duration(&mut dur, db);
|
||||
dur
|
||||
}
|
||||
pub fn add_duration(&self, dur: &mut QueueDuration, db: &Database) {
|
||||
if self.enabled {
|
||||
match &self.content {
|
||||
QueueContent::Song(v) => {
|
||||
dur.millis += db.get_song(v).map(|s| s.duration_millis).unwrap_or(0)
|
||||
}
|
||||
QueueContent::Folder(c, inner, _) => {
|
||||
for (i, inner) in inner.iter().enumerate() {
|
||||
if dur.include_past || i >= *c {
|
||||
inner.add_duration(dur, db);
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(total, done, inner) => {
|
||||
if *total == 0 {
|
||||
dur.infinite = true;
|
||||
} else if dur.include_past {
|
||||
// <total duration> * <total iterations>
|
||||
let dt = inner.duration_total(db);
|
||||
for _ in 0..*total {
|
||||
*dur += dt;
|
||||
}
|
||||
} else {
|
||||
// <remaining duration> + <total duration> * <remaining iterations>
|
||||
inner.add_duration(dur, db);
|
||||
let dt = inner.duration_total(db);
|
||||
for _ in 0..(total.saturating_sub(*done + 1)) {
|
||||
*dur += dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueContent::Random(q) => {
|
||||
if let Some(el) = q.iter().next() {
|
||||
dur.random_known_millis += el.duration_total(db).millis;
|
||||
}
|
||||
dur.random_counter += 1;
|
||||
}
|
||||
QueueContent::Shuffle { inner, state: _ } => {
|
||||
inner.add_duration(dur, db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// recursively descends the queue until the current active element is found, then returns it.
|
||||
pub fn get_current(&self) -> Option<&Self> {
|
||||
@@ -641,3 +695,42 @@ impl ToFromBytes for ShuffleState {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct QueueDuration {
|
||||
pub include_past: bool,
|
||||
pub infinite: bool,
|
||||
/// number of milliseconds (that we know of)
|
||||
pub millis: u64,
|
||||
/// number of milliseconds from the <random> element - only accurate the first time it is reached in queue.
|
||||
pub random_known_millis: u64,
|
||||
/// number of <random> elements, which could have pretty much any duration.
|
||||
pub random_counter: u64,
|
||||
}
|
||||
impl QueueDuration {
|
||||
fn new_total() -> Self {
|
||||
Self::new(true)
|
||||
}
|
||||
fn new_remaining() -> Self {
|
||||
Self::new(false)
|
||||
}
|
||||
fn new(include_past: bool) -> Self {
|
||||
QueueDuration {
|
||||
include_past,
|
||||
infinite: false,
|
||||
millis: 0,
|
||||
random_known_millis: 0,
|
||||
random_counter: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AddAssign<QueueDuration> for QueueDuration {
|
||||
fn add_assign(&mut self, rhs: QueueDuration) {
|
||||
if rhs.infinite {
|
||||
self.infinite = true;
|
||||
}
|
||||
self.millis += rhs.millis;
|
||||
self.random_known_millis += rhs.random_known_millis;
|
||||
self.random_counter += rhs.random_counter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ pub struct Song {
|
||||
pub artist: ArtistId,
|
||||
pub more_artists: Vec<ArtistId>,
|
||||
pub cover: Option<CoverId>,
|
||||
pub file_size: u64,
|
||||
/// song duration in milliseconds
|
||||
pub duration_millis: u64,
|
||||
pub general: GeneralData,
|
||||
/// None => No cached data
|
||||
/// Some(Err) => No cached data yet, but a thread is working on loading it.
|
||||
@@ -36,6 +39,8 @@ impl Song {
|
||||
artist: ArtistId,
|
||||
more_artists: Vec<ArtistId>,
|
||||
cover: Option<CoverId>,
|
||||
file_size: u64,
|
||||
duration_millis: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
@@ -45,6 +50,8 @@ impl Song {
|
||||
artist,
|
||||
more_artists,
|
||||
cover,
|
||||
file_size,
|
||||
duration_millis,
|
||||
general: GeneralData::default(),
|
||||
cached_data: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
@@ -185,6 +192,8 @@ impl ToFromBytes for Song {
|
||||
self.artist.to_bytes(s)?;
|
||||
self.more_artists.to_bytes(s)?;
|
||||
self.cover.to_bytes(s)?;
|
||||
self.file_size.to_bytes(s)?;
|
||||
self.duration_millis.to_bytes(s)?;
|
||||
self.general.to_bytes(s)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -200,6 +209,8 @@ impl ToFromBytes for Song {
|
||||
artist: ToFromBytes::from_bytes(s)?,
|
||||
more_artists: ToFromBytes::from_bytes(s)?,
|
||||
cover: ToFromBytes::from_bytes(s)?,
|
||||
file_size: ToFromBytes::from_bytes(s)?,
|
||||
duration_millis: ToFromBytes::from_bytes(s)?,
|
||||
general: ToFromBytes::from_bytes(s)?,
|
||||
cached_data: Arc::new(Mutex::new(None)),
|
||||
})
|
||||
|
||||
@@ -49,6 +49,7 @@ pub enum Command {
|
||||
RemoveAlbum(AlbumId),
|
||||
RemoveArtist(ArtistId),
|
||||
ModifyArtist(Artist),
|
||||
SetSongDuration(SongId, u64),
|
||||
InitComplete,
|
||||
ErrorInfo(String, String),
|
||||
}
|
||||
@@ -102,7 +103,7 @@ pub fn run_server(
|
||||
let command_sender = command_sender.clone();
|
||||
let db = Arc::clone(&database);
|
||||
thread::spawn(move || loop {
|
||||
if let Ok((connection, con_addr)) = v.accept() {
|
||||
if let Ok((connection, _con_addr)) = v.accept() {
|
||||
let command_sender = command_sender.clone();
|
||||
let db = Arc::clone(&db);
|
||||
thread::spawn(move || {
|
||||
@@ -275,6 +276,11 @@ impl ToFromBytes for Command {
|
||||
s.write_all(&[0b11011100])?;
|
||||
artist.to_bytes(s)?;
|
||||
}
|
||||
Self::SetSongDuration(i, d) => {
|
||||
s.write_all(&[0b11100000])?;
|
||||
i.to_bytes(s)?;
|
||||
d.to_bytes(s)?;
|
||||
}
|
||||
Self::InitComplete => {
|
||||
s.write_all(&[0b00110001])?;
|
||||
}
|
||||
@@ -326,6 +332,9 @@ impl ToFromBytes for Command {
|
||||
0b11010000 => Self::RemoveSong(ToFromBytes::from_bytes(s)?),
|
||||
0b11010011 => Self::RemoveAlbum(ToFromBytes::from_bytes(s)?),
|
||||
0b11011100 => Self::RemoveArtist(ToFromBytes::from_bytes(s)?),
|
||||
0b11100000 => {
|
||||
Self::SetSongDuration(ToFromBytes::from_bytes(s)?, ToFromBytes::from_bytes(s)?)
|
||||
}
|
||||
0b01011101 => Self::AddCover(ToFromBytes::from_bytes(s)?),
|
||||
0b00110001 => Self::InitComplete,
|
||||
0b11011011 => Self::ErrorInfo(ToFromBytes::from_bytes(s)?, ToFromBytes::from_bytes(s)?),
|
||||
|
||||
Reference in New Issue
Block a user