Initial commit

This commit is contained in:
Oystein Kristoffer Tveit 2024-11-05 22:47:35 +01:00
commit 8293c6e6e5
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
10 changed files with 566 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
result
result-*

65
Cargo.lock generated Normal file
View File

@ -0,0 +1,65 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "empidee"
version = "0.1.0"
dependencies = [
"serde",
]
[[package]]
name = "proc-macro2"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"

7
Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "empidee"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = "1.0.210"

View File

@ -0,0 +1,3 @@
fn main() {
todo!()
}

48
flake.lock generated Normal file
View File

@ -0,0 +1,48 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1729256560,
"narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1729477859,
"narHash": "sha256-r0VyeJxy4O4CgTB/PNtfQft9fPfN1VuGvnZiCxDArvg=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "ada8266712449c4c0e6ee6fcbc442b3c217c79e1",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

45
flake.nix Normal file
View File

@ -0,0 +1,45 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, rust-overlay }:
let
inherit (nixpkgs) lib;
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
"armv7l-linux"
];
forAllSystems = f: lib.genAttrs systems (system: let
pkgs = import nixpkgs {
inherit system;
overlays = [
(import rust-overlay)
];
};
rust-bin = rust-overlay.lib.mkRustBin { } pkgs.buildPackages;
toolchain = rust-bin.stable.latest.default.override {
extensions = [ "rust-src" "rust-analyzer" "rust-std" ];
};
in f system pkgs toolchain);
in {
devShells = forAllSystems (system: pkgs: toolchain: {
default = pkgs.mkShell {
nativeBuildInputs = [
toolchain
];
RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library";
};
});
};
}

77
src/common.rs Normal file
View File

@ -0,0 +1,77 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) 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 songs release date. This is usually a 4-digit year.
Date(String),
/// The songs 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),
}

11
src/lib.rs Normal file
View File

@ -0,0 +1,11 @@
///! This library contains structs and parsing for the mpd protocol
///! as described in https://mpd.readthedocs.io/en/latest/protocol.html#protocol-overview
///!
///! It does not provide any client or server implementation
mod common;
mod request;
mod response;
pub use request::Request;
pub use response::Response;

302
src/request.rs Normal file
View File

@ -0,0 +1,302 @@
type SongPosition = u32;
type SongId = u32;
type Seconds = u32;
type TimeWithFractions = f64;
type OneOrRange = (SongPosition, Option<SongPosition>);
type WindowRange = (Option<SongPosition>, Option<SongPosition>);
type Priority = u8;
type PlaylistName = String;
type Offset = u32;
// TODO: use a proper types
type TagName = String;
type TagValue = String;
type Uri = String;
type Path = String;
type Filter = String;
type Sort = String;
type Version = String;
type Tag = String;
type Feature = String;
type PartitionName = String;
type AudioOutputId = String;
type ChannelName = String;
type StickerType = String;
#[derive(Debug, Clone, PartialEq)]
pub enum Request {
// -- Query Commands -- //
ClearError,
CurrentSong,
Idle(Option<Vec<SubSystem>>),
Status,
Stats,
// -- Playback Commands -- //
Consume(ConsumeState),
Crossfade(Seconds),
MixRampDb(f32),
MixRampDelay(Seconds),
Random(bool),
Repeat(bool),
SetVol(Volume),
GetVol,
Single(SingleState),
ReplayGainMode(ReplayGainMode),
ReplayGainStatus,
Volume(Volume),
// -- Playback Control Commands -- //
Next,
Pause(Option<bool>),
Play(SongPosition),
PlayId(SongId),
Previous,
Seek(SongPosition, TimeWithFractions),
SeekId(SongId, TimeWithFractions),
SeekCur(SeekMode, TimeWithFractions),
Stop,
// -- Queue Commands -- //
// TODO: relative mode
Add(String, Option<SongPosition>),
// TODO: relative mode
AddId(String, Option<SongPosition>),
Clear,
Delete(OneOrRange),
DeleteId(SongId),
Move(OneOrRange, SongPosition),
MoveId(SongId, SongPosition),
Playlist,
PlaylistFind(Filter, Option<Sort>, Option<WindowRange>),
PlaylistId(SongId),
PlaylistInfo(OneOrRange),
PlaylistSearch(Filter, Option<Sort>, Option<WindowRange>),
// TODO: which type of range?
PlChanges(Version, Option<WindowRange>),
// TODO: which type of range?
PlChangesPosId(Version, Option<WindowRange>),
// TODO: which type of range?
Prio(Priority, WindowRange),
PrioId(Priority, Vec<SongId>),
RangeId(SongId, WindowRange),
Shuffle(Option<OneOrRange>),
Swap(SongPosition, SongPosition),
SwapId(SongId, SongId),
AddTagId(SongId, TagName, TagValue),
ClearTagId(SongId, TagName),
// -- Stored Playlist Commands -- //
ListPlaylist(PlaylistName, Option<WindowRange>),
ListPlaylistInfo(PlaylistName, Option<WindowRange>),
SearchPlaylist(PlaylistName, Filter, Option<WindowRange>),
ListPlaylists,
Load(PlaylistName, Option<WindowRange>, SongPosition),
PlaylistAdd(PlaylistName, Uri, SongPosition),
PlaylistClear(PlaylistName),
PlaylistDelete(PlaylistName, OneOrRange),
PlaylistLength(PlaylistName),
// TODO: which type of range?
PlaylistMove(PlaylistName, OneOrRange, SongPosition),
Rename(PlaylistName, PlaylistName),
Rm(PlaylistName),
Save(PlaylistName, Option<SaveMode>),
// -- Music Database Commands -- //
AlbumArt(Uri, Offset),
Count(Filter, Option<GroupType>),
GetFingerprint(Uri),
Find(Filter, Option<Sort>, Option<WindowRange>),
FindAdd(Filter, Option<Sort>, Option<WindowRange>, Option<SongPosition>),
List(Tag, Filter, Option<GroupType>),
#[deprecated]
ListAll(Option<Uri>),
#[deprecated]
ListAllInfo(Option<Uri>),
ListFiles(Uri),
LsInfo(Option<Uri>),
ReadComments(Uri),
ReadPicture(Uri, Offset),
Search(Filter, Option<Sort>, Option<WindowRange>),
SearchAdd(Filter, Option<Sort>, Option<WindowRange>, Option<SongPosition>),
SearchAddPl(Filter, Option<Sort>, Option<WindowRange>, Option<SongPosition>),
SearchCount(Filter, Option<GroupType>),
Update(Option<Uri>),
Rescan(Option<Uri>),
// -- Mount and Neighbor Commands -- //
Mount(Option<Path>, Option<Uri>),
Unmount(Path),
ListMounts,
ListNeighbors,
// -- Sticker Commands -- //
StickerGet(StickerType, Uri, String),
StickerSet(StickerType, Uri, String, String),
StickerDelete(StickerType, Uri, String),
StickerList(StickerType, Uri),
StickerFind(StickerType, Uri, String, Option<Sort>, Option<WindowRange>),
StickerFindValue(StickerType, Uri, String, String, Option<Sort>, Option<WindowRange>),
StickerNames,
StickerTypes,
StickerNamesTypes(Option<StickerType>),
// -- Connection Commands -- //
Close,
Kill,
Password(String),
Ping,
BinaryLimit(u64),
TagTypes,
TagTypesDisable(Vec<Tag>),
TagTypesEnable(Vec<Tag>),
TagTypesClear,
TagTypesAll,
TagTypesAvailable,
TagTypesReset(Vec<Tag>),
Protocol,
ProtocolDisable(Vec<Feature>),
ProtocolEnable(Vec<Feature>),
ProtocolClear,
ProtocolAll,
ProtocolAvailable,
// -- Partition Commands -- //
Partition(PartitionName),
ListPartitions,
NewPartition(PartitionName),
DelPartition(PartitionName),
MoveOutput(String),
// -- Audio Output Commands -- //
DisableOutput(AudioOutputId),
EnableOutput(AudioOutputId),
ToggleOutput(AudioOutputId),
Outputs,
OutputSet(AudioOutputId, String, String),
// -- Reflection Commands -- //
Config,
Commands,
NotCommands,
UrlHandlers,
Decoders,
// -- Client to Client Commands -- //
Subscribe(ChannelName),
Unsubscribe(ChannelName),
Channels,
ReadMessages,
SendMessage(ChannelName, String),
}
impl Into<Vec<u8>> for Request {
fn into(self) -> Vec<u8> {
todo!()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SaveMode {
Create,
Append,
Replace,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SeekMode {
Relative,
RelativeReverse,
Absolute,
}
#[derive(Debug, Clone, PartialEq, Eq)]
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 clients 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),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConsumeState {
On,
Off,
Oneshot,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SingleState {
On,
Off,
Oneshot,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ReplayGainMode {
Off,
Track,
Album,
Auto,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Volume(u32);
impl Volume {
pub fn new(volume: u32) -> Result<Self, ()> {
match volume {
0..=100 => Ok(Self(volume)),
_ => Err(()),
}
}
}
impl Into<u32> for Volume {
fn into(self) -> u32 {
self.0
}
}
// TODO: fill out
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GroupType {
Artist,
Album,
AlbumArtist,
Date,
Genre,
Track,
Composer,
Performer,
Conductor,
Comment,
Disc,
Filename,
Any,
}

5
src/response.rs Normal file
View File

@ -0,0 +1,5 @@
// See https://github.com/MusicPlayerDaemon/MPD/blob/7774c3369e1484dc5dec6d7d9572e0a57e9c5302/src/command/AllCommands.cxx#L67-L209
pub enum Response {
Ok,
GenericError(String),
}