Initial commit
This commit is contained in:
commit
8293c6e6e5
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
result
|
||||
result-*
|
65
Cargo.lock
generated
Normal file
65
Cargo.lock
generated
Normal 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
7
Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "empidee"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0.210"
|
3
examples/mpd-client/main.rs
Normal file
3
examples/mpd-client/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
todo!()
|
||||
}
|
48
flake.lock
generated
Normal file
48
flake.lock
generated
Normal 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
45
flake.nix
Normal 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
77
src/common.rs
Normal 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 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),
|
||||
}
|
11
src/lib.rs
Normal file
11
src/lib.rs
Normal 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
302
src/request.rs
Normal 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 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),
|
||||
}
|
||||
|
||||
#[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
5
src/response.rs
Normal 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),
|
||||
}
|
Loading…
Reference in New Issue
Block a user