Add m3u8 loading function syntax -- playlist(filepath)
This commit is contained in:
parent
7b92c340ee
commit
d264b84c90
12 changed files with 718 additions and 316 deletions
462
Cargo.lock
generated
462
Cargo.lock
generated
|
@ -97,6 +97,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.59.2"
|
version = "0.59.2"
|
||||||
|
@ -168,7 +174,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
"symphonia 0.5.0",
|
"symphonia",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -440,27 +446,27 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpal"
|
name = "cpal"
|
||||||
version = "0.13.5"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116"
|
checksum = "7d466b47cf0ea4100186a7c12d7d0166813dda7cf648553554c9c39c6324841b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alsa",
|
"alsa",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"coreaudio-rs",
|
"coreaudio-rs",
|
||||||
"jni",
|
"jni",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"libc",
|
"libc",
|
||||||
"mach",
|
"mach",
|
||||||
"ndk",
|
"ndk 0.7.0",
|
||||||
"ndk-glue",
|
"ndk-context",
|
||||||
"nix",
|
"nix",
|
||||||
"oboe",
|
"oboe",
|
||||||
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"stdweb",
|
"stdweb",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi 0.3.9",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -610,39 +616,10 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "cty"
|
||||||
version = "0.13.4"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"darling_macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_core"
|
|
||||||
version = "0.13.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
|
|
||||||
dependencies = [
|
|
||||||
"fnv",
|
|
||||||
"ident_case",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"strsim 0.10.0",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_macro"
|
|
||||||
version = "0.13.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dbus"
|
name = "dbus"
|
||||||
|
@ -814,12 +791,6 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs_extra"
|
name = "fs_extra"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -939,12 +910,6 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ident_case"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
|
@ -955,15 +920,6 @@ dependencies = [
|
||||||
"hashbrown 0.12.2",
|
"hashbrown 0.12.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instant"
|
|
||||||
version = "0.1.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.3"
|
version = "0.10.3"
|
||||||
|
@ -1258,16 +1214,18 @@ dependencies = [
|
||||||
name = "muss-interpreter"
|
name = "muss-interpreter"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"bliss-audio-symphonia",
|
"bliss-audio-symphonia",
|
||||||
"criterion",
|
"criterion",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"m3u8-rs",
|
||||||
"mpd",
|
"mpd",
|
||||||
"rand",
|
"rand",
|
||||||
"regex 1.6.0",
|
"regex 1.6.0",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
"sqlparser",
|
"sqlparser",
|
||||||
"symphonia 0.5.0",
|
"symphonia",
|
||||||
"unidecode",
|
"unidecode",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1343,45 +1301,31 @@ checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"ndk-sys",
|
"ndk-sys 0.3.0",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndk"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"jni-sys",
|
||||||
|
"ndk-sys 0.4.0",
|
||||||
|
"num_enum",
|
||||||
|
"raw-window-handle",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk-context"
|
name = "ndk-context"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ndk-glue"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"ndk",
|
|
||||||
"ndk-context",
|
|
||||||
"ndk-macro",
|
|
||||||
"ndk-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ndk-macro"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
|
|
||||||
dependencies = [
|
|
||||||
"darling",
|
|
||||||
"proc-macro-crate",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk-sys"
|
name = "ndk-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -1391,6 +1335,15 @@ dependencies = [
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndk-sys"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21d83ec9c63ec5bf950200a8e508bdad6659972187b625469f58ef8c08e29046"
|
||||||
|
dependencies = [
|
||||||
|
"jni-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.23.1"
|
version = "0.23.1"
|
||||||
|
@ -1542,7 +1495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1"
|
checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jni",
|
"jni",
|
||||||
"ndk",
|
"ndk 0.6.0",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
@ -1608,27 +1561,25 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.2"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"instant",
|
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.8.5"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"instant",
|
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"winapi 0.3.9",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1836,6 +1787,15 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "raw-window-handle"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a"
|
||||||
|
dependencies = [
|
||||||
|
"cty",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rawpointer"
|
name = "rawpointer"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1947,16 +1907,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rodio"
|
name = "rodio"
|
||||||
version = "0.15.0"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e"
|
checksum = "eb10b653d5ec0e9411a2e7d46e2c7f4046fd87d35b9955bd73ba4108d69072b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"claxon",
|
"claxon",
|
||||||
"cpal",
|
"cpal",
|
||||||
"hound",
|
"hound",
|
||||||
"lewton",
|
"lewton",
|
||||||
"minimp3",
|
"minimp3",
|
||||||
"symphonia 0.4.0",
|
"symphonia",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2157,25 +2117,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a7e5f38aa07e792f4eebb0faa93cee088ec82c48222dd332897aae1569d9a4b7"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"symphonia-bundle-flac 0.4.0",
|
|
||||||
"symphonia-bundle-mp3 0.4.0",
|
|
||||||
"symphonia-codec-aac 0.4.0",
|
|
||||||
"symphonia-codec-pcm 0.4.0",
|
|
||||||
"symphonia-codec-vorbis 0.4.0",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-format-isomp4 0.4.0",
|
|
||||||
"symphonia-format-ogg 0.4.0",
|
|
||||||
"symphonia-format-wav 0.4.1",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "symphonia"
|
name = "symphonia"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -2183,30 +2124,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb30457ee7a904dae1e4ace25156dcabaf71e425db318e7885267f09cd8fb648"
|
checksum = "eb30457ee7a904dae1e4ace25156dcabaf71e425db318e7885267f09cd8fb648"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
"symphonia-bundle-flac 0.5.0",
|
"symphonia-bundle-flac",
|
||||||
"symphonia-bundle-mp3 0.5.0",
|
"symphonia-bundle-mp3",
|
||||||
"symphonia-codec-aac 0.5.0",
|
"symphonia-codec-aac",
|
||||||
"symphonia-codec-alac",
|
"symphonia-codec-alac",
|
||||||
"symphonia-codec-pcm 0.5.0",
|
"symphonia-codec-pcm",
|
||||||
"symphonia-codec-vorbis 0.5.0",
|
"symphonia-codec-vorbis",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-format-isomp4 0.5.0",
|
"symphonia-format-isomp4",
|
||||||
"symphonia-format-mkv",
|
"symphonia-format-mkv",
|
||||||
"symphonia-format-ogg 0.5.0",
|
"symphonia-format-ogg",
|
||||||
"symphonia-format-wav 0.5.0",
|
"symphonia-format-wav",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-bundle-flac"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "116e5412f5fb4e5d07efd6628d50d6fcd7a61ebef43d98f5012f3cf763b25d02"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
"symphonia-utils-xiph 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2216,22 +2145,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f34f8f90825ee2692df0ee64981312267d6cf640358c3db7a4805d1805340665"
|
checksum = "f34f8f90825ee2692df0ee64981312267d6cf640358c3db7a4805d1805340665"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
"symphonia-utils-xiph 0.5.0",
|
"symphonia-utils-xiph",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-bundle-mp3"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec4d97c4a61ece4651751dddb393ebecb7579169d9e758ae808fe507a5250790"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2243,19 +2159,8 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-codec-aac"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd3d7ab37eb9b7df16ddedd7adb7cc382afe708ff078e525a14dc9b05e57558f"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2266,7 +2171,7 @@ checksum = "96671dbcf83a4415e899812c5820dd26f48b9a6fece8b8d680e3004553080468"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2276,17 +2181,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a95d0cc9d94c55d9467e71e26990e509bd5a602fabde3ee422d87f77bbda860a"
|
checksum = "a95d0cc9d94c55d9467e71e26990e509bd5a602fabde3ee422d87f77bbda860a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-codec-pcm"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba1d54738758993546107e3a4be2c1da827f2d4489fcffee0fa47867254e44c7"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2296,18 +2191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0812a197602dff1f963ff212f174c4aa4d9b695d6511ba7a8fe2470296cf8310"
|
checksum = "0812a197602dff1f963ff212f174c4aa4d9b695d6511ba7a8fe2470296cf8310"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-codec-vorbis"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a29ed6748078effb35a05064a451493a78038918981dc1a76bdf5a2752d441fa"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-utils-xiph 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2317,21 +2201,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "746fc459966b37e277565f9632e5ffd6cbd83d9381152727123f68484cb8f9c4"
|
checksum = "746fc459966b37e277565f9632e5ffd6cbd83d9381152727123f68484cb8f9c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-utils-xiph 0.5.0",
|
"symphonia-utils-xiph",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-core"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa135e97be0f4a666c31dfe5ef4c75435ba3d355fd6a73d2100aa79b14c104c9"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
"bitflags",
|
|
||||||
"bytemuck",
|
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"log",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2347,18 +2218,6 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-format-isomp4"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "feee3a7711e7ec1b7540756f3868bbb3cbb0d1195569b9bc26471a24a02f57b5"
|
|
||||||
dependencies = [
|
|
||||||
"encoding_rs",
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "symphonia-format-isomp4"
|
name = "symphonia-format-isomp4"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -2367,9 +2226,9 @@ checksum = "2a335816c1840bf3ce92b968a93b7b5c14a5d74737ad9ed63567ea451eac1951"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
"symphonia-utils-xiph 0.5.0",
|
"symphonia-utils-xiph",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2380,21 +2239,9 @@ checksum = "901a52e62285b3794a3ecb9b8a00b1d92d639e0dabf51eac0823a16493752726"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
"symphonia-utils-xiph 0.5.0",
|
"symphonia-utils-xiph",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-format-ogg"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d7b2357288a79adfec532cfd86049696cfa5c58efeff83bd51687a528f18a519"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
"symphonia-utils-xiph 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2404,20 +2251,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00f5b92a2a6370873d9dbe3326dad1bf795b3151efcadca6e5f47d732499a518"
|
checksum = "00f5b92a2a6370873d9dbe3326dad1bf795b3151efcadca6e5f47d732499a518"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
"symphonia-utils-xiph 0.5.0",
|
"symphonia-utils-xiph",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-format-wav"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d9fa5e5b420dea6763ba2547887eb1a02a142c676c5b02ed1b113a247101dad"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2427,20 +2263,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "66b2016576a9f7e5e95f9354993116458170a9077845a908ee67a4c81e8072c0"
|
checksum = "66b2016576a9f7e5e95f9354993116458170a9077845a908ee67a4c81e8072c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-metadata"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5260599daba18d8fe905ca3eb3b42ba210529a6276886632412cc74984e79b1a"
|
|
||||||
dependencies = [
|
|
||||||
"encoding_rs",
|
|
||||||
"lazy_static 1.4.0",
|
|
||||||
"log",
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2452,17 +2276,7 @@ dependencies = [
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
"log",
|
"log",
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symphonia-utils-xiph"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a37026c6948ff842e0bf94b4008579cc71ab16ed0ff9ca70a331f60f4f1e1e9"
|
|
||||||
dependencies = [
|
|
||||||
"symphonia-core 0.4.0",
|
|
||||||
"symphonia-metadata 0.4.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2471,8 +2285,8 @@ version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abadfa53359fa437836f2554a0019dd06bfdf742fbb735d0645db3b6c5a763e0"
|
checksum = "abadfa53359fa437836f2554a0019dd06bfdf742fbb735d0645db3b6c5a763e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"symphonia-core 0.5.0",
|
"symphonia-core",
|
||||||
"symphonia-metadata 0.5.0",
|
"symphonia-metadata",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2813,6 +2627,92 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.37.0",
|
||||||
|
"windows_i686_gnu 0.37.0",
|
||||||
|
"windows_i686_msvc 0.37.0",
|
||||||
|
"windows_x86_64_gnu 0.37.0",
|
||||||
|
"windows_x86_64_msvc 0.37.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.36.1",
|
||||||
|
"windows_i686_gnu 0.36.1",
|
||||||
|
"windows_i686_msvc 0.36.1",
|
||||||
|
"windows_x86_64_gnu 0.36.1",
|
||||||
|
"windows_x86_64_msvc 0.36.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "0.5.13"
|
version = "0.5.13"
|
||||||
|
|
|
@ -19,6 +19,8 @@ shellexpand = { version = "2", optional = true }
|
||||||
bliss-audio-symphonia = { version = "0.5", optional = true, path = "../bliss-rs" }
|
bliss-audio-symphonia = { version = "0.5", optional = true, path = "../bliss-rs" }
|
||||||
mpd = { version = "0.0.12", optional = true }
|
mpd = { version = "0.0.12", optional = true }
|
||||||
unidecode = { version = "0.3.0", optional = true }
|
unidecode = { version = "0.3.0", optional = true }
|
||||||
|
base64 = { version = "0.13", optional = true }
|
||||||
|
m3u8-rs = { version = "3.0.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
|
@ -28,10 +30,11 @@ name = "file_parse"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "music_library", "ergonomics", "advanced", "advanced-bliss", "fakesql" ]
|
default = [ "music_library", "ergonomics", "advanced", "advanced-bliss", "fakesql", "collections" ]
|
||||||
music_library = [ "symphonia", "mpd" ] # song metadata parsing and database auto-population
|
music_library = [ "symphonia", "mpd", "base64" ] # song metadata parsing and database auto-population
|
||||||
|
collections = [ "m3u8-rs" ] # read from m3u8 playlists (and other song collections, eventually)
|
||||||
ergonomics = ["shellexpand", "unidecode"] # niceties like ~ in paths and unicode string sanitisation
|
ergonomics = ["shellexpand", "unidecode"] # niceties like ~ in paths and unicode string sanitisation
|
||||||
advanced = [] # advanced language features like music analysis
|
advanced = [] # advanced language features like music analysis
|
||||||
advanced-bliss = ["bliss-audio-symphonia"] # bliss audio analysis
|
advanced-bliss = ["bliss-audio-symphonia"] # bliss audio analysis
|
||||||
sql = [ "rusqlite" ]
|
sql = [ "rusqlite" ] # sqlite database for music
|
||||||
fakesql = [ "sqlparser" ]
|
fakesql = [ "sqlparser" ] # transpiled sqlite interpreter
|
||||||
|
|
|
@ -54,6 +54,7 @@ pub(crate) fn standard_vocab(vocabulary: &mut LanguageDictionary) {
|
||||||
.add(crate::lang::vocabulary::AssignStatementFactory)
|
.add(crate::lang::vocabulary::AssignStatementFactory)
|
||||||
.add(crate::lang::vocabulary::sql_init_function_factory())
|
.add(crate::lang::vocabulary::sql_init_function_factory())
|
||||||
.add(crate::lang::vocabulary::files_function_factory())
|
.add(crate::lang::vocabulary::files_function_factory())
|
||||||
|
.add(crate::lang::vocabulary::playlist_function_factory())
|
||||||
.add(crate::lang::vocabulary::empty_function_factory())
|
.add(crate::lang::vocabulary::empty_function_factory())
|
||||||
.add(crate::lang::vocabulary::empties_function_factory())
|
.add(crate::lang::vocabulary::empties_function_factory())
|
||||||
.add(crate::lang::vocabulary::reset_function_factory())
|
.add(crate::lang::vocabulary::reset_function_factory())
|
||||||
|
|
78
interpreter/src/lang/generator_op.rs
Normal file
78
interpreter/src/lang/generator_op.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::iter::Iterator;
|
||||||
|
|
||||||
|
use crate::lang::{IteratorItem, Op, RuntimeError};
|
||||||
|
use crate::lang::{RuntimeOp, RuntimeMsg, PseudoOp};
|
||||||
|
use crate::Context;
|
||||||
|
use crate::Item;
|
||||||
|
|
||||||
|
pub struct GeneratorOp {
|
||||||
|
context: Option<Context>,
|
||||||
|
generator: Box<dyn FnMut(&mut Context) -> Option<Result<Item, RuntimeMsg>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeneratorOp {
|
||||||
|
pub fn new<F: FnMut(&mut Context) -> Option<Result<Item, RuntimeMsg>> + 'static>(generator_fn: F) -> Self {
|
||||||
|
Self {
|
||||||
|
context: None,
|
||||||
|
generator: Box::new(generator_fn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for GeneratorOp {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
write!(f, "*generator*[...]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for GeneratorOp {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
f.debug_struct("GeneratorOp")
|
||||||
|
.field("context", &self.context)
|
||||||
|
.field("generator", &"<boxed function>")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for GeneratorOp {
|
||||||
|
type Item = IteratorItem;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ctx = self.context.as_mut().unwrap();
|
||||||
|
match (self.generator)(ctx) {
|
||||||
|
Some(Err(e)) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
||||||
|
Some(Ok(item)) => Some(Ok(item)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Op for GeneratorOp {
|
||||||
|
fn enter(&mut self, ctx: Context) {
|
||||||
|
self.context = Some(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escape(&mut self) -> Context {
|
||||||
|
self.context.take().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_resetable(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) -> Result<(), RuntimeError> {
|
||||||
|
Err(
|
||||||
|
RuntimeMsg("Cannot reset generator op".to_string())
|
||||||
|
.with(RuntimeOp(PseudoOp::from_printable(self)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dup(&self) -> Box<dyn Op> {
|
||||||
|
// this shouldn't be called
|
||||||
|
Box::new(Self {
|
||||||
|
context: None,
|
||||||
|
generator: Box::new(|_| None)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ mod error;
|
||||||
mod filter;
|
mod filter;
|
||||||
mod filter_replace;
|
mod filter_replace;
|
||||||
mod function;
|
mod function;
|
||||||
|
mod generator_op;
|
||||||
mod iter_block;
|
mod iter_block;
|
||||||
mod lookup;
|
mod lookup;
|
||||||
mod operation;
|
mod operation;
|
||||||
|
@ -25,6 +26,7 @@ pub use error::{RuntimeError, RuntimeMsg, RuntimeOp, SyntaxError};
|
||||||
pub use filter::{FilterFactory, FilterPredicate, FilterStatement, FilterStatementFactory};
|
pub use filter::{FilterFactory, FilterPredicate, FilterStatement, FilterStatementFactory};
|
||||||
pub use filter_replace::FilterReplaceStatement;
|
pub use filter_replace::FilterReplaceStatement;
|
||||||
pub use function::{FunctionFactory, FunctionStatementFactory};
|
pub use function::{FunctionFactory, FunctionStatementFactory};
|
||||||
|
pub use generator_op::GeneratorOp;
|
||||||
pub use iter_block::{ItemBlockFactory, ItemOp, ItemOpFactory};
|
pub use iter_block::{ItemBlockFactory, ItemOp, ItemOpFactory};
|
||||||
pub use lookup::Lookup;
|
pub use lookup::Lookup;
|
||||||
pub use operation::{BoxedOpFactory, IteratorItem, Op, OpFactory, SimpleOpFactory};
|
pub use operation::{BoxedOpFactory, IteratorItem, Op, OpFactory, SimpleOpFactory};
|
||||||
|
|
|
@ -87,7 +87,7 @@ impl Iterator for FilesStatement {
|
||||||
Some(Ok(item)) => Some(Ok(item)),
|
Some(Ok(item)) => Some(Ok(item)),
|
||||||
Some(Err(e)) => Some(Err(RuntimeError {
|
Some(Err(e)) => Some(Err(RuntimeError {
|
||||||
line: 0,
|
line: 0,
|
||||||
op: (Box::new(self.clone()) as Box<dyn Op>).into(),
|
op: PseudoOp::from_printable(self),
|
||||||
msg: e,
|
msg: e,
|
||||||
})),
|
})),
|
||||||
None => None,
|
None => None,
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub(crate) mod empty;
|
||||||
mod files;
|
mod files;
|
||||||
mod intersection;
|
mod intersection;
|
||||||
mod mpd_query;
|
mod mpd_query;
|
||||||
|
mod playlist;
|
||||||
mod repeat;
|
mod repeat;
|
||||||
mod reset;
|
mod reset;
|
||||||
mod sql_init;
|
mod sql_init;
|
||||||
|
@ -17,6 +18,7 @@ pub use empty::{empty_function_factory, EmptyStatementFactory};
|
||||||
pub use files::{files_function_factory, FilesStatementFactory};
|
pub use files::{files_function_factory, FilesStatementFactory};
|
||||||
pub use intersection::{intersection_function_factory, IntersectionStatementFactory};
|
pub use intersection::{intersection_function_factory, IntersectionStatementFactory};
|
||||||
pub use mpd_query::{mpd_query_function_factory, MpdQueryStatementFactory};
|
pub use mpd_query::{mpd_query_function_factory, MpdQueryStatementFactory};
|
||||||
|
pub use playlist::{playlist_function_factory, PlaylistStatementFactory};
|
||||||
pub use repeat::{repeat_function_factory, RepeatStatementFactory};
|
pub use repeat::{repeat_function_factory, RepeatStatementFactory};
|
||||||
pub use reset::{reset_function_factory, ResetStatementFactory};
|
pub use reset::{reset_function_factory, ResetStatementFactory};
|
||||||
pub use sql_init::{sql_init_function_factory, SqlInitStatementFactory};
|
pub use sql_init::{sql_init_function_factory, SqlInitStatementFactory};
|
||||||
|
|
153
interpreter/src/lang/vocabulary/playlist.rs
Normal file
153
interpreter/src/lang/vocabulary/playlist.rs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::iter::Iterator;
|
||||||
|
|
||||||
|
use crate::tokens::Token;
|
||||||
|
use crate::Context;
|
||||||
|
|
||||||
|
use crate::lang::LanguageDictionary;
|
||||||
|
use crate::lang::{FunctionFactory, FunctionStatementFactory, IteratorItem, Op, GeneratorOp};
|
||||||
|
use crate::lang::{PseudoOp, RuntimeError, RuntimeOp, SyntaxError, Lookup, TypePrimitive};
|
||||||
|
//use crate::processing::general::FileIter;
|
||||||
|
use crate::processing::general::Type;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PlaylistStatement {
|
||||||
|
context: Option<Context>,
|
||||||
|
// function params
|
||||||
|
file: Lookup,
|
||||||
|
// state
|
||||||
|
playlist_iter: Option<GeneratorOp>,
|
||||||
|
has_tried: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PlaylistStatement {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
write!(f, "playlist({})", self.file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::clone::Clone for PlaylistStatement {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
context: None,
|
||||||
|
file: self.file.clone(),
|
||||||
|
playlist_iter: None,
|
||||||
|
has_tried: self.has_tried,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for PlaylistStatement {
|
||||||
|
type Item = IteratorItem;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.playlist_iter.is_none() {
|
||||||
|
if self.has_tried {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
self.has_tried = true;
|
||||||
|
}
|
||||||
|
let ctx = self.context.as_mut().unwrap();
|
||||||
|
let file = match self.file.get(ctx) {
|
||||||
|
Ok(Type::Primitive(TypePrimitive::String(s))) => s.to_owned(),
|
||||||
|
Ok(x) => return Some(Err(
|
||||||
|
RuntimeError {
|
||||||
|
msg: format!("Cannot use {} as filepath", x),
|
||||||
|
line: 0,
|
||||||
|
op: PseudoOp::from_printable(self),
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
Err(e) => return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
||||||
|
};
|
||||||
|
let iter = ctx.filesystem.read_file(&file);
|
||||||
|
self.playlist_iter = Some(match iter {
|
||||||
|
Ok(mut x) => {
|
||||||
|
x.enter(self.context.take().unwrap());
|
||||||
|
x
|
||||||
|
},
|
||||||
|
Err(e) => return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
match self.playlist_iter.as_mut().unwrap().next() {
|
||||||
|
Some(Ok(item)) => Some(Ok(item)),
|
||||||
|
Some(Err(e)) => Some(Err(e)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.playlist_iter
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.size_hint())
|
||||||
|
.unwrap_or((0, None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Op for PlaylistStatement {
|
||||||
|
fn enter(&mut self, ctx: Context) {
|
||||||
|
if let Some(playlist) = &mut self.playlist_iter {
|
||||||
|
playlist.enter(ctx);
|
||||||
|
} else {
|
||||||
|
self.context = Some(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escape(&mut self) -> Context {
|
||||||
|
if let Some(playlist) = &mut self.playlist_iter {
|
||||||
|
playlist.escape()
|
||||||
|
} else {
|
||||||
|
self.context.take().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_resetable(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) -> Result<(), RuntimeError> {
|
||||||
|
self.has_tried = false;
|
||||||
|
if let Some(playlist) = &mut self.playlist_iter {
|
||||||
|
self.context = Some(playlist.escape());
|
||||||
|
}
|
||||||
|
self.playlist_iter = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dup(&self) -> Box<dyn Op> {
|
||||||
|
let mut clone = self.clone();
|
||||||
|
clone.reset().unwrap();
|
||||||
|
Box::new(clone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PlaylistFunctionFactory;
|
||||||
|
|
||||||
|
impl FunctionFactory<PlaylistStatement> for PlaylistFunctionFactory {
|
||||||
|
fn is_function(&self, name: &str) -> bool {
|
||||||
|
name == "playlist"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_function_params(
|
||||||
|
&self,
|
||||||
|
_name: String,
|
||||||
|
tokens: &mut VecDeque<Token>,
|
||||||
|
_dict: &LanguageDictionary,
|
||||||
|
) -> Result<PlaylistStatement, SyntaxError> {
|
||||||
|
// playlist(filepath)
|
||||||
|
let filepath_lookup = Lookup::parse(tokens)?;
|
||||||
|
Ok(PlaylistStatement {
|
||||||
|
context: None,
|
||||||
|
file: filepath_lookup,
|
||||||
|
playlist_iter: None,
|
||||||
|
has_tried: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PlaylistStatementFactory = FunctionStatementFactory<PlaylistStatement, PlaylistFunctionFactory>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn playlist_function_factory() -> PlaylistStatementFactory {
|
||||||
|
PlaylistStatementFactory::new(PlaylistFunctionFactory)
|
||||||
|
}
|
|
@ -145,14 +145,22 @@ impl Library {
|
||||||
if let Some(rev) = metadata.current() {
|
if let Some(rev) = metadata.current() {
|
||||||
for tag in rev.tags() {
|
for tag in rev.tags() {
|
||||||
//println!("(pre) metadata tag ({},{})", tag.key, tag.value);
|
//println!("(pre) metadata tag ({},{})", tag.key, tag.value);
|
||||||
tags.add(tag.key.clone(), &tag.value);
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
for vis in rev.visuals() {
|
||||||
|
//println!("Got visual for song `{}`", path.display());
|
||||||
|
tags.add_visual(vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(rev) = probed.format.metadata().current() {
|
if let Some(rev) = probed.format.metadata().current() {
|
||||||
for tag in rev.tags() {
|
for tag in rev.tags() {
|
||||||
//println!("(post) metadata tag ({},{})", tag.key, tag.value);
|
//println!("(post) metadata tag ({},{})", tag.key, tag.value);
|
||||||
tags.add(tag.key.clone(), &tag.value);
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
for vis in rev.visuals() {
|
||||||
|
//println!("Got visual for song `{}`", path.display());
|
||||||
|
tags.add_visual(vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,14 +186,22 @@ impl Library {
|
||||||
if let Some(rev) = metadata.current() {
|
if let Some(rev) = metadata.current() {
|
||||||
for tag in rev.tags() {
|
for tag in rev.tags() {
|
||||||
//println!("(pre) metadata tag ({},{})", tag.key, tag.value);
|
//println!("(pre) metadata tag ({},{})", tag.key, tag.value);
|
||||||
tags.add(tag.key.clone(), &tag.value);
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
for vis in rev.visuals() {
|
||||||
|
//println!("Got visual for song `{}`", path.display());
|
||||||
|
tags.add_visual(vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(rev) = probed.format.metadata().current() {
|
if let Some(rev) = probed.format.metadata().current() {
|
||||||
for tag in rev.tags() {
|
for tag in rev.tags() {
|
||||||
//println!("(post) metadata tag ({},{})", tag.key, tag.value);
|
//println!("(post) metadata tag ({},{})", tag.key, tag.value);
|
||||||
tags.add(tag.key.clone(), &tag.value);
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
for vis in rev.visuals() {
|
||||||
|
//println!("Got visual for song `{}`", path.display());
|
||||||
|
tags.add_visual(vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.generate_entries(&tags);
|
self.generate_entries(&tags);
|
||||||
|
|
|
@ -1,15 +1,134 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use symphonia::core::meta::Value;
|
use symphonia::core::meta::{Value, Visual, Tag, StandardTagKey};
|
||||||
|
|
||||||
use crate::lang::db::*;
|
use crate::lang::db::*;
|
||||||
|
|
||||||
|
const BASE64_CONF: base64::Config = base64::Config::new(base64::CharacterSet::Standard, false);
|
||||||
|
|
||||||
pub struct Tags {
|
pub struct Tags {
|
||||||
data: HashMap<String, TagType>,
|
data: HashMap<String, TagType>,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn std_tag_to_str(key: StandardTagKey) -> &'static str {
|
||||||
|
match key {
|
||||||
|
StandardTagKey::AcoustidFingerprint => "acoustid_fingerprint",
|
||||||
|
StandardTagKey::AcoustidId => "acoustid_id",
|
||||||
|
StandardTagKey::Album => "album",
|
||||||
|
StandardTagKey::AlbumArtist => "albumartist",
|
||||||
|
StandardTagKey::Arranger => "arranger",
|
||||||
|
StandardTagKey::Artist => "artist",
|
||||||
|
StandardTagKey::Bpm => "bpm",
|
||||||
|
StandardTagKey::Comment => "comment",
|
||||||
|
StandardTagKey::Compilation => "compilation",
|
||||||
|
StandardTagKey::Composer => "composer",
|
||||||
|
StandardTagKey::Conductor => "conductor",
|
||||||
|
StandardTagKey::ContentGroup => "contentgroup",
|
||||||
|
StandardTagKey::Copyright => "copyright",
|
||||||
|
StandardTagKey::Date => "date",
|
||||||
|
StandardTagKey::Description => "description",
|
||||||
|
StandardTagKey::DiscNumber => "disc",
|
||||||
|
StandardTagKey::DiscSubtitle => "disc_subtitle",
|
||||||
|
StandardTagKey::DiscTotal => "disc_total",
|
||||||
|
StandardTagKey::EncodedBy => "encoded_by",
|
||||||
|
StandardTagKey::Encoder => "encoder",
|
||||||
|
StandardTagKey::EncoderSettings => "encoder_settings",
|
||||||
|
StandardTagKey::EncodingDate => "encoding_date",
|
||||||
|
StandardTagKey::Engineer => "engineer",
|
||||||
|
StandardTagKey::Ensemble => "ensemble",
|
||||||
|
StandardTagKey::Genre => "genre",
|
||||||
|
StandardTagKey::IdentAsin => "ident_asin",
|
||||||
|
StandardTagKey::IdentBarcode => "ident_barcode",
|
||||||
|
StandardTagKey::IdentCatalogNumber => "ident_catalog_number",
|
||||||
|
StandardTagKey::IdentEanUpn => "ident_ean_upn",
|
||||||
|
StandardTagKey::IdentIsrc => "ident_isrc",
|
||||||
|
StandardTagKey::IdentPn => "ident_pn",
|
||||||
|
StandardTagKey::IdentPodcast => "ident_podcast",
|
||||||
|
StandardTagKey::IdentUpc => "ident_upc",
|
||||||
|
StandardTagKey::Label => "label",
|
||||||
|
StandardTagKey::Language => "language",
|
||||||
|
StandardTagKey::License => "license",
|
||||||
|
StandardTagKey::Lyricist => "lyricist",
|
||||||
|
StandardTagKey::Lyrics => "lyrics",
|
||||||
|
StandardTagKey::MediaFormat => "mediaformat",
|
||||||
|
StandardTagKey::MixDj => "mixdj",
|
||||||
|
StandardTagKey::MixEngineer => "mix_engineer",
|
||||||
|
StandardTagKey::Mood => "mood",
|
||||||
|
StandardTagKey::MovementName => "movement_name",
|
||||||
|
StandardTagKey::MovementNumber => "movement_number",
|
||||||
|
StandardTagKey::MusicBrainzAlbumArtistId => "MusicBrainz_albumartist_id",
|
||||||
|
StandardTagKey::MusicBrainzAlbumId => "MusicBrainz_album_id",
|
||||||
|
StandardTagKey::MusicBrainzArtistId => "MusicBrainz_artist_id",
|
||||||
|
StandardTagKey::MusicBrainzDiscId => "MusicBrainz_disc_id",
|
||||||
|
StandardTagKey::MusicBrainzGenreId => "MusicBrainz_genre_id",
|
||||||
|
StandardTagKey::MusicBrainzLabelId => "MusicBrainz_label_id",
|
||||||
|
StandardTagKey::MusicBrainzOriginalAlbumId => "MusicBrainz_original_album_id",
|
||||||
|
StandardTagKey::MusicBrainzOriginalArtistId => "MusicBrainz_original_artist_id",
|
||||||
|
StandardTagKey::MusicBrainzRecordingId => "MusicBrainz_recording_id",
|
||||||
|
StandardTagKey::MusicBrainzReleaseGroupId => "MusicBrainz_release_group_id",
|
||||||
|
StandardTagKey::MusicBrainzReleaseStatus => "MusicBrainz_release_status",
|
||||||
|
StandardTagKey::MusicBrainzReleaseTrackId => "MusicBrainz_release_track_id",
|
||||||
|
StandardTagKey::MusicBrainzReleaseType => "MusicBrainz_release_type",
|
||||||
|
StandardTagKey::MusicBrainzTrackId => "MusicBrainz_track_id",
|
||||||
|
StandardTagKey::MusicBrainzWorkId => "MusicBrainz_work_id",
|
||||||
|
StandardTagKey::Opus => "Opus",
|
||||||
|
StandardTagKey::OriginalAlbum => "original_album",
|
||||||
|
StandardTagKey::OriginalArtist => "original_artist",
|
||||||
|
StandardTagKey::OriginalDate => "original_date",
|
||||||
|
StandardTagKey::OriginalFile => "original_file",
|
||||||
|
StandardTagKey::OriginalWriter => "original_writer",
|
||||||
|
StandardTagKey::Owner => "owner",
|
||||||
|
StandardTagKey::Part => "part",
|
||||||
|
StandardTagKey::PartTotal => "part_total",
|
||||||
|
StandardTagKey::Performer => "performer",
|
||||||
|
StandardTagKey::Podcast => "podcast",
|
||||||
|
StandardTagKey::PodcastCategory => "podcast_category",
|
||||||
|
StandardTagKey::PodcastDescription => "podcast_description",
|
||||||
|
StandardTagKey::PodcastKeywords => "podcast_keywords",
|
||||||
|
StandardTagKey::Producer => "producer",
|
||||||
|
StandardTagKey::PurchaseDate => "purchase_date",
|
||||||
|
StandardTagKey::Rating => "rating",
|
||||||
|
StandardTagKey::ReleaseCountry => "release_country",
|
||||||
|
StandardTagKey::ReleaseDate => "release_date",
|
||||||
|
StandardTagKey::Remixer => "remixer",
|
||||||
|
StandardTagKey::ReplayGainAlbumGain => "ReplayGain_album_gain",
|
||||||
|
StandardTagKey::ReplayGainAlbumPeak => "ReplayGain_album_peak",
|
||||||
|
StandardTagKey::ReplayGainTrackGain => "ReplayGain_track_gain",
|
||||||
|
StandardTagKey::ReplayGainTrackPeak => "ReplayGain_track_peak",
|
||||||
|
StandardTagKey::Script => "script",
|
||||||
|
StandardTagKey::SortAlbum => "sort_album",
|
||||||
|
StandardTagKey::SortAlbumArtist => "sort_albumartist",
|
||||||
|
StandardTagKey::SortArtist => "sort_artist",
|
||||||
|
StandardTagKey::SortComposer => "sort_composer",
|
||||||
|
StandardTagKey::SortTrackTitle => "sort_title",
|
||||||
|
StandardTagKey::TaggingDate => "tagging_date",
|
||||||
|
StandardTagKey::TrackNumber => "track",
|
||||||
|
StandardTagKey::TrackSubtitle => "track_subtitle",
|
||||||
|
StandardTagKey::TrackTitle => "title",
|
||||||
|
StandardTagKey::TrackTotal => "track_total",
|
||||||
|
StandardTagKey::TvEpisode => "tv_episode",
|
||||||
|
StandardTagKey::TvEpisodeTitle => "tv_episode_title",
|
||||||
|
StandardTagKey::TvNetwork => "tv_network",
|
||||||
|
StandardTagKey::TvSeason => "tv_season",
|
||||||
|
StandardTagKey::TvShowTitle => "tv_show_title",
|
||||||
|
StandardTagKey::Url => "url",
|
||||||
|
StandardTagKey::UrlArtist => "url_artist",
|
||||||
|
StandardTagKey::UrlCopyright => "url_copyright",
|
||||||
|
StandardTagKey::UrlInternetRadio => "url_internet_radio",
|
||||||
|
StandardTagKey::UrlLabel => "url_label",
|
||||||
|
StandardTagKey::UrlOfficial => "url_official",
|
||||||
|
StandardTagKey::UrlPayment => "url_payment",
|
||||||
|
StandardTagKey::UrlPodcast => "url_podcast",
|
||||||
|
StandardTagKey::UrlPurchase => "url_purchase",
|
||||||
|
StandardTagKey::UrlSource => "url_source",
|
||||||
|
StandardTagKey::Version => "version",
|
||||||
|
StandardTagKey::Writer => "writer",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Tags {
|
impl Tags {
|
||||||
pub fn new<P: AsRef<Path>>(path: P) -> Self {
|
pub fn new<P: AsRef<Path>>(path: P) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -18,9 +137,21 @@ impl Tags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, key: String, value: &Value) {
|
pub fn add(&mut self, tag: &Tag) {
|
||||||
|
let key = if let Some(std_key) = tag.std_key {
|
||||||
|
std_tag_to_str(std_key).to_owned()
|
||||||
|
} else {
|
||||||
|
tag.key.clone()
|
||||||
|
};
|
||||||
|
let value = &tag.value;
|
||||||
if let Some(tag_type) = TagType::from_symphonia_value(value) {
|
if let Some(tag_type) = TagType::from_symphonia_value(value) {
|
||||||
self.data.insert(key.trim().to_uppercase(), tag_type);
|
self.data.insert(key.trim().to_lowercase(), tag_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_visual(&mut self, visual: &Visual) {
|
||||||
|
if let Some(tag_type) = TagType::from_symphonia_visual(visual) {
|
||||||
|
self.data.insert("cover".to_owned(), tag_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +162,7 @@ impl Tags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn track_title(&self) -> String {
|
pub fn track_title(&self) -> String {
|
||||||
self.data
|
self.data
|
||||||
.get("TITLE")
|
.get(std_tag_to_str(StandardTagKey::TrackTitle))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.str()
|
.str()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
|
@ -55,7 +186,7 @@ impl Tags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn artist_name(&self) -> Option<String> {
|
pub fn artist_name(&self) -> Option<String> {
|
||||||
self.data
|
self.data
|
||||||
.get("ARTIST")
|
.get(std_tag_to_str(StandardTagKey::Artist))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.str()
|
.str()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
|
@ -64,7 +195,7 @@ impl Tags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn album_title(&self) -> Option<String> {
|
pub fn album_title(&self) -> Option<String> {
|
||||||
self.data
|
self.data
|
||||||
.get("ALBUM")
|
.get(std_tag_to_str(StandardTagKey::Album))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.str()
|
.str()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
|
@ -73,7 +204,7 @@ impl Tags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn albumartist_name(&self) -> Option<String> {
|
pub fn albumartist_name(&self) -> Option<String> {
|
||||||
self.data
|
self.data
|
||||||
.get("ALBUMARTIST")
|
.get(std_tag_to_str(StandardTagKey::AlbumArtist))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.str()
|
.str()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
|
@ -82,7 +213,7 @@ impl Tags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn genre_title(&self) -> Option<String> {
|
pub fn genre_title(&self) -> Option<String> {
|
||||||
self.data
|
self.data
|
||||||
.get("GENRE")
|
.get(std_tag_to_str(StandardTagKey::Genre))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.str()
|
.str()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
|
@ -91,14 +222,26 @@ impl Tags {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn track_number(&self) -> Option<u64> {
|
pub fn track_number(&self) -> Option<u64> {
|
||||||
self.data
|
self.data
|
||||||
.get("TRACKNUMBER")
|
.get(std_tag_to_str(StandardTagKey::TrackNumber))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn cover_art(&self) -> Option<String> {
|
||||||
|
self.data
|
||||||
|
.get("cover")
|
||||||
|
.unwrap_or(&TagType::Unknown)
|
||||||
|
.str()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn track_date(&self) -> Option<u64> {
|
pub fn track_date(&self) -> Option<u64> {
|
||||||
self.data.get("DATE").unwrap_or(&TagType::Unknown).uint()
|
self.data
|
||||||
|
.get(std_tag_to_str(StandardTagKey::Date))
|
||||||
|
.unwrap_or(&TagType::Unknown)
|
||||||
|
.uint()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn song(
|
pub fn song(
|
||||||
|
@ -125,20 +268,20 @@ impl Tags {
|
||||||
meta_id: id,
|
meta_id: id,
|
||||||
plays: self
|
plays: self
|
||||||
.data
|
.data
|
||||||
.get("PLAYS")
|
.get("plays")
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
track: self.track_number().unwrap_or(id),
|
track: self.track_number().unwrap_or(id),
|
||||||
disc: self
|
disc: self
|
||||||
.data
|
.data
|
||||||
.get("DISCNUMBER")
|
.get(std_tag_to_str(StandardTagKey::DiscNumber))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(1),
|
.unwrap_or(1),
|
||||||
duration: self
|
duration: self
|
||||||
.data
|
.data
|
||||||
.get("DURATION")
|
.get("duration")
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
|
@ -159,13 +302,8 @@ impl Tags {
|
||||||
pub fn album_artist(&self, id: u64, genre_id: u64) -> DbArtistItem {
|
pub fn album_artist(&self, id: u64, genre_id: u64) -> DbArtistItem {
|
||||||
DbArtistItem {
|
DbArtistItem {
|
||||||
artist_id: id,
|
artist_id: id,
|
||||||
name: self
|
name: self.albumartist_name()
|
||||||
.data
|
.unwrap_or("Unknown Artist".into()),
|
||||||
.get("ALBUMARTIST")
|
|
||||||
.unwrap_or(&TagType::Unknown)
|
|
||||||
.str()
|
|
||||||
.unwrap_or("Unknown Artist")
|
|
||||||
.into(),
|
|
||||||
genre: genre_id,
|
genre: genre_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,26 +323,26 @@ impl Tags {
|
||||||
meta_id: id,
|
meta_id: id,
|
||||||
plays: self
|
plays: self
|
||||||
.data
|
.data
|
||||||
.get("PLAYS")
|
.get("plays")
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
track: self
|
track: self
|
||||||
.data
|
.data
|
||||||
.get("TRACKTOTAL")
|
.get(std_tag_to_str(StandardTagKey::TrackTotal))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
disc: self
|
disc: self
|
||||||
.data
|
.data
|
||||||
.get("DISCTOTAL")
|
.get(std_tag_to_str(StandardTagKey::DiscTotal))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(1),
|
.unwrap_or(1),
|
||||||
duration: 0,
|
duration: 0,
|
||||||
date: self
|
date: self
|
||||||
.data
|
.data
|
||||||
.get("DATE")
|
.get(std_tag_to_str(StandardTagKey::Date))
|
||||||
.unwrap_or(&TagType::Unknown)
|
.unwrap_or(&TagType::Unknown)
|
||||||
.uint()
|
.uint()
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
|
@ -217,6 +355,19 @@ impl Tags {
|
||||||
title: self.genre_title().unwrap_or_else(|| "Unknown Genre".into()),
|
title: self.genre_title().unwrap_or_else(|| "Unknown Genre".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn export_to_item(self, item: &mut crate::Item, overwrite: bool) {
|
||||||
|
for (key, val) in self.data {
|
||||||
|
if let Some(primitive_val) = val.to_primitive() {
|
||||||
|
if overwrite || item.field(&key).is_none() {
|
||||||
|
item.set_field(&key, primitive_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if overwrite || item.field("filename").is_none() {
|
||||||
|
item.set_field("filename", self.filename.display().to_string().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -230,6 +381,7 @@ enum TagType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TagType {
|
impl TagType {
|
||||||
|
#[inline]
|
||||||
fn from_symphonia_value(value: &Value) -> Option<Self> {
|
fn from_symphonia_value(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Binary(_val) => None,
|
Value::Binary(_val) => None,
|
||||||
|
@ -242,6 +394,11 @@ impl TagType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_symphonia_visual(visual: &Visual) -> Option<Self> {
|
||||||
|
Some(Self::Str(format!("data:{};base64,{}", &visual.media_type, base64::encode_config(&visual.data, BASE64_CONF))))
|
||||||
|
}
|
||||||
|
|
||||||
fn str(&self) -> Option<&str> {
|
fn str(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Str(s) => Some(s),
|
Self::Str(s) => Some(s),
|
||||||
|
@ -257,4 +414,15 @@ impl TagType {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_primitive(self) -> Option<crate::lang::TypePrimitive> {
|
||||||
|
match self {
|
||||||
|
Self::Boolean(b) => Some(crate::lang::TypePrimitive::Bool(b)),
|
||||||
|
Self::Flag => None,
|
||||||
|
Self::I64(i) => Some(crate::lang::TypePrimitive::Int(i)),
|
||||||
|
Self::U64(u) => Some(crate::lang::TypePrimitive::UInt(u)),
|
||||||
|
Self::Str(s) => Some(crate::lang::TypePrimitive::String(s.clone())),
|
||||||
|
Self::Unknown => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
use std::fs::{DirEntry, ReadDir};
|
use std::fs::{DirEntry, ReadDir};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::lang::{RuntimeMsg, TypePrimitive};
|
use crate::lang::{RuntimeMsg, TypePrimitive, GeneratorOp};
|
||||||
use crate::Item;
|
use crate::Item;
|
||||||
|
|
||||||
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))$";
|
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))$";
|
||||||
|
@ -165,7 +166,8 @@ impl FileIter {
|
||||||
match crate::music::Library::read_media_tags(path) {
|
match crate::music::Library::read_media_tags(path) {
|
||||||
Ok(tags) => {
|
Ok(tags) => {
|
||||||
let mut item = Item::new();
|
let mut item = Item::new();
|
||||||
item.set_field("title", tags.track_title().into());
|
tags.export_to_item(&mut item, true);
|
||||||
|
/*item.set_field("title", tags.track_title().into());
|
||||||
if let Some(artist) = tags.artist_name() {
|
if let Some(artist) = tags.artist_name() {
|
||||||
item.set_field("artist", artist.into());
|
item.set_field("artist", artist.into());
|
||||||
}
|
}
|
||||||
|
@ -192,6 +194,9 @@ impl FileIter {
|
||||||
if let Some(year) = tags.track_date() {
|
if let Some(year) = tags.track_date() {
|
||||||
item.set_field("year", year.into());
|
item.set_field("year", year.into());
|
||||||
}
|
}
|
||||||
|
if let Some(cover) = tags.cover_art() {
|
||||||
|
item.set_field("cover", cover.into());
|
||||||
|
}*/
|
||||||
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
|
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
|
||||||
Some(item)
|
Some(item)
|
||||||
}
|
}
|
||||||
|
@ -334,6 +339,8 @@ pub trait FilesystemQuerier: Debug {
|
||||||
|
|
||||||
fn single(&mut self, path: &str, pattern: Option<&str>) -> Result<Item, RuntimeMsg>;
|
fn single(&mut self, path: &str, pattern: Option<&str>) -> Result<Item, RuntimeMsg>;
|
||||||
|
|
||||||
|
fn read_file(&mut self, path: &str) -> Result<GeneratorOp, RuntimeMsg>;
|
||||||
|
|
||||||
fn expand(&self, folder: Option<&str>) -> Result<Option<String>, RuntimeMsg> {
|
fn expand(&self, folder: Option<&str>) -> Result<Option<String>, RuntimeMsg> {
|
||||||
#[cfg(feature = "shellexpand")]
|
#[cfg(feature = "shellexpand")]
|
||||||
match folder {
|
match folder {
|
||||||
|
@ -360,6 +367,50 @@ pub trait FilesystemQuerier: Debug {
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct FilesystemExecutor {}
|
pub struct FilesystemExecutor {}
|
||||||
|
|
||||||
|
impl FilesystemExecutor {
|
||||||
|
#[cfg(feature = "collections")]
|
||||||
|
fn read_m3u8<P: AsRef<Path> + 'static>(&self, path: P) -> Result<GeneratorOp, RuntimeMsg> {
|
||||||
|
let mut file = std::fs::File::open(&path).map_err(|e| RuntimeMsg(format!("Path read error: {}", e)))?;
|
||||||
|
let mut file_bytes = Vec::new();
|
||||||
|
file.read_to_end(&mut file_bytes).map_err(|e| RuntimeMsg(format!("File read error: {}", e)))?;
|
||||||
|
let (_, playlist) = m3u8_rs::parse_playlist(&file_bytes).map_err(|e| RuntimeMsg(format!("Playlist read error: {}", e)))?;
|
||||||
|
let playlist = match playlist {
|
||||||
|
m3u8_rs::Playlist::MasterPlaylist(_) => return Err(RuntimeMsg(format!("Playlist not supported: `{}` is a master (not media) playlist", path.as_ref().display()))),
|
||||||
|
m3u8_rs::Playlist::MediaPlaylist(l) => l,
|
||||||
|
};
|
||||||
|
let mut index = 0;
|
||||||
|
Ok(GeneratorOp::new(move |ctx| {
|
||||||
|
if let Some(segment) = playlist.segments.get(index) {
|
||||||
|
let path = path.as_ref();
|
||||||
|
index += 1;
|
||||||
|
let item_path = if let Some(parent) = path.parent() {
|
||||||
|
let joined_path = parent.join(&segment.uri);
|
||||||
|
if let Some(s) = joined_path.to_str() {
|
||||||
|
s.to_owned()
|
||||||
|
} else {
|
||||||
|
return Some(Err(RuntimeMsg(format!("Failed to convert path to string for `{}`", joined_path.display()))));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
segment.uri.clone()
|
||||||
|
};
|
||||||
|
let item = match ctx.filesystem.single(&item_path, None) {
|
||||||
|
Err(e) => Err(e),
|
||||||
|
Ok(mut item) => {
|
||||||
|
item.set_field("duration", (segment.duration as f64).into());
|
||||||
|
if let Some(title) = &segment.title {
|
||||||
|
item.set_field("title", title.to_owned().into());
|
||||||
|
}
|
||||||
|
Ok(item)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(item)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FilesystemQuerier for FilesystemExecutor {
|
impl FilesystemQuerier for FilesystemExecutor {
|
||||||
fn raw(
|
fn raw(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -376,4 +427,17 @@ impl FilesystemQuerier for FilesystemExecutor {
|
||||||
let mut file_iter = FileIter::new(path, pattern, false).map_err(RuntimeMsg)?;
|
let mut file_iter = FileIter::new(path, pattern, false).map_err(RuntimeMsg)?;
|
||||||
file_iter.only_once().map_err(RuntimeMsg)
|
file_iter.only_once().map_err(RuntimeMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_file(&mut self, path: &str) -> Result<GeneratorOp, RuntimeMsg> {
|
||||||
|
let path: PathBuf = self.expand(Some(path))?.unwrap().into();
|
||||||
|
if let Some(ext) = path.extension().and_then(|ext| ext.to_str()) {
|
||||||
|
match &ext.to_lowercase() as &str {
|
||||||
|
#[cfg(feature = "collections")]
|
||||||
|
"m3u8" => self.read_m3u8(path),
|
||||||
|
ext => Err(RuntimeMsg(format!("Unrecognised extension `{}` in path `{}`", ext, path.display())))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(RuntimeMsg(format!("Unrecognised path `{}`", path.display())))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -842,3 +842,18 @@ fn execute_mpdfunction_line() -> Result<(), InterpreterError> {
|
||||||
execute_single_line("mpd(`default`)", false, true)?;
|
execute_single_line("mpd(`default`)", false, true)?;
|
||||||
execute_single_line("mpd(`127.0.0.1:6600`)", false, true)
|
execute_single_line("mpd(`127.0.0.1:6600`)", false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn execute_playlist_line() -> Result<(), InterpreterError> {
|
||||||
|
execute_single_line(
|
||||||
|
r"playlist(`~/Music/Playlists/cabello.m3u8`)",
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
execute_single_line(
|
||||||
|
r"playlist(`/home/ngnius/Music/Playlists/powers.m3u8`)",
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
execute_single_line(r"playlist(`~/Music/Playlists/empty.m3u8`)", true, true)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue