Replace MpsMusicItem with general-purpose MpsItem and bump version to v0.3.0
This commit is contained in:
parent
9afda71f6a
commit
58cae6155c
33 changed files with 535 additions and 340 deletions
246
Cargo.lock
generated
246
Cargo.lock
generated
|
@ -94,15 +94,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.8.0"
|
||||
version = "3.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.7.2"
|
||||
version = "1.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
|
||||
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
@ -159,9 +159,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.0"
|
||||
version = "3.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9"
|
||||
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
|
@ -176,9 +176,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.0.0"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9"
|
||||
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
@ -195,9 +195,9 @@ checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688"
|
|||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.2"
|
||||
version = "4.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5"
|
||||
checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
|
@ -259,8 +259,18 @@ version = "0.10.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
"darling_core 0.10.2",
|
||||
"darling_macro 0.10.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
|
||||
dependencies = [
|
||||
"darling_core 0.13.1",
|
||||
"darling_macro 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -277,13 +287,38 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_core 0.10.2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
|
||||
dependencies = [
|
||||
"darling_core 0.13.1",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
@ -298,17 +333,6 @@ dependencies = [
|
|||
"libdbus-sys",
|
||||
]
|
||||
|
||||
[[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 = "dirs"
|
||||
version = "4.0.0"
|
||||
|
@ -352,9 +376,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.29"
|
||||
version = "0.8.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746"
|
||||
checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
@ -379,9 +403,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
@ -414,12 +438,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
|
@ -444,9 +465,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -492,9 +513,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.55"
|
||||
version = "0.3.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
|
||||
checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -524,9 +545,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.108"
|
||||
version = "0.2.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
||||
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
|
@ -539,9 +560,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
|
||||
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
|
@ -549,9 +570,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.23.1"
|
||||
version = "0.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2"
|
||||
checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
|
@ -634,7 +655,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mps"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"mps-interpreter",
|
||||
|
@ -643,7 +664,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mps-interpreter"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"regex",
|
||||
|
@ -654,7 +675,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mps-player"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"m3u8-rs",
|
||||
"mpris-player",
|
||||
|
@ -669,20 +690,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"ndk-sys 0.2.2",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.4.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c"
|
||||
checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"ndk-sys 0.3.0",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
]
|
||||
|
@ -697,22 +718,22 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"ndk 0.3.0",
|
||||
"ndk-macro",
|
||||
"ndk-sys",
|
||||
"ndk-macro 0.2.0",
|
||||
"ndk-sys 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-glue"
|
||||
version = "0.4.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420"
|
||||
checksum = "04c0d14b0858eb9962a5dac30b809b19f19da7e4547d64af2b0bb051d2e55d79"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"ndk 0.4.0",
|
||||
"ndk-macro",
|
||||
"ndk-sys",
|
||||
"ndk 0.6.0",
|
||||
"ndk-macro 0.3.0",
|
||||
"ndk-sys 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -721,19 +742,41 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"darling 0.10.2",
|
||||
"proc-macro-crate 0.1.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-macro"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
|
||||
dependencies = [
|
||||
"darling 0.13.1",
|
||||
"proc-macro-crate 1.1.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.20.0"
|
||||
|
@ -789,19 +832,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.4"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f"
|
||||
checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.4"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9"
|
||||
checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.1.0",
|
||||
"proc-macro2",
|
||||
|
@ -811,13 +853,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "oboe"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1"
|
||||
checksum = "2463c8f2e19b4e0d0710a21f8e4011501ff28db1c95d7a5482a553b2100502d2"
|
||||
dependencies = [
|
||||
"jni",
|
||||
"ndk 0.4.0",
|
||||
"ndk-glue 0.4.0",
|
||||
"ndk 0.6.0",
|
||||
"ndk-glue 0.6.0",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"oboe-sys",
|
||||
|
@ -825,9 +867,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "oboe-sys"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc"
|
||||
checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
@ -843,9 +885,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
|
@ -889,9 +931,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
|||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
|
@ -938,18 +980,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -1041,9 +1083,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
|
@ -1073,9 +1115,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
|
@ -1210,9 +1252,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "symphonia-format-wav"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da3586e944a951f3ff19ae14d3f46643c063784f119bffb091fc536102909575"
|
||||
checksum = "6d9fa5e5b420dea6763ba2547887eb1a02a142c676c5b02ed1b113a247101dad"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
|
@ -1243,9 +1285,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.82"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1311,12 +1353,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
|
@ -1331,9 +1367,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
|
@ -1354,9 +1390,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.78"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1364,9 +1400,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.78"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
|
||||
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
@ -1379,9 +1415,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.78"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
|
||||
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1389,9 +1425,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.78"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
|
||||
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1402,15 +1438,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.78"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
|
||||
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.55"
|
||||
version = "0.3.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
|
||||
checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "mps"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
||||
description = "Music Playlist Scripting language (MPS)"
|
||||
|
@ -15,14 +15,14 @@ members = [
|
|||
|
||||
[dependencies]
|
||||
# local
|
||||
mps-interpreter = { version = "0.2.0", path = "./mps-interpreter" }
|
||||
mps-interpreter = { version = "0.3.0", path = "./mps-interpreter" }
|
||||
# external
|
||||
clap = { version = "3.0", features = ["derive"] }
|
||||
# termios = { version = "^0.3"}
|
||||
|
||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||
mps-player = { version = "0.2.0", path = "./mps-player", default-features = false }
|
||||
mps-player = { version = "0.3.0", path = "./mps-player", default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
# TODO fix need to specify OS-specific dependency of mps-player
|
||||
mps-player = { version = "0.2.0", path = "./mps-player", features = ["mpris-player"] }
|
||||
mps-player = { version = "0.3.0", path = "./mps-player", features = ["mpris-player"] }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "mps-interpreter"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
license = "LGPL-2.1-only OR GPL-2.0-or-later"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::path::Path;
|
|||
use super::lang::{MpsLanguageDictionary, MpsLanguageError, MpsOp};
|
||||
use super::tokens::MpsToken;
|
||||
use super::MpsContext;
|
||||
use super::MpsMusicItem;
|
||||
use super::MpsItem;
|
||||
|
||||
/// The script interpreter.
|
||||
/// Use MpsRunner for a better interface.
|
||||
|
@ -81,7 +81,7 @@ impl<T> Iterator for MpsInterpretor<T>
|
|||
where
|
||||
T: crate::tokens::MpsTokenReader,
|
||||
{
|
||||
type Item = Result<MpsMusicItem, Box<dyn MpsLanguageError>>;
|
||||
type Item = Result<MpsItem, Box<dyn MpsLanguageError>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut is_stmt_done = false;
|
||||
|
|
58
mps-interpreter/src/item.rs
Normal file
58
mps-interpreter/src/item.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use crate::lang::MpsTypePrimitive;
|
||||
//use crate::lang::RuntimeError;
|
||||
//use crate::processing::OpGetter;
|
||||
|
||||
/// general type object for MPS
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MpsItem {
|
||||
fields: HashMap<String, MpsTypePrimitive>,
|
||||
}
|
||||
|
||||
impl MpsItem {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn field(&self, name: &str) -> Option<&MpsTypePrimitive> {
|
||||
self.fields.get(name)
|
||||
}
|
||||
|
||||
pub fn set_field(&mut self, name: &str, value: MpsTypePrimitive) -> Option<MpsTypePrimitive> {
|
||||
self.fields.insert(name.to_owned(), value)
|
||||
}
|
||||
|
||||
pub fn set_field_chain(&mut self, name: &str, value: MpsTypePrimitive) -> &mut Self {
|
||||
self.set_field(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_field(&mut self, name: &str) -> Option<MpsTypePrimitive> {
|
||||
self.fields.remove(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MpsItem {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "MpsItem[({} fields)]", self.fields.len())
|
||||
}
|
||||
}
|
||||
|
||||
/*pub(crate) trait MpsItemRuntimeUtil {
|
||||
fn get_field_runtime(&self, name: &str, op: &mut OpGetter) -> Result<&MpsTypePrimitive, RuntimeError>;
|
||||
}
|
||||
|
||||
impl MpsItemRuntimeUtil for MpsItem {
|
||||
fn get_field_runtime(&self, name: &str, op: &mut OpGetter) -> Result<&MpsTypePrimitive, RuntimeError> {
|
||||
match self.field(name) {
|
||||
Some(item) => Ok(item),
|
||||
None => Err(RuntimeError{
|
||||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Field {} not found on item", name),
|
||||
})
|
||||
}
|
||||
}
|
||||
}*/
|
|
@ -5,7 +5,7 @@ use std::marker::PhantomData;
|
|||
|
||||
use crate::lang::utility::{assert_token, assert_token_raw, check_name, assert_name};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp};
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::lang::SingleItem;
|
||||
use crate::lang::MpsFilterReplaceStatement;
|
||||
|
@ -13,14 +13,14 @@ use crate::processing::general::MpsType;
|
|||
use crate::processing::OpGetter;
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
const INNER_VARIABLE_NAME: &str = "[inner variable]";
|
||||
|
||||
pub trait MpsFilterPredicate: Clone + Debug + Display {
|
||||
fn matches(
|
||||
&mut self,
|
||||
item: &MpsMusicItem,
|
||||
item: &MpsItem,
|
||||
ctx: &mut MpsContext,
|
||||
op: &mut OpGetter,
|
||||
) -> Result<bool, RuntimeError>;
|
||||
|
@ -161,7 +161,7 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
|
|||
}
|
||||
|
||||
impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.predicate.is_complete() && self.other_filters.is_none() {
|
||||
|
@ -363,7 +363,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
if start_of_predicate > tokens_len - 1 {
|
||||
false
|
||||
} else {
|
||||
let pipe_location_opt = last_double_pipe(tokens, 1);
|
||||
let pipe_location_opt = first_double_pipe(tokens, 1);
|
||||
if pipe_location_opt.is_some() && pipe_location_opt.unwrap() > start_of_predicate {
|
||||
let pipe_location = pipe_location_opt.unwrap();
|
||||
// filters combined by OR operations
|
||||
|
@ -470,7 +470,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
}
|
||||
} else {
|
||||
let mut another_filter = None;
|
||||
let (has_or, end_tokens) = if let Some(pipe_location) = last_double_pipe(tokens, 1) {
|
||||
let (has_or, end_tokens) = if let Some(pipe_location) = first_double_pipe(tokens, 0) {
|
||||
(true, tokens.split_off(pipe_location)) // parse up to OR operator
|
||||
} else {
|
||||
(false, tokens.split_off(tokens.len()-1)) // don't parse closing bracket in filter
|
||||
|
@ -546,21 +546,21 @@ fn last_dot_before_open_bracket(tokens: &VecDeque<MpsToken>) -> usize {
|
|||
0
|
||||
}
|
||||
|
||||
fn last_double_pipe(tokens: &VecDeque<MpsToken>, in_brackets: usize) -> Option<usize> {
|
||||
fn first_double_pipe(tokens: &VecDeque<MpsToken>, in_brackets: usize) -> Option<usize> {
|
||||
let mut inside_brackets = 0;
|
||||
let mut pipe_found = false;
|
||||
for i in (0..tokens.len()).rev() {
|
||||
for i in 0..tokens.len() {
|
||||
if tokens[i].is_pipe() && inside_brackets == in_brackets {
|
||||
if pipe_found {
|
||||
return Some(i);
|
||||
return Some(i-1);
|
||||
} else {
|
||||
pipe_found = true;
|
||||
}
|
||||
} else {
|
||||
pipe_found = false;
|
||||
if tokens[i].is_close_bracket() {
|
||||
if tokens[i].is_open_bracket() {
|
||||
inside_brackets += 1;
|
||||
} else if tokens[i].is_open_bracket() && inside_brackets != 0 {
|
||||
} else if tokens[i].is_close_bracket() && inside_brackets != 0 {
|
||||
inside_brackets -= 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,20 @@ use std::collections::VecDeque;
|
|||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::{MpsOp, PseudoOp};
|
||||
use crate::lang::{MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::RuntimeError;
|
||||
use crate::lang::{MpsFilterPredicate, filter::VariableOrOp};
|
||||
use crate::lang::SingleItem;
|
||||
use crate::processing::general::MpsType;
|
||||
use crate::processing::OpGetter;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
const ITEM_VARIABLE_NAME: &str = "item";
|
||||
const ITEM_CACHE_DEFAULT_SIZE: usize = 8;
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn item_cache_deque() -> VecDeque<Result<MpsMusicItem, RuntimeError>> {
|
||||
pub(super) fn item_cache_deque() -> VecDeque<Result<MpsItem, RuntimeError>> {
|
||||
VecDeque::with_capacity(ITEM_CACHE_DEFAULT_SIZE)
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub struct MpsFilterReplaceStatement<P: MpsFilterPredicate + 'static> {
|
|||
pub(super) context: Option<MpsContext>,
|
||||
pub(super) op_if: PseudoOp,
|
||||
pub(super) op_else: Option<PseudoOp>,
|
||||
pub(super) item_cache: VecDeque<Result<MpsMusicItem, RuntimeError>>,
|
||||
pub(super) item_cache: VecDeque<Result<MpsItem, RuntimeError>>,
|
||||
}
|
||||
|
||||
impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterReplaceStatement<P> {
|
||||
|
@ -120,7 +120,7 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterReplaceStatement<P> {
|
|||
}
|
||||
|
||||
impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P> {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if !self.item_cache.is_empty() {
|
||||
|
|
|
@ -21,7 +21,7 @@ pub use filter::{
|
|||
pub use filter_replace::MpsFilterReplaceStatement;
|
||||
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||
pub use lookup::Lookup;
|
||||
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem};
|
||||
pub use pseudo_op::PseudoOp;
|
||||
pub use repeated_meme::{repeated_tokens, RepeatedTokens};
|
||||
pub use single_op::SingleItem;
|
||||
|
|
|
@ -7,7 +7,7 @@ use super::PseudoOp;
|
|||
use super::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
pub trait SimpleMpsOpFactory<T: MpsOp + 'static> {
|
||||
fn is_op_simple(&self, tokens: &VecDeque<MpsToken>) -> bool;
|
||||
|
@ -58,7 +58,9 @@ pub trait BoxedMpsOpFactory {
|
|||
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool;
|
||||
}
|
||||
|
||||
pub trait MpsOp: Iterator<Item = Result<MpsMusicItem, RuntimeError>> + Debug + Display {
|
||||
pub type MpsIteratorItem = Result<MpsItem, RuntimeError>;
|
||||
|
||||
pub trait MpsOp: Iterator<Item = MpsIteratorItem> + Debug + Display {
|
||||
fn enter(&mut self, ctx: MpsContext);
|
||||
|
||||
fn escape(&mut self) -> MpsContext;
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::{MpsOp, RuntimeError};
|
||||
use crate::lang::{MpsOp, RuntimeError, MpsIteratorItem};
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SingleItem {
|
||||
context: Option<MpsContext>,
|
||||
item: Result<MpsMusicItem, RuntimeError>,
|
||||
item: Result<MpsItem, RuntimeError>,
|
||||
is_complete: bool,
|
||||
}
|
||||
|
||||
impl SingleItem {
|
||||
pub fn new(item: Result<MpsMusicItem, RuntimeError>) -> Self {
|
||||
pub fn new(item: Result<MpsItem, RuntimeError>) -> Self {
|
||||
Self {
|
||||
context: None,
|
||||
item: item,
|
||||
|
@ -21,11 +21,11 @@ impl SingleItem {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_ok(item: MpsMusicItem) -> Self {
|
||||
pub fn new_ok(item: MpsItem) -> Self {
|
||||
Self::new(Ok(item))
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, new_item: Result<MpsMusicItem, RuntimeError>) {
|
||||
pub fn replace(&mut self, new_item: Result<MpsItem, RuntimeError>) {
|
||||
self.item = new_item
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ impl SingleItem {
|
|||
impl Display for SingleItem {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
match &self.item {
|
||||
Ok(item) => write!(f, "*single item*[Ok({})]", item.filename),
|
||||
Ok(item) => write!(f, "*single item*[Ok({})]", item),
|
||||
Err(e) => write!(f, "*single-item*[Err({})]", e)
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ impl std::clone::Clone for SingleItem {
|
|||
}
|
||||
|
||||
impl Iterator for SingleItem {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.is_complete {
|
||||
|
|
|
@ -74,6 +74,47 @@ impl MpsTypePrimitive {
|
|||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_str(self) -> Option<String> {
|
||||
match self {
|
||||
Self::String(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_u64(self) -> Option<u64> {
|
||||
match self {
|
||||
Self::UInt(x) => Some(x),
|
||||
Self::Int(x) => Some(x as _),
|
||||
Self::Float(x) => Some(x as _),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_i64(self) -> Option<i64> {
|
||||
match self {
|
||||
Self::UInt(x) => Some(x as _),
|
||||
Self::Int(x) => Some(x),
|
||||
Self::Float(x) => Some(x as _),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(s: String) -> Self {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
Self::Int(i)
|
||||
} else if let Ok(u) = s.parse::<u64>() {
|
||||
Self::UInt(u)
|
||||
} else if let Ok(f) = s.parse::<f64>() {
|
||||
Self::Float(f)
|
||||
} else if s == "false" {
|
||||
Self::Bool(false)
|
||||
} else if s == "true" {
|
||||
Self::Bool(true)
|
||||
} else {
|
||||
Self::String(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MpsTypePrimitive {
|
||||
|
@ -96,3 +137,33 @@ fn map_ordering(ordering: std::cmp::Ordering) -> i8 {
|
|||
std::cmp::Ordering::Greater => 1,
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<String> for MpsTypePrimitive {
|
||||
fn from(item: String) -> Self {
|
||||
Self::String(item)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<i64> for MpsTypePrimitive {
|
||||
fn from(item: i64) -> Self {
|
||||
Self::Int(item)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<u64> for MpsTypePrimitive {
|
||||
fn from(item: u64) -> Self {
|
||||
Self::UInt(item)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<f64> for MpsTypePrimitive {
|
||||
fn from(item: f64) -> Self {
|
||||
Self::Float(item)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<bool> for MpsTypePrimitive {
|
||||
fn from(item: bool) -> Self {
|
||||
Self::Bool(item)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@ use std::iter::Iterator;
|
|||
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem};
|
||||
use crate::lang::SyntaxError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommentStatement {
|
||||
|
@ -45,7 +44,7 @@ impl std::clone::Clone for CommentStatement {
|
|||
}
|
||||
|
||||
impl Iterator for CommentStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
None
|
||||
|
|
|
@ -4,12 +4,11 @@ use std::iter::Iterator;
|
|||
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
|
||||
use crate::lang::repeated_tokens;
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp};
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::processing::general::FileIter;
|
||||
|
||||
|
@ -65,7 +64,7 @@ impl std::clone::Clone for FilesStatement {
|
|||
}
|
||||
|
||||
impl Iterator for FilesStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.file_iter.is_none() {
|
||||
|
@ -87,7 +86,7 @@ impl Iterator for FilesStatement {
|
|||
});
|
||||
}
|
||||
match self.file_iter.as_mut().unwrap().next() {
|
||||
Some(Ok(item)) => Some(Ok(item)),
|
||||
Some(Ok(item)) => Some(Ok(item.into())),
|
||||
Some(Err(e)) => Some(Err(RuntimeError {
|
||||
line: 0,
|
||||
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::lang::{RuntimeError, SyntaxError};
|
|||
use crate::processing::OpGetter;
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EmptyFilter;
|
||||
|
@ -21,7 +21,7 @@ impl Display for EmptyFilter {
|
|||
impl MpsFilterPredicate for EmptyFilter {
|
||||
fn matches(
|
||||
&mut self,
|
||||
_item: &MpsMusicItem,
|
||||
_item: &MpsItem,
|
||||
_ctx: &mut MpsContext,
|
||||
_op: &mut OpGetter,
|
||||
) -> Result<bool, RuntimeError> {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use super::utility::{assert_comparison_operator, item_to_primitive_lut};
|
||||
use super::utility::assert_comparison_operator;
|
||||
use crate::lang::utility::{assert_token, assert_type, check_is_type};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::MpsTypePrimitive;
|
||||
|
@ -11,7 +11,7 @@ use crate::processing::general::MpsType;
|
|||
use crate::processing::OpGetter;
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) enum VariableOrValue {
|
||||
|
@ -61,11 +61,10 @@ impl Display for FieldFilter {
|
|||
impl MpsFilterPredicate for FieldFilter {
|
||||
fn matches(
|
||||
&mut self,
|
||||
item: &MpsMusicItem,
|
||||
music_item_lut: &MpsItem,
|
||||
ctx: &mut MpsContext,
|
||||
op: &mut OpGetter,
|
||||
) -> Result<bool, RuntimeError> {
|
||||
let music_item_lut = item_to_primitive_lut(item.to_owned());
|
||||
let variable = match &self.val {
|
||||
VariableOrValue::Variable(name) => match ctx.variables.get(&name, op)? {
|
||||
MpsType::Primitive(t) => Ok(t),
|
||||
|
@ -77,7 +76,7 @@ impl MpsFilterPredicate for FieldFilter {
|
|||
},
|
||||
VariableOrValue::Value(val) => Ok(val),
|
||||
}?;
|
||||
if let Some(field) = music_item_lut.get(&self.field_name) {
|
||||
if let Some(field) = music_item_lut.field(&self.field_name) {
|
||||
let compare_res = field.compare(variable);
|
||||
if let Err(e) = compare_res {
|
||||
match self.comparison_errors {
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::lang::{Lookup, utility::assert_token_raw};
|
|||
use crate::processing::{OpGetter, general::MpsType};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexFilter {
|
||||
|
@ -28,7 +28,7 @@ impl Display for IndexFilter {
|
|||
impl MpsFilterPredicate for IndexFilter {
|
||||
fn matches(
|
||||
&mut self,
|
||||
_item: &MpsMusicItem,
|
||||
_item: &MpsItem,
|
||||
ctx: &mut MpsContext,
|
||||
op: &mut OpGetter,
|
||||
) -> Result<bool, RuntimeError> {
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::lang::utility::assert_token_raw;
|
|||
use crate::processing::{OpGetter, general::MpsType};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RangeFilter {
|
||||
|
@ -33,7 +33,7 @@ impl Display for RangeFilter {
|
|||
impl MpsFilterPredicate for RangeFilter {
|
||||
fn matches(
|
||||
&mut self,
|
||||
_item: &MpsMusicItem,
|
||||
_item: &MpsItem,
|
||||
ctx: &mut MpsContext,
|
||||
op: &mut OpGetter,
|
||||
) -> Result<bool, RuntimeError> {
|
||||
|
|
|
@ -1,38 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::lang::utility::assert_token_raw;
|
||||
use crate::lang::MpsTypePrimitive;
|
||||
use crate::lang::SyntaxError;
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsMusicItem;
|
||||
|
||||
pub fn item_to_primitive_lut(item: MpsMusicItem) -> HashMap<String, MpsTypePrimitive> {
|
||||
let mut result = HashMap::new();
|
||||
result.insert("title".into(), MpsTypePrimitive::String(item.title));
|
||||
result.insert(
|
||||
"artist".into(),
|
||||
MpsTypePrimitive::String(item.artist.unwrap_or("".to_owned())),
|
||||
);
|
||||
result.insert(
|
||||
"album".into(),
|
||||
MpsTypePrimitive::String(item.album.unwrap_or("".to_owned())),
|
||||
);
|
||||
result.insert("filename".into(), MpsTypePrimitive::String(item.filename));
|
||||
result.insert(
|
||||
"genre".into(),
|
||||
MpsTypePrimitive::String(item.genre.unwrap_or("".to_owned())),
|
||||
);
|
||||
result.insert(
|
||||
"track".into(),
|
||||
MpsTypePrimitive::UInt(item.track.unwrap_or(0)),
|
||||
);
|
||||
result.insert(
|
||||
"year".into(),
|
||||
MpsTypePrimitive::UInt(item.year.unwrap_or(0)),
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn assert_comparison_operator(tokens: &mut VecDeque<MpsToken>) -> Result<[i8; 2], SyntaxError> {
|
||||
let token1 = tokens.pop_front().unwrap();
|
||||
|
|
|
@ -4,11 +4,11 @@ use std::iter::Iterator;
|
|||
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp};
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -16,7 +16,7 @@ pub struct RepeatStatement {
|
|||
inner_statement: PseudoOp,
|
||||
inner_done: bool,
|
||||
context: Option<MpsContext>,
|
||||
cache: Vec<MpsMusicItem>,
|
||||
cache: Vec<MpsItem>,
|
||||
cache_position: usize,
|
||||
repetitions: usize,
|
||||
loop_forever: bool,
|
||||
|
@ -49,7 +49,7 @@ impl std::clone::Clone for RepeatStatement {
|
|||
}
|
||||
|
||||
impl Iterator for RepeatStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let real_op = match self.inner_statement.try_real() {
|
||||
|
|
|
@ -5,13 +5,12 @@ use std::iter::Iterator;
|
|||
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
|
||||
use crate::lang::repeated_tokens;
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::SyntaxError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SqlInitStatement {
|
||||
|
@ -39,7 +38,7 @@ impl std::clone::Clone for SqlInitStatement {
|
|||
}
|
||||
|
||||
impl Iterator for SqlInitStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let pseudo_clone = self.clone();
|
||||
|
|
|
@ -3,23 +3,23 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
|||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp};
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
//use super::db::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SqlStatement {
|
||||
query: String,
|
||||
context: Option<MpsContext>,
|
||||
rows: Option<Vec<Result<MpsMusicItem, RuntimeError>>>,
|
||||
rows: Option<Vec<Result<MpsItem, RuntimeError>>>,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl SqlStatement {
|
||||
fn get_item(&mut self, increment: bool) -> Option<Result<MpsMusicItem, RuntimeError>> {
|
||||
fn get_item(&mut self, increment: bool) -> Option<MpsIteratorItem> {
|
||||
if let Some(rows) = &self.rows {
|
||||
if increment {
|
||||
if self.current == rows.len() {
|
||||
|
@ -32,7 +32,7 @@ impl SqlStatement {
|
|||
} else {
|
||||
//Some(rows[self.current].clone())
|
||||
match &rows[self.current] {
|
||||
Ok(item) => Some(Ok(item.clone())),
|
||||
Ok(item) => Some(Ok(item.clone().into())),
|
||||
Err(e) => Some(Err(RuntimeError {
|
||||
line: e.line,
|
||||
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
|
||||
|
@ -82,7 +82,7 @@ impl std::clone::Clone for SqlStatement {
|
|||
}
|
||||
|
||||
impl Iterator for SqlStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.rows.is_some() {
|
||||
|
|
|
@ -3,11 +3,11 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
|||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp};
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum QueryMode {
|
||||
|
@ -63,12 +63,12 @@ pub struct SimpleSqlStatement {
|
|||
query: String,
|
||||
mode: QueryMode,
|
||||
context: Option<MpsContext>,
|
||||
rows: Option<Vec<Result<MpsMusicItem, RuntimeError>>>,
|
||||
rows: Option<Vec<Result<MpsItem, RuntimeError>>>,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl SimpleSqlStatement {
|
||||
fn get_item(&mut self, increment: bool) -> Option<Result<MpsMusicItem, RuntimeError>> {
|
||||
fn get_item(&mut self, increment: bool) -> Option<MpsIteratorItem> {
|
||||
if let Some(rows) = &self.rows {
|
||||
if increment {
|
||||
if self.current == rows.len() {
|
||||
|
@ -81,7 +81,7 @@ impl SimpleSqlStatement {
|
|||
} else {
|
||||
//Some(rows[self.current].clone())
|
||||
match &rows[self.current] {
|
||||
Ok(item) => Some(Ok(item.clone())),
|
||||
Ok(item) => Some(Ok(item.clone().into())),
|
||||
Err(e) => Some(Err(RuntimeError {
|
||||
line: e.line,
|
||||
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
|
||||
|
@ -132,7 +132,7 @@ impl std::clone::Clone for SimpleSqlStatement {
|
|||
}
|
||||
|
||||
impl Iterator for SimpleSqlStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.rows.is_some() {
|
||||
|
|
|
@ -4,11 +4,10 @@ use std::iter::Iterator;
|
|||
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsMusicItem;
|
||||
|
||||
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp};
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::processing::general::MpsType;
|
||||
|
||||
|
@ -46,7 +45,7 @@ impl std::clone::Clone for AssignStatement {
|
|||
}
|
||||
|
||||
impl Iterator for AssignStatement {
|
||||
type Item = Result<MpsMusicItem, RuntimeError>;
|
||||
type Item = MpsIteratorItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(inner_statement) = &mut self.inner_statement {
|
||||
|
|
|
@ -125,17 +125,20 @@
|
|||
|
||||
mod context;
|
||||
mod interpretor;
|
||||
mod item;
|
||||
pub mod lang;
|
||||
#[cfg(feature = "music_library")]
|
||||
pub mod music;
|
||||
mod music_item;
|
||||
//mod music_item;
|
||||
pub mod processing;
|
||||
mod runner;
|
||||
pub mod tokens;
|
||||
|
||||
pub use context::MpsContext;
|
||||
pub use interpretor::{interpretor, MpsInterpretor};
|
||||
pub use music_item::MpsMusicItem;
|
||||
pub use item::MpsItem;
|
||||
//pub(crate) use item::MpsItemRuntimeUtil;
|
||||
//pub use music_item::MpsMusicItem;
|
||||
pub use runner::MpsRunner;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::lang::db::{
|
||||
DatabaseObj, DbAlbumItem, DbArtistItem, DbGenreItem, DbMetaItem, DbMusicItem,
|
||||
};
|
||||
use super::MpsItem;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MpsMusicItem {
|
||||
|
@ -45,3 +46,35 @@ impl MpsMusicItem {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<MpsItem> for MpsMusicItem {
|
||||
fn from(mut item: MpsItem) -> Self {
|
||||
let default_str = "".to_string();
|
||||
Self {
|
||||
title: item.remove_field("title").and_then(|x| x.to_str()).unwrap_or(default_str.clone()),
|
||||
artist: item.remove_field("artist").and_then(|x| x.to_str()),
|
||||
album: item.remove_field("album").and_then(|x| x.to_str()),
|
||||
filename: item.remove_field("filename").and_then(|x| x.to_str()).unwrap_or(default_str),
|
||||
genre: item.remove_field("genre").and_then(|x| x.to_str()),
|
||||
track: item.remove_field("track").and_then(|x| x.to_u64()),
|
||||
year: item.remove_field("year").and_then(|x| x.to_u64()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::Into<MpsItem> for MpsMusicItem {
|
||||
fn into(self) -> MpsItem {
|
||||
let mut result = MpsItem::new();
|
||||
result.set_field("title", self.title.into());
|
||||
result.set_field("filename", self.filename.into());
|
||||
|
||||
if let Some(artist) = self.artist {result.set_field("artist", artist.into());}
|
||||
if let Some(album) = self.album {result.set_field("album", album.into());}
|
||||
if let Some(genre) = self.genre {result.set_field("genre", genre.into());}
|
||||
|
||||
if let Some(track) = self.track {result.set_field("track", track.into());}
|
||||
if let Some(year) = self.year {result.set_field("year", year.into());}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ use std::path::{Path, PathBuf};
|
|||
use regex::Regex;
|
||||
|
||||
use super::OpGetter;
|
||||
use crate::lang::RuntimeError;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::lang::{RuntimeError, MpsTypePrimitive};
|
||||
use crate::MpsItem;
|
||||
|
||||
const DEFAULT_REGEX: &str = r"/(?P<artist>[^/]+)/(?P<album>[^/]+)/(?:(?:(?P<disc>\d+)\s+)?(?P<track>\d+)\.?\s+)?(?P<title>[^/]+)\.(?P<format>(?:mp3)|(?:wav)|(?:ogg)|(?:flac)|(?:mp4)|(?:aac))$";
|
||||
|
||||
|
@ -127,7 +127,7 @@ impl FileIter {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_item<P: AsRef<Path>>(&self, filepath: P) -> Option<MpsMusicItem> {
|
||||
fn build_item<P: AsRef<Path>>(&self, filepath: P) -> Option<MpsItem> {
|
||||
let path = filepath.as_ref();
|
||||
let path_str = path.to_str()?;
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -135,8 +135,9 @@ impl FileIter {
|
|||
panic!("Got non-file path `{}` when building music item", path_str)
|
||||
}
|
||||
let captures = self.pattern.captures(path_str)?;
|
||||
let capture_names = self.pattern.capture_names();
|
||||
// populate fields
|
||||
self.populate_item_impl(path, path_str, captures)
|
||||
self.populate_item_impl(path, path_str, captures, capture_names)
|
||||
}
|
||||
|
||||
#[cfg(feature = "music_library")]
|
||||
|
@ -145,105 +146,90 @@ impl FileIter {
|
|||
path: &Path,
|
||||
path_str: &str,
|
||||
captures: regex::Captures,
|
||||
) -> Option<MpsMusicItem> {
|
||||
capture_names: regex::CaptureNames,
|
||||
) -> Option<MpsItem> {
|
||||
match crate::music::MpsLibrary::read_media_tags(path) {
|
||||
Ok(tags) => Some(MpsMusicItem {
|
||||
title: captures
|
||||
.name("title")
|
||||
.and_then(|m| Some(m.as_str().to_string()))
|
||||
.unwrap_or_else(|| tags.track_title()),
|
||||
artist: captures
|
||||
.name("artist")
|
||||
.and_then(|m| Some(m.as_str().to_string()))
|
||||
.or_else(|| tags.artist_name()),
|
||||
album: captures
|
||||
.name("album")
|
||||
.and_then(|m| Some(m.as_str().to_string()))
|
||||
.or_else(|| tags.album_title()),
|
||||
filename: path_str.to_string(),
|
||||
genre: captures
|
||||
.name("genre")
|
||||
.and_then(|m| Some(m.as_str().to_string()))
|
||||
.or_else(|| tags.genre_title()),
|
||||
track: match captures.name("track") {
|
||||
None => tags.track_number(),
|
||||
Some(m) => match m.as_str().parse::<u64>() {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => tags.track_number(),
|
||||
Ok(tags) => {
|
||||
let mut item = MpsItem::new();
|
||||
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
|
||||
if item.field("title").is_none() {
|
||||
item.set_field("title", tags.track_title().into());
|
||||
}
|
||||
if item.field("artist").is_none() {
|
||||
if let Some(artist) = tags.artist_name() {
|
||||
item.set_field("artist", artist.into());
|
||||
}
|
||||
}
|
||||
if item.field("album").is_none() {
|
||||
if let Some(album) = tags.album_title() {
|
||||
item.set_field("album", album.into());
|
||||
}
|
||||
}
|
||||
if item.field("genre").is_none() {
|
||||
if let Some(genre) = tags.genre_title() {
|
||||
item.set_field("genre", genre.into());
|
||||
}
|
||||
}
|
||||
if item.field("track").is_none() {
|
||||
if let Some(track) = tags.track_number() {
|
||||
item.set_field("track", track.into());
|
||||
}
|
||||
}
|
||||
if item.field("year").is_none() {
|
||||
if let Some(year) = tags.track_date() {
|
||||
item.set_field("year", year.into());
|
||||
}
|
||||
}
|
||||
Some(item)
|
||||
},
|
||||
Err(_) => {
|
||||
let mut item = MpsItem::new();
|
||||
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
|
||||
Some(item)
|
||||
},
|
||||
year: match captures.name("year") {
|
||||
None => tags.track_date(),
|
||||
Some(m) => match m.as_str().parse::<u64>() {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => tags.track_date(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
Err(_) => self.populate_item_impl_simple(path, path_str, captures),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "music_library"))]
|
||||
fn populate_item_impl(
|
||||
&self,
|
||||
path: &Path,
|
||||
path_str: &str,
|
||||
captures: regex::Captures,
|
||||
) -> Option<MpsMusicItem> {
|
||||
self.populate_item_impl_simple(path, path_str, captures)
|
||||
capture_names: regex::CaptureNames,
|
||||
) -> Option<MpsItem> {
|
||||
let mut item = MpsItem::new();
|
||||
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
|
||||
Some(item)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn populate_item_impl_simple(
|
||||
&self,
|
||||
path: &Path,
|
||||
item: &mut MpsItem,
|
||||
path_str: &str,
|
||||
captures: regex::Captures,
|
||||
) -> Option<MpsMusicItem> {
|
||||
Some(MpsMusicItem {
|
||||
title: captures
|
||||
.name("title")
|
||||
.and_then(|m| Some(m.as_str().to_string()))
|
||||
.unwrap_or_else(|| Self::default_title(path)),
|
||||
artist: captures
|
||||
.name("artist")
|
||||
.and_then(|m| Some(m.as_str().to_string())),
|
||||
album: captures
|
||||
.name("album")
|
||||
.and_then(|m| Some(m.as_str().to_string())),
|
||||
filename: path_str.to_string(),
|
||||
genre: captures
|
||||
.name("genre")
|
||||
.and_then(|m| Some(m.as_str().to_string())),
|
||||
track: match captures.name("track") {
|
||||
None => None,
|
||||
Some(m) => match m.as_str().parse::<u64>() {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => None,
|
||||
},
|
||||
},
|
||||
year: match captures.name("year") {
|
||||
None => None,
|
||||
Some(m) => match m.as_str().parse::<u64>() {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => None,
|
||||
},
|
||||
},
|
||||
})
|
||||
mut capture_names: regex::CaptureNames,
|
||||
) {
|
||||
// populates fields from named capture groups
|
||||
while let Some(Some(name)) = capture_names.next() {
|
||||
if let Some(value) = captures.name(name).and_then(|m| Some(m.as_str().to_string())) {
|
||||
item.set_field(name, MpsTypePrimitive::parse(value));
|
||||
}
|
||||
}
|
||||
item.set_field("filename", path_str.to_string().into());
|
||||
}
|
||||
|
||||
fn default_title(path: &Path) -> String {
|
||||
/*fn default_title(path: &Path) -> String {
|
||||
let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
|
||||
path.file_name()
|
||||
.and_then(|file| file.to_str())
|
||||
.and_then(|file| Some(file.replacen(&format!(".{}", extension), "", 1)))
|
||||
.unwrap_or("Unknown Title".into())
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
impl Iterator for FileIter {
|
||||
type Item = Result<MpsMusicItem, String>;
|
||||
type Item = Result<MpsItem, String>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.is_complete {
|
||||
|
|
|
@ -3,11 +3,11 @@ use std::collections::{HashMap, HashSet};
|
|||
|
||||
use crate::lang::db::*;
|
||||
use crate::lang::RuntimeError;
|
||||
use crate::MpsMusicItem;
|
||||
use crate::MpsItem;
|
||||
|
||||
use super::OpGetter as QueryOp;
|
||||
|
||||
pub type QueryResult = Result<Vec<Result<MpsMusicItem, RuntimeError>>, RuntimeError>;
|
||||
pub type QueryResult = Result<Vec<Result<MpsItem, RuntimeError>>, RuntimeError>;
|
||||
|
||||
/// SQL querying functionality, loosely de-coupled from any specific SQL dialect (excluding raw call)
|
||||
pub trait MpsDatabaseQuerier: Debug {
|
||||
|
@ -250,7 +250,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings {
|
|||
let music_path = self
|
||||
.music_path
|
||||
.and_then(|p| Some(std::path::PathBuf::from(p)))
|
||||
.unwrap_or_else(|| crate::lang::utility::music_folder());
|
||||
.unwrap_or_else(crate::lang::utility::music_folder);
|
||||
let sqlite_path = self
|
||||
.db_path
|
||||
.unwrap_or_else(|| crate::lang::db::DEFAULT_SQLITE_FILEPATH.to_string());
|
||||
|
@ -262,7 +262,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings {
|
|||
fn build_mps_item(
|
||||
conn: &mut rusqlite::Connection,
|
||||
item: DbMusicItem,
|
||||
) -> rusqlite::Result<MpsMusicItem> {
|
||||
) -> rusqlite::Result<MpsItem> {
|
||||
// query artist
|
||||
let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?;
|
||||
let artist = stmt.query_row([item.artist], DbArtistItem::map_row)?;
|
||||
|
@ -276,14 +276,14 @@ fn build_mps_item(
|
|||
let mut stmt = conn.prepare_cached("SELECT * from genres WHERE genre_id = ?")?;
|
||||
let genre = stmt.query_row([item.genre], DbGenreItem::map_row)?;
|
||||
|
||||
Ok(MpsMusicItem::merge(item, artist, album, meta, genre))
|
||||
Ok(rows_to_item(item, artist, album, meta, genre))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn perform_query(
|
||||
conn: &mut rusqlite::Connection,
|
||||
query: &str,
|
||||
) -> Result<Vec<rusqlite::Result<MpsMusicItem>>, String> {
|
||||
) -> Result<Vec<rusqlite::Result<MpsItem>>, String> {
|
||||
let collection: Vec<rusqlite::Result<DbMusicItem>>;
|
||||
{
|
||||
let mut stmt = conn
|
||||
|
@ -306,7 +306,7 @@ fn perform_single_param_query(
|
|||
conn: &mut rusqlite::Connection,
|
||||
query: &str,
|
||||
param: &str,
|
||||
) -> Result<Vec<rusqlite::Result<MpsMusicItem>>, String> {
|
||||
) -> Result<Vec<rusqlite::Result<MpsItem>>, String> {
|
||||
let collection: Vec<rusqlite::Result<DbMusicItem>>;
|
||||
{
|
||||
let mut stmt = conn
|
||||
|
@ -323,3 +323,28 @@ fn perform_single_param_query(
|
|||
});
|
||||
Ok(iter2.collect())
|
||||
}
|
||||
|
||||
fn rows_to_item(
|
||||
music: DbMusicItem,
|
||||
artist: DbArtistItem,
|
||||
album: DbAlbumItem,
|
||||
meta: DbMetaItem,
|
||||
genre: DbGenreItem,
|
||||
) -> MpsItem {
|
||||
|
||||
let mut item = MpsItem::new();
|
||||
item
|
||||
// music row
|
||||
.set_field_chain("title", music.title.into())
|
||||
.set_field_chain("filename", music.filename.into())
|
||||
// artist row
|
||||
.set_field_chain("artist", artist.name.into())
|
||||
// album row
|
||||
.set_field_chain("album", album.title.into())
|
||||
// genre row
|
||||
.set_field_chain("genre", genre.title.into())
|
||||
// music metadata
|
||||
.set_field_chain("track", meta.track.into())
|
||||
.set_field_chain("year", meta.date.into());
|
||||
item
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::iter::Iterator;
|
|||
|
||||
use super::lang::{MpsLanguageDictionary, MpsLanguageError};
|
||||
use super::tokens::{MpsTokenReader, MpsTokenizer};
|
||||
use super::{MpsContext, MpsInterpretor, MpsMusicItem};
|
||||
use super::{MpsContext, MpsInterpretor, MpsItem};
|
||||
|
||||
pub struct MpsRunnerSettings<T: MpsTokenReader> {
|
||||
pub vocabulary: MpsLanguageDictionary,
|
||||
|
@ -57,7 +57,7 @@ impl<R: Read> MpsRunner<MpsTokenizer<R>> {
|
|||
}
|
||||
|
||||
impl<T: MpsTokenReader> Iterator for MpsRunner<T> {
|
||||
type Item = Result<MpsMusicItem, Box<dyn MpsLanguageError>>;
|
||||
type Item = Result<MpsItem, Box<dyn MpsLanguageError>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut item = self.interpretor.next();
|
||||
|
|
|
@ -62,7 +62,10 @@ fn execute_single_line(
|
|||
break;
|
||||
}
|
||||
} // no need to spam the rest of the songs
|
||||
println!("Got song `{}` (file: `{}`)", item.title, item.filename);
|
||||
println!("Got song `{}` (file: `{}`)",
|
||||
item.field("title").expect("Expected field `title` to exist").clone().to_str().expect("Expected field `title` to be String"),
|
||||
item.field("filename").expect("Expected field `filename` to exist").clone().to_str().expect("Expected field `filename` to be String")
|
||||
);
|
||||
} else {
|
||||
println!("!!! Got error while iterating (executing) !!!");
|
||||
eprintln!("{}", result.as_ref().err().unwrap());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "mps-player"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
license = "LGPL-2.1-only OR GPL-2.0-or-later"
|
||||
readme = "README.md"
|
||||
|
@ -10,7 +10,7 @@ rodio = { version = "^0.14"}
|
|||
m3u8-rs = { version = "^3.0.0" }
|
||||
|
||||
# local
|
||||
mps-interpreter = { path = "../mps-interpreter", version = "0.2.0" }
|
||||
mps-interpreter = { path = "../mps-interpreter", version = "0.3.0" }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
#dbus = { version = "^0.9" }
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::thread::JoinHandle;
|
|||
use mpris_player::{MprisPlayer, PlaybackStatus, Metadata};
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls"))]
|
||||
use mps_interpreter::MpsMusicItem;
|
||||
use mps_interpreter::MpsItem;
|
||||
|
||||
//use super::MpsController;
|
||||
use super::player_wrapper::{ControlAction, PlaybackAction};
|
||||
|
@ -177,20 +177,20 @@ impl SystemControlWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
fn enqueued(item: MpsMusicItem, dbus_ctrl: &Sender<DbusControl>) {
|
||||
fn enqueued(item: MpsItem, dbus_ctrl: &Sender<DbusControl>) {
|
||||
//println!("Got enqueued item {}", &item.title);
|
||||
dbus_ctrl.send(DbusControl::SetMetadata(Metadata {
|
||||
length: None,
|
||||
art_url: None,
|
||||
album: item.album,
|
||||
album: item.field("album").and_then(|x| x.to_owned().to_str()),
|
||||
album_artist: None, // TODO maybe?
|
||||
artist: item.artist.map(|artist| vec![artist]),
|
||||
artist: item.field("artist").and_then(|x| x.to_owned().to_str()).map(|x| vec![x]),
|
||||
composer: None,
|
||||
disc_number: None,
|
||||
genre: item.genre.map(|genre| vec![genre]),
|
||||
title: Some(item.title),
|
||||
track_number: item.track.map(|track| track as i32),
|
||||
url: Some(item.filename),
|
||||
genre: item.field("genre").and_then(|x| x.to_owned().to_str()).map(|genre| vec![genre]),
|
||||
title: item.field("title").and_then(|x| x.to_owned().to_str()),
|
||||
track_number: item.field("track").and_then(|x| x.to_owned().to_i64()).map(|track| track as i32),
|
||||
url: item.field("filename").and_then(|x| x.to_owned().to_str()),
|
||||
})).unwrap_or(());
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
|
|||
|
||||
use m3u8_rs::{MediaPlaylist, MediaSegment};
|
||||
|
||||
use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsMusicItem};
|
||||
use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsItem};
|
||||
|
||||
use super::PlaybackError;
|
||||
|
||||
|
@ -36,12 +36,15 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
self.sink.sleep_until_end();
|
||||
match item {
|
||||
Ok(music) => {
|
||||
let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?;
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||
let stream = io::BufReader::new(file);
|
||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||
self.sink.append(source);
|
||||
//self.sink.play(); // idk if this is necessary
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
}?;
|
||||
|
@ -50,18 +53,21 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enqueue_all(&mut self) -> Result<Vec<MpsMusicItem>, PlaybackError> {
|
||||
pub fn enqueue_all(&mut self) -> Result<Vec<MpsItem>, PlaybackError> {
|
||||
let mut enqueued = Vec::new();
|
||||
for item in &mut self.runner {
|
||||
match item {
|
||||
Ok(music) => {
|
||||
enqueued.push(music.clone());
|
||||
let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?;
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||
let stream = io::BufReader::new(file);
|
||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||
self.sink.append(source);
|
||||
//self.sink.play(); // idk if this is necessary
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
}?;
|
||||
|
@ -69,7 +75,7 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
Ok(enqueued)
|
||||
}
|
||||
|
||||
pub fn enqueue(&mut self, count: usize) -> Result<Vec<MpsMusicItem>, PlaybackError> {
|
||||
pub fn enqueue(&mut self, count: usize) -> Result<Vec<MpsItem>, PlaybackError> {
|
||||
let mut items_left = count;
|
||||
let mut enqueued = Vec::with_capacity(count);
|
||||
if items_left == 0 {
|
||||
|
@ -79,12 +85,15 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
match item {
|
||||
Ok(music) => {
|
||||
enqueued.push(music.clone());
|
||||
let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?;
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||
let stream = io::BufReader::new(file);
|
||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||
self.sink.append(source);
|
||||
//self.sink.play(); // idk if this is necessary
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
}?;
|
||||
|
@ -130,12 +139,16 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
for item in &mut self.runner {
|
||||
match item {
|
||||
Ok(music) => {
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
playlist.segments.push(MediaSegment {
|
||||
uri: music.filename,
|
||||
title: Some(music.title),
|
||||
uri: filename,
|
||||
title: music.field("title").and_then(|x| x.to_owned().to_str()),
|
||||
..Default::default()
|
||||
});
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
}?;
|
||||
|
@ -173,7 +186,7 @@ mod tests {
|
|||
use std::io;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[test]
|
||||
//#[test]
|
||||
fn play_cursor() -> Result<(), PlaybackError> {
|
||||
let cursor = io::Cursor::new("sql(`SELECT * FROM songs JOIN artists ON songs.artist = artists.artist_id WHERE artists.name like 'thundercat'`);");
|
||||
let runner = MpsRunner::with_stream(cursor);
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::mpsc::{Receiver, Sender};
|
|||
use std::{thread, thread::JoinHandle};
|
||||
|
||||
use mps_interpreter::tokens::MpsTokenReader;
|
||||
use mps_interpreter::MpsMusicItem;
|
||||
use mps_interpreter::MpsItem;
|
||||
|
||||
use super::MpsPlayer;
|
||||
use super::PlaybackError;
|
||||
|
@ -215,7 +215,7 @@ pub enum PlayerAction {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum PlaybackAction {
|
||||
Empty,
|
||||
Enqueued(MpsMusicItem),
|
||||
Enqueued(MpsItem),
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue