287 lines
9.4 KiB
Rust
287 lines
9.4 KiB
Rust
use std::str::FromStr;
|
||
|
||
use serde::{Deserialize, Serialize};
|
||
|
||
pub type SongPosition = u32;
|
||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
pub enum AbsouluteRelativeSongPosition {
|
||
Absolute(SongPosition),
|
||
RelativePlus(SongPosition),
|
||
RelativeMinus(SongPosition),
|
||
}
|
||
|
||
impl FromStr for AbsouluteRelativeSongPosition {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
Ok(match s {
|
||
s if s.starts_with('+') => Self::RelativePlus(s[1..].parse().map_err(|_| ())?),
|
||
s if s.starts_with('-') => Self::RelativeMinus(s[1..].parse().map_err(|_| ())?),
|
||
s => Self::Absolute(s.parse().map_err(|_| ())?),
|
||
})
|
||
}
|
||
}
|
||
|
||
pub type SongId = u32;
|
||
pub type Seconds = u32;
|
||
pub type TimeWithFractions = f64;
|
||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
pub enum OneOrRange {
|
||
One(SongPosition),
|
||
Range(SongPosition, SongPosition),
|
||
}
|
||
|
||
impl FromStr for OneOrRange {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
let mut parts = s.split(':');
|
||
let start = parts.next().ok_or(())?.parse().map_err(|_| ())?;
|
||
Ok(match parts.next() {
|
||
Some(end) => Self::Range(start, end.parse().map_err(|_| ())?),
|
||
None => Self::One(start),
|
||
})
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
pub struct WindowRange {
|
||
pub start: SongPosition,
|
||
pub end: Option<SongPosition>,
|
||
}
|
||
|
||
impl FromStr for WindowRange {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
let mut parts = s.split(':');
|
||
let start = parts.next().ok_or(())?.parse().map_err(|_| ())?;
|
||
let end = parts.next().map(|s| s.parse().map_err(|_| ()));
|
||
Ok(Self {
|
||
start,
|
||
end: end.transpose()?,
|
||
})
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
pub struct TimeInterval {
|
||
pub start: Option<TimeWithFractions>,
|
||
pub end: Option<TimeWithFractions>,
|
||
}
|
||
|
||
impl FromStr for TimeInterval {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
let mut parts = s.split(':');
|
||
let start = parts.next().map(|s| s.parse().map_err(|_| ()));
|
||
let end = parts.next().map(|s| s.parse().map_err(|_| ()));
|
||
Ok(Self {
|
||
start: start.transpose()?,
|
||
end: end.transpose()?,
|
||
})
|
||
}
|
||
}
|
||
|
||
pub type Priority = u8;
|
||
pub type PlaylistName = String;
|
||
pub type Offset = u32;
|
||
|
||
// TODO: use a proper types
|
||
pub type TagName = String;
|
||
pub type TagValue = String;
|
||
pub type Uri = String;
|
||
pub type Path = String;
|
||
pub type Sort = String;
|
||
pub type Version = String;
|
||
pub type Feature = String;
|
||
pub type PartitionName = String;
|
||
pub type AudioOutputId = String;
|
||
pub type ChannelName = String;
|
||
pub type StickerType = String;
|
||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum Tag {
|
||
/// The artist name. Its meaning is not well-defined; see “composer” and “performer” for more specific tags.
|
||
Artist(String),
|
||
/// Same as artist, but for sorting. This usually omits prefixes such as “The”.
|
||
ArtistSort(String),
|
||
/// The album name.
|
||
Album(String),
|
||
/// Same as album, but for sorting.
|
||
AlbumSort(String),
|
||
/// On multi-artist albums, this is the artist name which shall be used for the whole album. The exact meaning of this tag is not well-defined.
|
||
AlbumArtist(String),
|
||
/// Same as albumartist, but for sorting.
|
||
AlbumArtistSort(String),
|
||
/// The song title.
|
||
Title(String),
|
||
/// Same as title, but for sorting.
|
||
TitleSort(String),
|
||
/// The decimal track number within the album.
|
||
Track(String),
|
||
/// A name for this song. This is not the song title. The exact meaning of this tag is not well-defined. It is often used by badly configured internet radio stations with broken tags to squeeze both the artist name and the song title in one tag.
|
||
Name(String),
|
||
/// The music genre.
|
||
Genre(String),
|
||
/// The mood of the audio with a few keywords.
|
||
Mood(String),
|
||
/// The song's release date. This is usually a 4-digit year.
|
||
Date(String),
|
||
/// The song's original release date.
|
||
OriginalDate(String),
|
||
/// The artist who composed the song.
|
||
Composer(String),
|
||
/// Same as composer, but for sorting.
|
||
ComposerSort(String),
|
||
/// The artist who performed the song.
|
||
Performer(String),
|
||
/// The conductor who conducted the song.
|
||
Conductor(String),
|
||
/// “a work is a distinct intellectual or artistic creation, which can be expressed in the form of one or more audio recordings”
|
||
Work(String),
|
||
/// The ensemble performing this song, e.g. “Wiener Philharmoniker”.
|
||
Ensemble(String),
|
||
/// Name of the movement, e.g. “Andante con moto”.
|
||
Movement(String),
|
||
/// Movement number, e.g. “2” or “II”.
|
||
MovementNumber(String),
|
||
/// If this tag is set to “1” players supporting this tag will display the work, movement, and movementnumber` instead of the track title.
|
||
ShowMovement(String),
|
||
/// Location of the recording, e.g. “Royal Albert Hall”.
|
||
Location(String),
|
||
/// “used if the sound belongs to a larger category of sounds/music” (from the IDv2.4.0 TIT1 description).
|
||
Grouping(String),
|
||
/// A human-readable comment about this song. The exact meaning of this tag is not well-defined.
|
||
Comment(String),
|
||
/// The decimal disc number in a multi-disc album.
|
||
Disc(String),
|
||
/// The name of the label or publisher.
|
||
Label(String),
|
||
/// The artist id in the MusicBrainz database.
|
||
MusicBrainzArtistId(String),
|
||
/// The album id in the MusicBrainz database.
|
||
MusicBrainzAlbumId(String),
|
||
/// The album artist id in the MusicBrainz database.
|
||
MusicBrainzAlbumArtistId(String),
|
||
/// The track id in the MusicBrainz database.
|
||
MusicBrainzTrackId(String),
|
||
/// The release group id in the MusicBrainz database.
|
||
MusicBrainzReleaseGroupId(String),
|
||
/// The release track id in the MusicBrainz database.
|
||
MusicBrainzReleaseTrackId(String),
|
||
/// The work id in the MusicBrainz database.
|
||
MusicBrainzWorkId(String),
|
||
|
||
/// Other tags not covered by the above
|
||
Other(String, String),
|
||
}
|
||
|
||
/// These are different parts of the canonical MPD server.
|
||
/// They are mostly used in the protocol with the `idle` command,
|
||
/// signalling that the client is waiting for changes in any, one or multiple of these subsystems.
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum SubSystem {
|
||
/// The song database has been modified after update.
|
||
Database,
|
||
/// A database update has started or finished. If the database was modified during the update, the database event is also emitted.
|
||
Update,
|
||
/// A stored playlist has been modified, renamed, created or deleted
|
||
StoredPlaylist,
|
||
/// The queue (i.e. the current playlist) has been modified
|
||
Playlist,
|
||
/// The player has been started, stopped or seeked or tags of the currently playing song have changed (e.g. received from stream)
|
||
Player,
|
||
/// The volume has been changed
|
||
Mixer,
|
||
/// An audio output has been added, removed or modified (e.g. renamed, enabled or disabled)
|
||
Output,
|
||
/// Options like repeat, random, crossfade, replay gain
|
||
Options,
|
||
/// A partition was added, removed or changed
|
||
Partition,
|
||
/// The sticker database has been modified.
|
||
Sticker,
|
||
/// A client has subscribed or unsubscribed to a channel
|
||
Subscription,
|
||
/// A message was received on a channel this client is subscribed to; this event is only emitted when the client’s message queue is empty
|
||
Message,
|
||
/// A neighbor was found or lost
|
||
Neighbor,
|
||
/// The mount list has changed
|
||
Mount,
|
||
|
||
/// Other subsystems not covered by the above
|
||
Other(String),
|
||
}
|
||
|
||
impl FromStr for SubSystem {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
Ok(match s {
|
||
"database" => Self::Database,
|
||
"update" => Self::Update,
|
||
"stored_playlist" => Self::StoredPlaylist,
|
||
"playlist" => Self::Playlist,
|
||
"player" => Self::Player,
|
||
"mixer" => Self::Mixer,
|
||
"output" => Self::Output,
|
||
"options" => Self::Options,
|
||
"partition" => Self::Partition,
|
||
"sticker" => Self::Sticker,
|
||
"subscription" => Self::Subscription,
|
||
"message" => Self::Message,
|
||
"neighbor" => Self::Neighbor,
|
||
"mount" => Self::Mount,
|
||
other => Self::Other(other.to_string()),
|
||
})
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
pub struct Audio {
|
||
pub sample_rate: u64,
|
||
pub bits: u8,
|
||
pub channels: u8,
|
||
}
|
||
|
||
impl FromStr for Audio {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
let mut parts = s.split(':');
|
||
let sample_rate = parts.next().ok_or(())?.parse().map_err(|_| ())?;
|
||
let bits = u8::from_str_radix(parts.next().ok_or(())?, 16).map_err(|_| ())? + 1;
|
||
let channels = parts.next().ok_or(())?.parse().map_err(|_| ())?;
|
||
Ok(Self {
|
||
sample_rate,
|
||
bits,
|
||
channels,
|
||
})
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||
pub enum BoolOrOneshot {
|
||
True,
|
||
False,
|
||
Oneshot,
|
||
}
|
||
|
||
impl FromStr for BoolOrOneshot {
|
||
type Err = ();
|
||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
Ok(match s {
|
||
"0" => Self::False,
|
||
"1" => Self::True,
|
||
"oneshot" => Self::Oneshot,
|
||
_ => return Err(()),
|
||
})
|
||
}
|
||
}
|