Compare commits

..

2 commits

Author SHA1 Message Date
b8416b29dd
Split routes up into smaller modules 2023-07-13 00:37:36 +02:00
3900a5c5c0
Update dependencies 2023-07-13 00:37:30 +02:00
10 changed files with 323 additions and 292 deletions

170
Cargo.lock generated
View file

@ -117,7 +117,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "async-channel"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
dependencies = [
"concurrent-queue",
"event-listener",
@ -316,7 +316,7 @@ dependencies = [
"log",
"memchr",
"once_cell",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"pin-utils",
"slab",
"wasm-bindgen-futures",
@ -330,13 +330,13 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
[[package]]
name = "async-trait"
version = "0.1.68"
version = "0.1.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -371,9 +371,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "basic-toml"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1"
checksum = "f838d03a705d72b12389b8930bd14cacf493be1380bfb15720d4d12db5ab03ac"
dependencies = [
"serde",
]
@ -527,9 +527,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
@ -601,7 +601,7 @@ dependencies = [
"askama",
"askama_tide",
"async-std",
"infer 0.13.0",
"infer 0.15.0",
"percent-encoding",
"serde",
"serde_qs 0.12.0",
@ -613,9 +613,9 @@ dependencies = [
[[package]]
name = "erased-serde"
version = "0.3.25"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2b0c2380453a92ea8b6c8e5f64ecaafccddde8ceab55ff7a8ac1029f894569"
checksum = "f94c0e13118e7d7533271f754a168ae8400e6a1cc043f2bfd53cc7290f1a1de3"
dependencies = [
"serde",
]
@ -713,7 +713,7 @@ dependencies = [
"futures-io",
"memchr",
"parking",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"waker-fn",
]
@ -725,7 +725,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -743,7 +743,7 @@ dependencies = [
"futures-core",
"futures-macro",
"futures-task",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"pin-utils",
"slab",
]
@ -804,9 +804,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "hkdf"
@ -863,7 +863,7 @@ dependencies = [
"cookie",
"futures-lite",
"infer 0.2.3",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"rand 0.7.3",
"serde",
"serde_json",
@ -928,9 +928,9 @@ checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
[[package]]
name = "infer"
version = "0.13.0"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc"
checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199"
[[package]]
name = "instant"
@ -954,9 +954,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.6"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
[[package]]
name = "js-sys"
@ -984,9 +984,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.146"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libm"
@ -1083,22 +1083,22 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "pin-project"
version = "1.1.0"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.0"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -1109,9 +1109,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
[[package]]
name = "pin-utils"
@ -1131,7 +1131,7 @@ dependencies = [
"concurrent-queue",
"libc",
"log",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"windows-sys",
]
@ -1160,18 +1160,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
version = "1.0.63"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.28"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
dependencies = [
"proc-macro2",
]
@ -1264,9 +1264,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.37.20"
version = "0.37.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
dependencies = [
"bitflags",
"errno",
@ -1278,9 +1278,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.13"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
[[package]]
name = "semver"
@ -1299,22 +1299,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.164"
version = "1.0.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.164"
version = "1.0.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -1328,9 +1328,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.99"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed"
dependencies = [
"itoa",
"ryu",
@ -1521,15 +1521,15 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "sval"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2faba619276044eec7cd160d87b15d9191fb9b9f7198440343d2144f760cf08"
checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1"
[[package]]
name = "sval_buffer"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a353d3cca10721384077c9643c3fafdd6ed2600e57933b8e45c0b580d97b25af"
checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028"
dependencies = [
"sval",
"sval_ref",
@ -1537,18 +1537,18 @@ dependencies = [
[[package]]
name = "sval_dynamic"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee5fc7349e9f6cb2ab950046818f66ad3f2d7209ccc5dced93da19292a30273a"
checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf"
dependencies = [
"sval",
]
[[package]]
name = "sval_fmt"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "098fb51d5d6007bd2c3f0a23b79aa953d7c46bf943086ce51424c3187c40f9b1"
checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326"
dependencies = [
"itoa",
"ryu",
@ -1557,9 +1557,9 @@ dependencies = [
[[package]]
name = "sval_json"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f01126a2783d767496f18f13af26ab2587881f6343368bb26dc62956a723d1c7"
checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d"
dependencies = [
"itoa",
"ryu",
@ -1568,18 +1568,18 @@ dependencies = [
[[package]]
name = "sval_ref"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5854d9eaa7bd31840a850322591c59c5b547eb29c9a6ecee1989d6ef963312ce"
checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c"
dependencies = [
"sval",
]
[[package]]
name = "sval_serde"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cdd25fc04c5e882787d62112591aa93efb5bdc2000b43164d29f08582bb85f7"
checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046"
dependencies = [
"serde",
"sval",
@ -1600,9 +1600,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.22"
version = "2.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2"
dependencies = [
"proc-macro2",
"quote",
@ -1611,22 +1611,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.40"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -1656,7 +1656,7 @@ dependencies = [
"http-types",
"kv-log-macro",
"log",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"route-recognizer",
"serde",
"serde_json",
@ -1745,7 +1745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.10",
"tracing-attributes",
"tracing-core",
]
@ -1758,7 +1758,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
]
[[package]]
@ -1814,9 +1814,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-ident"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
[[package]]
name = "unicode-normalization"
@ -1851,9 +1851,9 @@ dependencies = [
[[package]]
name = "value-bag"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e"
checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3"
dependencies = [
"value-bag-serde1",
"value-bag-sval2",
@ -1861,9 +1861,9 @@ dependencies = [
[[package]]
name = "value-bag-serde1"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4735c95b4cca1447b448e2e2e87e98d7e7498f4da27e355cf7af02204521001d"
checksum = "b0b9f3feef403a50d4d67e9741a6d8fc688bcbb4e4f31bd4aab72cc690284394"
dependencies = [
"erased-serde",
"serde",
@ -1872,9 +1872,9 @@ dependencies = [
[[package]]
name = "value-bag-sval2"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859cb4f0ce7da6a118b559ba74b0e63bf569bea867c20ba457a6b1c886a04e97"
checksum = "30b24f4146b6f3361e91cbf527d1fb35e9376c3c0cef72ca5ec5af6d640fad7d"
dependencies = [
"sval",
"sval_buffer",
@ -1938,7 +1938,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
"wasm-bindgen-shared",
]
@ -1972,7 +1972,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
"syn 2.0.25",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -2035,9 +2035,9 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.48.0"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",

View file

@ -11,7 +11,7 @@ anyhow = "1.0.70"
askama = { version = "0.12.0", default-features = false, features = ["serde-json"] }
askama_tide = "0.15.0"
async-std = { version = "1.12.0", features = ["attributes"] }
infer = { version = "0.13.0", default-features = false }
infer = { version = "0.15.0", default-features = false }
percent-encoding = "2.2.0"
serde = { version = "1.0.160", features = ["derive"] }
serde_qs = "0.12.0"

6
src/crate_version.rs Normal file
View file

@ -0,0 +1,6 @@
#[macro_export]
macro_rules! crate_version {
() => {
env!("CARGO_PKG_VERSION")
};
}

View file

@ -1,157 +1,6 @@
use std::{collections::HashMap, path::Path};
use askama::Template;
use percent_encoding::percent_decode_str;
use serde::Deserialize;
mod mpd;
macro_rules! crate_version {
() => {
env!("CARGO_PKG_VERSION")
};
}
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate;
#[derive(Deserialize, Default)]
#[serde(default)]
struct IndexQuery {
path: String,
}
async fn get_index(_req: tide::Request<()>) -> tide::Result {
Ok(askama_tide::into_response(&IndexTemplate))
}
#[derive(Template)]
#[template(path = "queue.html")]
struct QueueTemplate {
queue: Vec<mpd::QueueItem>,
}
async fn get_queue(_req: tide::Request<()>) -> tide::Result {
let queue = mpd::Mpd::connect().await?.playlist().await?;
let template = QueueTemplate { queue };
Ok(template.into())
}
#[derive(Template)]
#[template(path = "player.html")]
struct PlayerTemplate<'a> {
song: Option<&'a HashMap<String, String>>,
name: Option<String>,
state: &'a str,
elapsed: f32,
duration: f32,
}
async fn get_player(_req: tide::Request<()>) -> tide::Result {
let mut mpd = mpd::Mpd::connect().await?;
let song = mpd.command("currentsong").await?.into_hashmap();
let status = mpd.command("status").await?.into_hashmap();
let elapsed = status
.get("elapsed")
.and_then(|e| e.parse().ok())
.unwrap_or(0.0);
let duration = status
.get("duration")
.and_then(|e| e.parse().ok())
.unwrap_or(1.0);
let mut template = PlayerTemplate {
song: if song.is_empty() { None } else { Some(&song) },
name: None,
state: &status["state"],
elapsed,
duration,
};
if !song.is_empty() {
let name = song.get("Title").unwrap_or(&song["file"]).to_string();
template.name = Some(name);
}
Ok(template.into())
}
#[derive(Template)]
#[template(path = "browser.html")]
struct BrowserTemplate {
path: Vec<String>,
entries: Vec<mpd::Entry>,
}
async fn get_browser(req: tide::Request<()>) -> tide::Result {
let query: IndexQuery = req.query()?;
let path = percent_decode_str(&query.path).decode_utf8_lossy();
let entries = mpd::Mpd::connect().await?.ls(&path).await?;
let template = BrowserTemplate {
path: Path::new(&*path)
.iter()
.map(|s| s.to_string_lossy().to_string())
.collect(),
entries,
};
Ok(template.into())
}
#[derive(Deserialize)]
struct PostQueueQuery {
path: String,
#[serde(default)]
replace: bool,
#[serde(default)]
next: bool,
#[serde(default)]
play: bool,
}
async fn post_queue(req: tide::Request<()>) -> tide::Result {
let query: PostQueueQuery = req.query()?;
let path = percent_decode_str(&query.path).decode_utf8_lossy();
let mut mpd = mpd::Mpd::connect().await?;
if query.replace {
mpd.clear().await?;
}
if query.next {
mpd.add_pos(&path, "+0").await?;
} else {
mpd.add(&path).await?;
}
if query.play {
mpd.play().await?;
}
Ok("".into())
}
#[derive(Deserialize)]
struct DeleteQueueQuery {
#[serde(default)]
id: Option<u32>,
}
async fn delete_queue(req: tide::Request<()>) -> tide::Result {
let query: DeleteQueueQuery = req.query()?;
let mut mpd = mpd::Mpd::connect().await?;
if let Some(id) = query.id {
mpd.command(&format!("deleteid {id}")).await?;
} else {
mpd.command("clear").await?;
}
Ok("".into())
}
mod routes;
mod crate_version;
async fn post_play(_req: tide::Request<()>) -> tide::Result {
mpd::Mpd::connect().await?.command("play").await?;
@ -173,51 +22,6 @@ async fn post_next(_req: tide::Request<()>) -> tide::Result {
Ok("".into())
}
#[derive(Deserialize, Debug)]
struct UpdateQueueBody {
from: u32,
to: u32,
}
async fn post_queue_move(mut req: tide::Request<()>) -> tide::Result {
let body: UpdateQueueBody = req.body_json().await?;
let mut mpd = mpd::Mpd::connect().await?;
mpd.command(&format!("move {} {}", body.from, body.to))
.await?;
Ok("".into())
}
async fn get_art(req: tide::Request<()>) -> tide::Result {
let query: IndexQuery = req.query()?;
let path = percent_decode_str(&query.path).decode_utf8_lossy();
let mut mpd = mpd::Mpd::connect().await?;
let resp = if let Ok(art) = mpd.albumart(&path).await {
let mime = infer::get(&art)
.map(|k| k.mime_type())
.unwrap_or("application/octet-stream");
tide::Response::builder(tide::StatusCode::Ok)
.body(art)
.content_type(mime)
.header("cache-control", "max-age=3600")
} else if let Ok(art) = mpd.readpicture(&path).await {
let mime = infer::get(&art)
.map(|k| k.mime_type())
.unwrap_or("application/octet-stream");
tide::Response::builder(tide::StatusCode::Ok)
.body(art)
.content_type(mime)
.header("cache-control", "max-age=3600")
} else {
tide::Response::builder(tide::StatusCode::NotFound)
};
Ok(resp.into())
}
async fn sse(_req: tide::Request<()>, sender: tide::sse::Sender) -> tide::Result<()> {
// Update everything on connect
sender.send("playlist", "", None).await?;
@ -242,17 +46,17 @@ async fn main() -> tide::Result<()> {
let mut app = tide::new();
app.with(tide_tracing::TraceMiddleware::new());
app.at("/").get(get_index);
app.at("/queue").get(get_queue);
app.at("/player").get(get_player);
app.at("/art").get(get_art);
app.at("/browser").get(get_browser);
app.at("/").get(routes::index::get_index);
app.at("/player").get(routes::player::get_player);
app.at("/browser").get(routes::browser::get_browser);
app.at("/art").get(routes::art::get_art);
app.at("/sse").get(tide::sse::endpoint(sse));
app.at("/queue").post(post_queue);
app.at("/queue").delete(delete_queue);
app.at("/queue/move").post(post_queue_move);
app.at("/queue").get(routes::queue::get_queue);
app.at("/queue").post(routes::queue::post_queue);
app.at("/queue").delete(routes::queue::delete_queue);
app.at("/queue/move").post(routes::queue::post_queue_move);
app.at("/play").post(post_play);
app.at("/pause").post(post_pause);

40
src/routes/art.rs Normal file
View file

@ -0,0 +1,40 @@
use serde::Deserialize;
use crate::mpd;
use percent_encoding::percent_decode_str;
#[derive(Deserialize, Default)]
#[serde(default)]
struct ArtQuery {
path: String,
}
pub async fn get_art(req: tide::Request<()>) -> tide::Result {
let query: ArtQuery = req.query()?;
let path = percent_decode_str(&query.path).decode_utf8_lossy();
let mut mpd = mpd::Mpd::connect().await?;
let resp = if let Ok(art) = mpd.albumart(&path).await {
let mime = infer::get(&art)
.map(|k| k.mime_type())
.unwrap_or("application/octet-stream");
tide::Response::builder(tide::StatusCode::Ok)
.body(art)
.content_type(mime)
.header("cache-control", "max-age=3600")
} else if let Ok(art) = mpd.readpicture(&path).await {
let mime = infer::get(&art)
.map(|k| k.mime_type())
.unwrap_or("application/octet-stream");
tide::Response::builder(tide::StatusCode::Ok)
.body(art)
.content_type(mime)
.header("cache-control", "max-age=3600")
} else {
tide::Response::builder(tide::StatusCode::NotFound)
};
Ok(resp.into())
}

34
src/routes/browser.rs Normal file
View file

@ -0,0 +1,34 @@
use askama::Template;
use serde::Deserialize;
use crate::mpd;
use percent_encoding::percent_decode_str;
use std::path::Path;
#[derive(Template)]
#[template(path = "browser.html")]
struct BrowserTemplate {
path: Vec<String>,
entries: Vec<mpd::Entry>,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct BrowserQuery {
path: String,
}
pub async fn get_browser(req: tide::Request<()>) -> tide::Result {
let query: BrowserQuery = req.query()?;
let path = percent_decode_str(&query.path).decode_utf8_lossy();
let entries = mpd::Mpd::connect().await?.ls(&path).await?;
let template = BrowserTemplate {
path: Path::new(&*path)
.iter()
.map(|s| s.to_string_lossy().to_string())
.collect(),
entries,
};
Ok(template.into())
}

17
src/routes/index.rs Normal file
View file

@ -0,0 +1,17 @@
use askama::Template;
use serde::Deserialize;
use crate::crate_version;
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate;
#[derive(Deserialize, Default)]
#[serde(default)]
struct IndexQuery {
path: String,
}
pub async fn get_index(_req: tide::Request<()>) -> tide::Result {
Ok(askama_tide::into_response(&IndexTemplate))
}

5
src/routes/mod.rs Normal file
View file

@ -0,0 +1,5 @@
pub mod index;
pub mod queue;
pub mod player;
pub mod browser;
pub mod art;

43
src/routes/player.rs Normal file
View file

@ -0,0 +1,43 @@
use askama::Template;
use crate::mpd;
use std::collections::HashMap;
#[derive(Template)]
#[template(path = "player.html")]
struct PlayerTemplate<'a> {
song: Option<&'a HashMap<String, String>>,
name: Option<String>,
state: &'a str,
elapsed: f32,
duration: f32,
}
pub async fn get_player(_req: tide::Request<()>) -> tide::Result {
let mut mpd = mpd::Mpd::connect().await?;
let song = mpd.command("currentsong").await?.into_hashmap();
let status = mpd.command("status").await?.into_hashmap();
let elapsed = status
.get("elapsed")
.and_then(|e| e.parse().ok())
.unwrap_or(0.0);
let duration = status
.get("duration")
.and_then(|e| e.parse().ok())
.unwrap_or(1.0);
let mut template = PlayerTemplate {
song: if song.is_empty() { None } else { Some(&song) },
name: None,
state: &status["state"],
elapsed,
duration,
};
if !song.is_empty() {
let name = song.get("Title").unwrap_or(&song["file"]).to_string();
template.name = Some(name);
}
Ok(template.into())
}

82
src/routes/queue.rs Normal file
View file

@ -0,0 +1,82 @@
use askama::Template;
use crate::mpd;
use serde::Deserialize;
use percent_encoding::percent_decode_str;
#[derive(Template)]
#[template(path = "queue.html")]
struct QueueTemplate {
queue: Vec<mpd::QueueItem>,
}
pub async fn get_queue(_req: tide::Request<()>) -> tide::Result {
let queue = mpd::Mpd::connect().await?.playlist().await?;
let template = QueueTemplate { queue };
Ok(template.into())
}
#[derive(Deserialize)]
struct PostQueueQuery {
path: String,
#[serde(default)]
replace: bool,
#[serde(default)]
next: bool,
#[serde(default)]
play: bool,
}
pub async fn post_queue(req: tide::Request<()>) -> tide::Result {
let query: PostQueueQuery = req.query()?;
let path = percent_decode_str(&query.path).decode_utf8_lossy();
let mut mpd = mpd::Mpd::connect().await?;
if query.replace {
mpd.clear().await?;
}
if query.next {
mpd.add_pos(&path, "+0").await?;
} else {
mpd.add(&path).await?;
}
if query.play {
mpd.play().await?;
}
Ok("".into())
}
#[derive(Deserialize)]
struct DeleteQueueQuery {
#[serde(default)]
id: Option<u32>,
}
pub async fn delete_queue(req: tide::Request<()>) -> tide::Result {
let query: DeleteQueueQuery = req.query()?;
let mut mpd = mpd::Mpd::connect().await?;
if let Some(id) = query.id {
mpd.command(&format!("deleteid {id}")).await?;
} else {
mpd.command("clear").await?;
}
Ok("".into())
}
#[derive(Deserialize, Debug)]
struct UpdateQueueBody {
from: u32,
to: u32,
}
pub async fn post_queue_move(mut req: tide::Request<()>) -> tide::Result {
let body: UpdateQueueBody = req.body_json().await?;
let mut mpd = mpd::Mpd::connect().await?;
mpd.command(&format!("move {} {}", body.from, body.to))
.await?;
Ok("".into())
}