From 74c09f69667edbf77516f03320dcb0a19b70a268 Mon Sep 17 00:00:00 2001 From: Lee Jun Kit Date: Sat, 14 Aug 2021 18:49:34 +0800 Subject: [PATCH] say hello to PlayerCore written in Rust --- .gitignore | 3 + PlayerCore/Cargo.lock | 2361 ++++++++++++++++++++++++++++++++ PlayerCore/Cargo.toml | 20 + PlayerCore/src/api.rs | 152 ++ PlayerCore/src/config.rs | 55 + PlayerCore/src/event.rs | 40 + PlayerCore/src/lib.rs | 62 + PlayerCore/src/queue.rs | 436 ++++++ PlayerCore/src/sink_wrapper.rs | 52 + PlayerCore/src/spotify.rs | 257 ++++ 10 files changed, 3438 insertions(+) create mode 100644 PlayerCore/Cargo.lock create mode 100644 PlayerCore/Cargo.toml create mode 100644 PlayerCore/src/api.rs create mode 100644 PlayerCore/src/config.rs create mode 100644 PlayerCore/src/event.rs create mode 100644 PlayerCore/src/lib.rs create mode 100644 PlayerCore/src/queue.rs create mode 100644 PlayerCore/src/sink_wrapper.rs create mode 100644 PlayerCore/src/spotify.rs diff --git a/.gitignore b/.gitignore index 330d167..853316f 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,6 @@ fastlane/test_output # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ + +# Rust +PlayerCore/target/** \ No newline at end of file diff --git a/PlayerCore/Cargo.lock b/PlayerCore/Cargo.lock new file mode 100644 index 0000000..4644be3 --- /dev/null +++ b/PlayerCore/Cargo.lock @@ -0,0 +1,2361 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" +dependencies = [ + "aes-soft", + "aesni", + "cipher", + "ctr", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "alsa" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bindgen" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + +[[package]] +name = "bumpalo" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + +[[package]] +name = "cc" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "clang-sys" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "combine" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d47c1b11006b87e492b53b313bb699ce60e16613c4dddaa91f8f7c220ab2fa" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f45f0a21f617cd2c788889ef710b63f075c949259593ea09c826f1e47a2418" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "jni 0.19.0", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk", + "ndk-glue", + "nix", + "oboe", + "parking_lot", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "termcolor", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" + +[[package]] +name = "futures-executor" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" + +[[package]] +name = "futures-macro" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" + +[[package]] +name = "futures-task" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" + +[[package]] +name = "futures-util" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +dependencies = [ + "autocfg", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "h2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "headers" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" +dependencies = [ + "base64", + "bitflags", + "bytes", + "headers-core", + "http", + "mime", + "sha-1", + "time", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" + +[[package]] +name = "httpdate" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-proxy" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "tokio", + "tower-service", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if-addrs" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28538916eb3f3976311f5dfbe67b5362d0add1293d0a9cad17debf86f8e3aa48" +dependencies = [ + "if-addrs-sys", + "libc", + "winapi", +] + +[[package]] +name = "if-addrs-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "input_buffer" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" +dependencies = [ + "bytes", +] + +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "jni" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5ca711fd837261e14ec9e674f092cbb931d3fa1482b017ae59328ddc6f3212b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + +[[package]] +name = "libc" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" + +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libmdns" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98477a6781ae1d6a1c2aeabfd2e23353a75fe8eb7c2545f6ed282ac8f3e2fc53" +dependencies = [ + "byteorder", + "futures-util", + "hostname", + "if-addrs", + "log", + "multimap", + "rand 0.8.4", + "socket2", + "thiserror", + "tokio", +] + +[[package]] +name = "librespot" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "450aa724dcc28a06c6f3a070e7f4b84c0800d9152bec3b012a11ff886986bd58" +dependencies = [ + "base64", + "env_logger", + "futures-util", + "getopts", + "hex", + "hyper", + "librespot-audio", + "librespot-connect", + "librespot-core", + "librespot-metadata", + "librespot-playback", + "librespot-protocol", + "log", + "rpassword", + "sha-1", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "librespot-audio" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0e89d3e106d80600537eba02c17ea6dd8b3de3f46c99952b813b6f6d6445c0" +dependencies = [ + "aes-ctr", + "byteorder", + "bytes", + "cfg-if", + "futures-util", + "lewton", + "librespot-core", + "log", + "ogg", + "tempfile", + "tokio", + "zerocopy", +] + +[[package]] +name = "librespot-connect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69425fd6c8d74779f1ec86b16e6b3114df50c8a0d94db5a5601ef634bfb5e288" +dependencies = [ + "aes-ctr", + "base64", + "form_urlencoded", + "futures-core", + "futures-util", + "hmac", + "hyper", + "libmdns", + "librespot-core", + "librespot-playback", + "librespot-protocol", + "log", + "protobuf", + "rand 0.8.4", + "serde", + "serde_json", + "sha-1", + "tokio", + "tokio-stream", + "url", +] + +[[package]] +name = "librespot-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3e70dce131f5531c982ca133f04fd1d1dd4208de27291dcd9ab6841c963248" +dependencies = [ + "aes", + "base64", + "byteorder", + "bytes", + "form_urlencoded", + "futures-core", + "futures-util", + "hmac", + "http", + "httparse", + "hyper", + "hyper-proxy", + "librespot-protocol", + "log", + "num-bigint", + "num-integer", + "num-traits", + "once_cell", + "pbkdf2", + "priority-queue", + "protobuf", + "rand 0.8.4", + "serde", + "serde_json", + "sha-1", + "shannon", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "url", + "uuid", + "vergen", +] + +[[package]] +name = "librespot-metadata" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84157ce5d901dbdcaef17ed305deba5d87171725347673a1b632a334d910af47" +dependencies = [ + "async-trait", + "byteorder", + "librespot-core", + "librespot-protocol", + "log", + "protobuf", +] + +[[package]] +name = "librespot-playback" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ca3df986a7e1a43008717660803e159177e86a589d484a0fc01fccd7967ad6" +dependencies = [ + "byteorder", + "cpal", + "futures-executor", + "futures-util", + "librespot-audio", + "librespot-core", + "librespot-metadata", + "log", + "rodio", + "shell-words", + "thiserror", + "tokio", + "zerocopy", +] + +[[package]] +name = "librespot-protocol" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c753be4c3bd0f02b30c00d5d8547f16d557654cb737e70505aec6aa9990435d" +dependencies = [ + "glob", + "protobuf", + "protobuf-codegen", + "protobuf-codegen-pure", +] + +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "multipart" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" +dependencies = [ + "buf_redux", + "httparse", + "log", + "mime", + "mime_guess", + "quick-error", + "rand 0.7.3", + "safemem", + "tempfile", + "twoway", +] + +[[package]] +name = "ndk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +dependencies = [ + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-glue" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk", + "ndk-macro", + "ndk-sys", +] + +[[package]] +name = "ndk-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling", + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" + +[[package]] +name = "nix" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8e5e343312e7fbeb2a52139114e9e702991ef9c2aea6817ff2440b35647d56" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand 0.8.4", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2c8fd66061a707503d515639b8af10fd3807a5b5ee6959f7ff1bd303634bd5" +dependencies = [ + "derivative", + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474fd1d096da3ad17084694eebed40ba09c4a36c5255cd772bd8b98859cc562e" +dependencies = [ + "proc-macro-crate 1.0.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "oboe" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa187b38ae20374617b7ad418034ed3dc90ac980181d211518bd03537ae8f8d" +dependencies = [ + "jni 0.18.0", + "ndk", + "ndk-glue", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88e64835aa3f579c08d182526dc34e3907343d5b97e87b71a40ba5bca7aca9e" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac", + "hmac", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "priority-queue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1340009a04e81f656a4e45e295f0b1191c81de424bf940c865e33577a8e223" +dependencies = [ + "autocfg", + "indexmap", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "protobuf" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" + +[[package]] +name = "protobuf-codegen" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de113bba758ccf2c1ef816b127c958001b7831136c9bc3f8e9ec695ac4e82b0c" +dependencies = [ + "protobuf", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1a4febc73bf0cada1d77c459a0c8e5973179f1cfd5b0f1ab789d45b17b6440" +dependencies = [ + "protobuf", + "protobuf-codegen", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.3", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core 0.6.3", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rodio" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65c2eda643191f6d1bb12ea323a9db8d9ba95374e9be3780b5a9fb5cfb8520f" +dependencies = [ + "cpal", +] + +[[package]] +name = "rpassword" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + +[[package]] +name = "serde" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "shannon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" +dependencies = [ + "byteorder", +] + +[[package]] +name = "shell-words" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" + +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "socket2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spottie-player-core" +version = "0.1.0" +dependencies = [ + "futures", + "librespot", + "rand 0.8.4", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "warp", +] + +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand 0.8.4", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cf844b23c6131f624accf65ce0e4e9956a8bb329400ea5bcc26ae3a5c20b0b" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b" +dependencies = [ + "futures-util", + "log", + "pin-project", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "input_buffer", + "log", + "rand 0.8.4", + "sha-1", + "url", + "utf-8", +] + +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.3", +] + +[[package]] +name = "vergen" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" +dependencies = [ + "bitflags", + "chrono", + "rustc_version", +] + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "warp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multipart", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" + +[[package]] +name = "web-sys" +version = "0.3.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zerocopy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] diff --git a/PlayerCore/Cargo.toml b/PlayerCore/Cargo.toml new file mode 100644 index 0000000..6333ba8 --- /dev/null +++ b/PlayerCore/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "spottie-player-core" +version = "0.1.0" +authors = ["Lee Jun Kit "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["lib", "staticlib"] + +[dependencies] +tokio = { version = "1", features = ["full"] } +tokio-stream = { version = "0.1", features = ["net"] } +warp = "0.3" +librespot = "0.2.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +rand = "0.8" +futures = "0.3" \ No newline at end of file diff --git a/PlayerCore/src/api.rs b/PlayerCore/src/api.rs new file mode 100644 index 0000000..b1437ee --- /dev/null +++ b/PlayerCore/src/api.rs @@ -0,0 +1,152 @@ +use std::sync::{Arc, Mutex}; +use crate::spotify::Spotify; + +pub mod filters { + use super::{handlers, Arc, Mutex, Spotify}; + use serde::{Deserialize}; + use crate::queue::Queue; + use std::convert::Infallible; + use warp::{ + Filter, + }; + + #[derive(Clone, Debug, Deserialize)] + struct QueueRequestBody { + track_ids: Vec + } + + pub fn get_token(spotify: Arc>) -> impl Filter + Clone { + warp::path!("token") + .and(with_spotify(spotify)) + .and_then(handlers::get_token) + } + + pub fn toggle_playback(queue: Arc) -> impl Filter + Clone { + warp::post() + .and(warp::path!("queue" / "toggle")) + .and(with_queue(queue)) + .and_then(handlers::toggle_playback) + } + + pub fn play(queue: Arc) -> impl Filter + Clone { + warp::post() + .and(warp::path!("queue" / "play")) + .and(json_body()) + .map(|body: QueueRequestBody| { + body.track_ids + }) + .and(with_queue(queue)) + .and_then(handlers::play) + } + + pub fn next(queue: Arc) -> impl Filter + Clone { + warp::post() + .and(warp::path!("queue" / "next")) + .and(with_queue(queue)) + .and_then(handlers::next) + } + + pub fn previous(queue: Arc) -> impl Filter + Clone { + warp::post() + .and(warp::path!("queue" / "previous")) + .and(with_queue(queue)) + .and_then(handlers::previous) + } + + // pub fn play_next(queue: Arc) -> impl Filter + Clone { + // warp::post() + // .and(warp::path!("queue/play_next")) + // } + + // pub fn queue(queue: Arc) -> impl Filter + Clone { + // warp::post() + // .and(warp::path!("queue/push")) + // } + + fn json_body() -> impl Filter + Clone { + warp::body::content_length_limit(1024 * 16).and(warp::body::json()) + } + + fn with_queue(queue: Arc) -> impl Filter,), Error = Infallible> + Clone { + warp::any().map(move || queue.clone()) + } + + fn with_spotify(spotify: Arc>) -> impl Filter>,), Error = Infallible> + Clone { + warp::any().map(move || spotify.clone()) + } +} + +mod handlers { + use librespot::core::spotify_id::SpotifyId; + use librespot::core::keymaster; + use serde::Serialize; + use super::{Arc, Mutex, Spotify}; + use std::convert::Infallible; + use warp::{Reply}; + use crate::queue::Queue; + + #[derive(Serialize)] + struct TokenProxy { + access_token: String, + expires_in: u32, + token_type: String, + scope: Vec, + } + + pub async fn get_token(spotify: Arc>) -> Result { + let session = spotify.lock().unwrap().get_session().clone(); + let client_id = "d420a117a32841c2b3474932e49fb54b"; + let scopes = "user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read,user-read-recently-played"; + let token = keymaster::get_token(&session, client_id, scopes).await.unwrap(); + let proxy = TokenProxy { + access_token: token.access_token, + expires_in: token.expires_in, + token_type: token.token_type, + scope: token.scope, + }; + + Ok(warp::reply::json(&proxy).into_response()) + } + + pub async fn play(track_ids: Vec, queue: Arc) -> Result { + let q = queue.clone(); + + // append the track_ids into the queue + let index = q.append_next(track_ids.iter().map(|id: &String| { + SpotifyId::from_base62(id).unwrap() + }).collect()); + + // start playback at the first inserted index + q.play(index, true, true); + + // return latest queue items + let queue_items = q.queue.read().unwrap(); + let ids: Vec = queue_items.iter().map(|id: &SpotifyId| { + id.to_base62() + }).collect(); + + Ok(warp::reply::json(&ids).into_response()) + } + + pub async fn toggle_playback(queue: Arc) -> Result { + let q = queue.clone(); + q.toggleplayback(); + Ok(warp::reply()) + } + + pub async fn next(queue: Arc) -> Result { + let q = queue.clone(); + q.next(true); + Ok(warp::reply()) + } + + pub async fn previous(queue: Arc) -> Result { + let q = queue.clone(); + q.previous(); + Ok(warp::reply()) + } + + pub fn queue_append_after_current() { + + } +} \ No newline at end of file diff --git a/PlayerCore/src/config.rs b/PlayerCore/src/config.rs new file mode 100644 index 0000000..ffb00ee --- /dev/null +++ b/PlayerCore/src/config.rs @@ -0,0 +1,55 @@ +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use serde::{Serialize, Deserialize}; +use crate::queue; + +/* +#[derive(Serialize, Default, Deserialize, Debug, Clone)] +pub struct QueueState { + pub current_track: Option, + pub random_order: Option>, + pub track_progress: std::time::Duration, + pub queue: Vec, +} +*/ + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserState { + pub volume: u16, + pub shuffle: bool, + pub repeat: queue::RepeatSetting, + //pub queue_state: QueueState, +} + +impl Default for UserState { + fn default() -> Self { + UserState { + volume: u16::max_value(), + shuffle: false, + repeat: queue::RepeatSetting::None, + } + } +} + +pub struct Config { + state: RwLock, +} + +impl Config { + pub fn new() -> Self { + Self { + state: RwLock::new(UserState::default()) + } + } + + pub fn state(&self) -> RwLockReadGuard { + self.state.read().expect("can't readlock user state") + } + + pub fn with_state_mut(&self, cb: F) + where + F: Fn(RwLockWriteGuard), + { + let state_guard = self.state.write().expect("can't writelock user state"); + cb(state_guard); + } +} diff --git a/PlayerCore/src/event.rs b/PlayerCore/src/event.rs new file mode 100644 index 0000000..be1d5b8 --- /dev/null +++ b/PlayerCore/src/event.rs @@ -0,0 +1,40 @@ +use std::ffi::{c_void}; +use std::sync::{Arc, Mutex}; +use serde_json::json; +use crate::queue::{Queue, QueueState}; +use crate::spotify::*; + +pub struct EventCallbackBox { + pub ptr: *const c_void, + pub callback: extern fn(*const c_void, *mut u8, usize) +} + +unsafe impl Send for EventCallbackBox {} + +pub fn start_event_broadcast(spotify: Arc>, queue: Arc, b: EventCallbackBox) { + tokio::spawn(async move { + let mut spotify_event_rx = spotify.lock().unwrap().get_spotify_event_channel(); + loop { + let spotify_event = spotify_event_rx.recv().await; + let queue_items = queue.queue.read().unwrap(); + let base62 = queue_items.clone().into_iter().map(|item| item.to_base62()).collect(); + + let json = json!({ + "player": spotify_event, + "queue": QueueState { + items: base62, + current_index: queue.get_current_index(), + } + }); + + let mut v = serde_json::to_vec(&json).unwrap(); + v.shrink_to_fit(); + + let ptr = v.as_mut_ptr(); + let len = v.len(); + + let cb = b.callback; + cb(b.ptr, ptr, len); + } + }); +} \ No newline at end of file diff --git a/PlayerCore/src/lib.rs b/PlayerCore/src/lib.rs new file mode 100644 index 0000000..957f4ce --- /dev/null +++ b/PlayerCore/src/lib.rs @@ -0,0 +1,62 @@ +use std::{env, fs}; +use std::sync::mpsc; +use std::os::raw::c_char; +use tokio::runtime::Runtime; +use tokio::net::UnixListener; +use tokio_stream::wrappers::UnixListenerStream; +use warp::Filter; +use std::ffi::{c_void, CString}; + +mod api; +mod sink_wrapper; +mod spotify; +mod config; +mod queue; +mod event; + +#[no_mangle] +pub extern "C" fn librespot_init(user_data: *const c_void, event_callback: extern fn(*const c_void, *mut u8, usize)) { + let rt = Runtime::new().unwrap(); + rt.block_on(async move { + let (sink_reload_tx, sink_reload_rx) = mpsc::sync_channel(1); + let spotify = spotify::Spotify::new(sink_reload_rx).await; + let queue = queue::Queue::new(spotify.clone()); + + event::start_event_broadcast(spotify.clone(), queue.clone(), event::EventCallbackBox { + ptr: user_data, + callback: event_callback, + }); + + let mut dir = env::temp_dir(); + dir.push("warp.sock"); + println!("Temporary directory: {}", &dir.display()); + + fs::remove_file(&dir).ok(); + + let listener = UnixListener::bind(dir).unwrap(); + let incoming = UnixListenerStream::new(listener); + + let routes = api::filters::get_token(spotify.clone()) + .or(api::filters::play(queue.clone())) + .or(api::filters::toggle_playback(queue.clone())) + .or(api::filters::next(queue.clone())) + .or(api::filters::previous(queue.clone())); + + warp::serve(routes) + .run_incoming(incoming) + .await; + }); +} + +#[no_mangle] +pub extern "C" fn free_string(s: *mut c_char) { + let cstring = unsafe { CString::from_raw(s) }; + drop(cstring); +} + +#[no_mangle] +/// This is intended for the C code to call for deallocating +/// the Rust-allocated u8 array. +pub unsafe extern "C" fn deallocate_rust_buffer(ptr: *mut u8, len: usize) { + drop(Vec::from_raw_parts(ptr, len, len)); +} \ No newline at end of file diff --git a/PlayerCore/src/queue.rs b/PlayerCore/src/queue.rs new file mode 100644 index 0000000..5b1c0a9 --- /dev/null +++ b/PlayerCore/src/queue.rs @@ -0,0 +1,436 @@ +/* +Adapted from ncspot's queue implementation found at +https://github.com/hrkfdn/ncspot/blob/HEAD/src/queue.rs + +BSD 2-Clause License + +Copyright (c) 2019, Henrik Friedrichsen +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +use std::cmp::Ordering; +use std::sync::{Mutex, Arc, RwLock}; +use librespot::core::spotify_id::SpotifyId; +use librespot::playback::player::PlayerEvent as LibrespotPlayerEvent; +use tokio::sync::mpsc::{UnboundedReceiver}; +use serde::{Serialize, Deserialize}; +use rand::prelude::*; +use crate::spotify::{Spotify, PlayerEvent}; +use crate::config::Config; + +#[derive(Clone, Debug, Serialize)] +pub struct QueueState { + pub items: Vec, + pub current_index: Option, +} + +#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] +pub enum RepeatSetting { + #[serde(rename = "off")] + None, + #[serde(rename = "playlist")] + RepeatPlaylist, + #[serde(rename = "track")] + RepeatTrack, +} + +pub struct Queue { + pub queue: Arc>>, + random_order: RwLock>>, + current_track: RwLock>, + spotify: Arc>, + cfg: Arc, +} + +impl Queue { + pub fn new(spotify: Arc>) -> Arc { + // get an event channel for LibrespotPlayerEvent + let player_events_rx = spotify.lock().unwrap().get_player_event_channel(); + let cfg = Arc::new(Config::new()); + + let q = Arc::new(Queue { + queue: Arc::new(RwLock::new(vec![])), + random_order: RwLock::new(Some(vec![])), + current_track: RwLock::new(None), + spotify, + cfg, + }); + + Queue::player_events_run_loop(player_events_rx, q.clone()); + + q + } + + fn player_events_run_loop(mut events_rx: UnboundedReceiver, queue: Arc) { + tokio::spawn(async move { + loop { + let event = events_rx.recv().await; + match event { + Some(LibrespotPlayerEvent::EndOfTrack { .. }) => { + queue.next(false); + } + Some(LibrespotPlayerEvent::TimeToPreloadNextTrack { .. }) => { + if let Some(next_index) = queue.next_index() { + let track = queue.queue.read().unwrap()[next_index].clone(); + queue.spotify.lock().unwrap().preload(track); + } + } + _ => {} + } + } + }); + } + + pub fn next_index(&self) -> Option { + match *self.current_track.read().unwrap() { + Some(mut index) => { + let random_order = self.random_order.read().unwrap(); + if let Some(order) = random_order.as_ref() { + index = order.iter().position(|&i| i == index).unwrap(); + } + + let mut next_index = index + 1; + if next_index < self.queue.read().unwrap().len() { + if let Some(order) = random_order.as_ref() { + next_index = order[next_index]; + } + + Some(next_index) + } else { + None + } + } + None => None, + } + } + + pub fn previous_index(&self) -> Option { + match *self.current_track.read().unwrap() { + Some(mut index) => { + let random_order = self.random_order.read().unwrap(); + if let Some(order) = random_order.as_ref() { + index = order.iter().position(|&i| i == index).unwrap(); + } + + if index > 0 { + let mut next_index = index - 1; + if let Some(order) = random_order.as_ref() { + next_index = order[next_index]; + } + + Some(next_index) + } else { + None + } + } + None => None, + } + } + + pub fn get_current(&self) -> Option { + self.get_current_index() + .map(|index| self.queue.read().unwrap()[index].clone()) + } + + pub fn get_current_index(&self) -> Option { + *self.current_track.read().unwrap() + } + + pub fn insert_after_current(&self, track: SpotifyId) { + if let Some(index) = self.get_current_index() { + let mut random_order = self.random_order.write().unwrap(); + if let Some(order) = random_order.as_mut() { + let next_i = order.iter().position(|&i| i == index).unwrap(); + // shift everything after the insertion in order + for item in order.iter_mut() { + if *item > index { + *item += 1; + } + } + // finally, add the next track index + order.insert(next_i + 1, index + 1); + } + let mut q = self.queue.write().unwrap(); + q.insert(index + 1, track); + } else { + self.append(track); + } + } + + pub fn append(&self, track: SpotifyId) { + let mut random_order = self.random_order.write().unwrap(); + if let Some(order) = random_order.as_mut() { + let index = order.len().saturating_sub(1); + order.push(index); + } + + let mut q = self.queue.write().unwrap(); + q.push(track); + } + + pub fn append_next(&self, tracks: Vec) -> usize { + let mut q = self.queue.write().unwrap(); + + { + let mut random_order = self.random_order.write().unwrap(); + if let Some(order) = random_order.as_mut() { + order.extend((q.len().saturating_sub(1))..(q.len() + tracks.len())); + } + } + + let first = match *self.current_track.read().unwrap() { + Some(index) => index + 1, + None => q.len(), + }; + + let mut i = first; + for track in tracks { + q.insert(i, track.clone()); + i += 1; + } + + first + } + + pub fn remove(&self, index: usize) { + { + let mut q = self.queue.write().unwrap(); + if q.len() == 0 { + return; + } + q.remove(index); + } + + // if the queue is empty stop playback + let len = self.queue.read().unwrap().len(); + if len == 0 { + self.stop(); + return; + } + + // if we are deleting the currently playing track, play the track with + // the same index again, because the next track is now at the position + // of the one we deleted + let current = *self.current_track.read().unwrap(); + if let Some(current_track) = current { + match current_track.cmp(&index) { + Ordering::Equal => { + // if we have deleted the last item and it was playing + // stop playback, unless repeat playlist is on, play next + if current_track == len { + if self.get_repeat() == RepeatSetting::RepeatPlaylist { + self.next(false); + } else { + self.stop(); + } + } else { + self.play(index, false, false); + } + } + Ordering::Greater => { + let mut current = self.current_track.write().unwrap(); + current.replace(current_track - 1); + } + _ => (), + } + } + + if self.get_shuffle() { + self.generate_random_order(); + } + } + + pub fn clear(&self) { + self.stop(); + + let mut q = self.queue.write().unwrap(); + q.clear(); + + let mut random_order = self.random_order.write().unwrap(); + if let Some(o) = random_order.as_mut() { + o.clear() + } + } + + pub fn len(&self) -> usize { + self.queue.read().unwrap().len() + } + + pub fn shift(&self, from: usize, to: usize) { + let mut queue = self.queue.write().unwrap(); + let item = queue.remove(from); + queue.insert(to, item); + + // if the currently playing track is affected by the shift, update its + // index + let mut current = self.current_track.write().unwrap(); + if let Some(index) = *current { + if index == from { + current.replace(to); + } else if index == to && from > index { + current.replace(to + 1); + } else if index == to && from < index { + current.replace(to - 1); + } + } + } + + pub fn play(&self, mut index: usize, reshuffle: bool, shuffle_index: bool) { + if shuffle_index && self.get_shuffle() { + let mut rng = rand::thread_rng(); + index = rng.gen_range(0..self.queue.read().unwrap().len()); + } + + if let Some(track) = self.queue.read().unwrap().get(index) { + self.spotify.lock().unwrap().load(track.clone(), true, 0); + let mut current = self.current_track.write().unwrap(); + current.replace(index); + } + + if reshuffle && self.get_shuffle() { + self.generate_random_order() + } + } + + pub fn toggleplayback(&self) { + let spotify = self.spotify.lock().unwrap(); + let current_status = spotify.get_current_status(); + + match current_status { + PlayerEvent::Playing(_, _) | PlayerEvent::Paused(_, _) => { + spotify.toggleplayback(); + } + PlayerEvent::Stopped => match self.next_index() { + Some(_) => { + drop(spotify); + self.next(false); + } + None => { + drop(spotify); + self.play(0, false, false); + } + }, + _ => (), + } + } + + pub fn stop(&self) { + let mut current = self.current_track.write().unwrap(); + *current = None; + self.spotify.lock().unwrap().stop(); + } + + pub fn next(&self, manual: bool) { + let q = self.queue.read().unwrap(); + let current = *self.current_track.read().unwrap(); + let repeat = self.cfg.state().repeat; + + if repeat == RepeatSetting::RepeatTrack && !manual { + if let Some(index) = current { + self.play(index, false, false); + } + } else if let Some(index) = self.next_index() { + self.play(index, false, false); + if repeat == RepeatSetting::RepeatTrack && manual { + self.set_repeat(RepeatSetting::RepeatPlaylist); + } + } else if repeat == RepeatSetting::RepeatPlaylist && q.len() > 0 { + let random_order = self.random_order.read().unwrap(); + self.play( + random_order.as_ref().map(|o| o[0]).unwrap_or(0), + false, + false, + ); + } else { + self.spotify.lock().unwrap().stop(); + } + } + + pub fn previous(&self) { + let q = self.queue.read().unwrap(); + let current = *self.current_track.read().unwrap(); + let repeat = self.cfg.state().repeat; + + if let Some(index) = self.previous_index() { + self.play(index, false, false); + } else if repeat == RepeatSetting::RepeatPlaylist && q.len() > 0 { + if self.get_shuffle() { + let random_order = self.random_order.read().unwrap(); + self.play( + random_order.as_ref().map(|o| o[q.len() - 1]).unwrap_or(0), + false, + false, + ); + } else { + self.play(q.len() - 1, false, false); + } + } else if let Some(index) = current { + self.play(index, false, false); + } + } + + pub fn get_repeat(&self) -> RepeatSetting { + self.cfg.state().repeat + } + + pub fn set_repeat(&self, new: RepeatSetting) { + self.cfg.with_state_mut(|mut s| s.repeat = new); + } + + pub fn get_shuffle(&self) -> bool { + self.cfg.state().shuffle + } + + pub fn get_random_order(&self) -> Option> { + self.random_order.read().unwrap().clone() + } + + fn generate_random_order(&self) { + let q = self.queue.read().unwrap(); + let mut order: Vec = Vec::with_capacity(q.len()); + let mut random: Vec = (0..q.len()).collect(); + + if let Some(current) = *self.current_track.read().unwrap() { + order.push(current); + random.remove(current); + } + + let mut rng = rand::thread_rng(); + random.shuffle(&mut rng); + order.extend(random); + + let mut random_order = self.random_order.write().unwrap(); + *random_order = Some(order); + } + + pub fn set_shuffle(&self, new: bool) { + self.cfg.with_state_mut(|mut s| s.shuffle = new); + if new { + self.generate_random_order(); + } else { + let mut random_order = self.random_order.write().unwrap(); + *random_order = None; + } + } +} \ No newline at end of file diff --git a/PlayerCore/src/sink_wrapper.rs b/PlayerCore/src/sink_wrapper.rs new file mode 100644 index 0000000..1ba211c --- /dev/null +++ b/PlayerCore/src/sink_wrapper.rs @@ -0,0 +1,52 @@ +use librespot::playback::audio_backend; +use librespot::playback::config::AudioFormat; +use std::sync::mpsc::Receiver; +use librespot::audio::AudioPacket; +use std::io; + +pub struct SinkWrapper { + sink: Box, + sink_rx: Receiver<()>, +} + +impl SinkWrapper { + pub fn new(sink_rx: Receiver<()>) -> Box { + Box::new(SinkWrapper { + sink: SinkWrapper::get_sink(), + sink_rx, + }) + } + + fn get_sink() -> Box { + let backend = audio_backend::find(None).unwrap(); + let audio_format = AudioFormat::default(); + backend(None, audio_format) + } + + fn reload_sink(&mut self) { + self.sink = SinkWrapper::get_sink(); + } +} + +impl audio_backend::Sink for SinkWrapper { + fn start(&mut self) -> Result<(), std::io::Error> { + Ok(()) + } + + fn stop(&mut self) -> Result<(), std::io::Error> { + Ok(()) + } + + fn write( + &mut self, + packet: &AudioPacket + ) -> io::Result<()> { + let iter = self.sink_rx.try_iter(); + let c = iter.count(); + if c > 0 { + self.reload_sink(); + } + + self.sink.write(packet) + } +} \ No newline at end of file diff --git a/PlayerCore/src/spotify.rs b/PlayerCore/src/spotify.rs new file mode 100644 index 0000000..eae69bf --- /dev/null +++ b/PlayerCore/src/spotify.rs @@ -0,0 +1,257 @@ +use librespot::core::authentication::Credentials; +use librespot::core::config::SessionConfig; +use librespot::core::session::Session; +use librespot::core::spotify_id::SpotifyId; +use librespot::core::mercury::MercuryError; +use librespot::core::keymaster; +use librespot::playback::config::PlayerConfig; +use librespot::playback::player::{Player, PlayerEvent as LibrespotPlayerEvent}; +use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver}; +use serde::Serialize; +use std::time::{Duration, SystemTime}; +use std::sync::mpsc::Receiver; +use std::sync::{Arc, RwLock, Mutex}; +use crate::sink_wrapper::SinkWrapper; + +#[derive(Clone, Debug, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum PlayerState { + Playing, + Paused, + Stopped, +} + +#[derive(Clone, Serialize, Debug)] +pub struct SpotifyState { + pub state: PlayerState, + pub track_id: Option, + pub elapsed: Option, + pub since: Option, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PlayerEvent { + Playing(SystemTime, SpotifyId), + Paused(Duration, SpotifyId), + Stopped, + FinishedTrack, +} + +pub struct Spotify { + player: Player, + session: Session, + status: Arc>, + elapsed: Arc>>, + since: Arc>>, + event_senders: Vec>, +} + +impl Spotify { + pub async fn new(sink_rx: Receiver<()>) -> Arc> { + let session_config = SessionConfig::default(); + let player_config = PlayerConfig::default(); + let credentials = Credentials::with_password("***REMOVED***", "***REMOVED***"); + + println!("Connecting..."); + let session = Session::connect(session_config, credentials, None) + .await + .unwrap(); + + let (player, player_events_rx) = Player::new(player_config, session.clone(), None, move || { + SinkWrapper::new(sink_rx) + }); + + let spotify = Arc::new(Mutex::new(Spotify { + player, + session, + status: Arc::new(RwLock::new(PlayerEvent::Stopped)), + elapsed: Arc::new(RwLock::new(None)), + since: Arc::new(RwLock::new(None)), + event_senders: [].to_vec(), + })); + + // handle Player events + Spotify::player_events_run_loop(player_events_rx, spotify.clone()); + + spotify + } + + fn player_events_run_loop(mut events_rx: UnboundedReceiver, spotify: Arc>) { + tokio::spawn(async move { + loop { + let event = events_rx.recv().await; + match event { + Some(LibrespotPlayerEvent::Playing { + play_request_id: _, + track_id, + position_ms, + duration_ms: _, + }) => { + let position = Duration::from_millis(position_ms as u64); + let playback_start = SystemTime::now() - position; + spotify.lock().unwrap().update_status(PlayerEvent::Playing(playback_start, track_id)); + } + Some(LibrespotPlayerEvent::Paused { + play_request_id: _, + track_id, + position_ms, + duration_ms: _, + }) => { + let position = Duration::from_millis(position_ms as u64); + spotify.lock().unwrap().update_status(PlayerEvent::Paused(position, track_id)); + } + Some(LibrespotPlayerEvent::Stopped { .. }) => { + spotify.lock().unwrap().update_status(PlayerEvent::Stopped); + } + _ => {} + }; + } + }); + } + + pub fn get_spotify_event_channel(&mut self) -> UnboundedReceiver { + let (event_sender, event_receiver) = unbounded_channel(); + self.event_senders.push(event_sender); + event_receiver + } + + pub fn get_player_event_channel(&mut self) -> UnboundedReceiver { + self.player.get_player_event_channel() + } + + pub fn get_session(&self) -> &Session { + &self.session + } + + pub async fn get_token(&self) -> Result { + let client_id = "d420a117a32841c2b3474932e49fb54b"; + let scopes = "user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read,user-read-recently-played"; + keymaster::get_token(&self.session, client_id, scopes).await + } + + pub fn preload(&self, track: SpotifyId) { + self.player.preload(track); + } + + pub fn load(&mut self, track: SpotifyId, start_playing: bool, position_ms: u32) { + self.player.load(track, start_playing, position_ms); + } + + pub fn play(&self) { + self.player.play(); + } + + pub fn pause(&self) { + self.player.pause(); + } + + pub fn stop(&self) { + self.player.stop(); + } + + pub fn toggleplayback(&self) { + match self.get_current_status() { + PlayerEvent::Playing(_, _) => self.pause(), + PlayerEvent::Paused(_, _) => self.play(), + _ => (), + } + } + + pub fn get_current_status(&self) -> PlayerEvent { + let status = self + .status + .read() + .expect("could not acquire read lock on playback status"); + (*status).clone() + } + + pub fn update_status(&mut self, new_status: PlayerEvent) { + { + let mut status = self + .status + .write() + .expect("could not acquire write lock on player status"); + *status = new_status; + } + + match new_status { + PlayerEvent::Paused(position, track_id) => { + self.set_elapsed(Some(position)); + self.set_since(None); + + self.send_event(SpotifyState { + state: PlayerState::Paused, + track_id: Some(track_id.to_base62()), + elapsed: Some(position), + since: None, + }); + } + PlayerEvent::Playing(playback_start, track_id) => { + self.set_since(Some(playback_start)); + self.set_elapsed(None); + + self.send_event(SpotifyState { + state: PlayerState::Playing, + track_id: Some(track_id.to_base62()), + elapsed: None, + since: Some(playback_start), + }); + } + PlayerEvent::Stopped | PlayerEvent::FinishedTrack => { + self.set_elapsed(None); + self.set_since(None); + + self.send_event(SpotifyState { + state: PlayerState::Stopped, + track_id: None, + elapsed: None, + since: None, + }); + } + } + } + + fn send_event(&mut self, event: SpotifyState) { + let mut index = 0; + while index < self.event_senders.len() { + match self.event_senders[index].send(event.clone()) { + Ok(_) => index += 1, + Err(_) => { + self.event_senders.remove(index); + } + } + } + } + + fn set_elapsed(&self, new_elapsed: Option) { + let mut elapsed = self + .elapsed + .write() + .expect("could not acquire write lock on elapsed time"); + *elapsed = new_elapsed; + } + + pub fn get_elapsed(&self) -> Option { + let elapsed = self + .elapsed + .read() + .expect("could not acquire read lock on elapsed time"); + *elapsed + } + + fn set_since(&self, new_since: Option) { + let mut since = self + .since + .write() + .expect("could not acquire write lock on since time"); + *since = new_since; + } + + pub fn get_since(&self) -> Option { + let since = self + .since + .read() + .expect("could not acquire read lock on since time"); + *since + } +}