diff --git a/Cargo.lock b/Cargo.lock index c017459..90d2631 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,7 +63,7 @@ dependencies = [ "futures-lite 1.13.0", "once_cell", "serde", - "zbus", + "zbus 3.15.2", ] [[package]] @@ -93,15 +93,6 @@ dependencies = [ "winit", ] -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.0" @@ -292,6 +283,28 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "ashpd" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3" +dependencies = [ + "async-fs 2.1.2", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand", + "raw-window-handle 0.6.2", + "serde", + "serde_repr", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.5", + "zbus 5.1.1", +] + [[package]] name = "async-broadcast" version = "0.5.1" @@ -302,6 +315,18 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-broadcast" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-channel" version = "2.3.1" @@ -339,6 +364,17 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock 3.4.0", + "blocking", + "futures-lite 2.4.0", +] + [[package]] name = "async-io" version = "1.13.0" @@ -398,6 +434,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.3.4", + "blocking", + "futures-lite 2.4.0", +] + [[package]] name = "async-once-cell" version = "0.5.4" @@ -421,6 +468,25 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io 2.3.4", + "async-lock 3.4.0", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.3.1", + "futures-lite 2.4.0", + "rustix 0.38.39", + "tracing", +] + [[package]] name = "async-recursion" version = "1.1.1" @@ -493,9 +559,9 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zbus", - "zbus_names", - "zvariant", + "zbus 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", ] [[package]] @@ -507,7 +573,7 @@ dependencies = [ "atspi-common", "atspi-proxies", "futures-lite 1.13.0", - "zbus", + "zbus 3.15.2", ] [[package]] @@ -518,7 +584,7 @@ checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52" dependencies = [ "atspi-common", "serde", - "zbus", + "zbus 3.15.2", ] [[package]] @@ -527,21 +593,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.21.7" @@ -811,6 +862,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "cgl" version = "0.3.2" @@ -1212,15 +1269,6 @@ dependencies = [ "serde", ] -[[package]] -name = "ecolor" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" -dependencies = [ - "emath 0.28.1", -] - [[package]] name = "eframe" version = "0.27.2" @@ -1230,7 +1278,7 @@ dependencies = [ "bytemuck", "cocoa", "document-features", - "egui 0.27.2", + "egui", "egui-wgpu", "egui-winit", "egui_glow", @@ -1263,33 +1311,12 @@ checksum = "584c5d1bf9a67b25778a3323af222dbe1a1feb532190e103901187f92c7fe29a" dependencies = [ "accesskit", "ahash", - "epaint 0.27.2", + "epaint", "log", "nohash-hasher", "serde", ] -[[package]] -name = "egui" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" -dependencies = [ - "ahash", - "emath 0.28.1", - "epaint 0.28.1", - "nohash-hasher", -] - -[[package]] -name = "egui-aesthetix" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b91e1b07193fa9bc71849e39a76d30ffd6a2f57bfc54552e3a2df263da577b" -dependencies = [ - "egui 0.28.1", -] - [[package]] name = "egui-wgpu" version = "0.27.2" @@ -1298,8 +1325,8 @@ checksum = "469ff65843f88a702b731a1532b7d03b0e8e96d283e70f3a22b0e06c46cb9b37" dependencies = [ "bytemuck", "document-features", - "egui 0.27.2", - "epaint 0.27.2", + "egui", + "epaint", "log", "thiserror", "type-map", @@ -1316,7 +1343,7 @@ checksum = "2e3da0cbe020f341450c599b35b92de4af7b00abde85624fd16f09c885573609" dependencies = [ "accesskit_winit", "arboard", - "egui 0.27.2", + "egui", "log", "raw-window-handle 0.6.2", "smithay-clipboard", @@ -1331,7 +1358,7 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b78779f35ded1a853786c9ce0b43fe1053e10a21ea3b23ebea411805ce41593" dependencies = [ - "egui 0.27.2", + "egui", "ehttp", "enum-map", "image", @@ -1348,7 +1375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0e5d975f3c86edc3d35b1db88bb27c15dde7c55d3b5af164968ab5ede3f44ca" dependencies = [ "bytemuck", - "egui 0.27.2", + "egui", "glow", "log", "memoffset 0.9.1", @@ -1387,12 +1414,6 @@ dependencies = [ "serde", ] -[[package]] -name = "emath" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -1402,6 +1423,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + [[package]] name = "enum-map" version = "2.7.3" @@ -1487,28 +1514,14 @@ dependencies = [ "ab_glyph", "ahash", "bytemuck", - "ecolor 0.27.2", - "emath 0.27.2", + "ecolor", + "emath", "log", "nohash-hasher", "parking_lot", "serde", ] -[[package]] -name = "epaint" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" -dependencies = [ - "ab_glyph", - "ahash", - "ecolor 0.28.1", - "emath 0.28.1", - "nohash-hasher", - "parking_lot", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -1651,6 +1664,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.31" @@ -1691,6 +1713,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -1711,6 +1744,7 @@ checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1750,12 +1784,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "gl_generator" version = "0.14.0" @@ -1792,7 +1820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" dependencies = [ "bitflags 2.6.0", - "cfg_aliases", + "cfg_aliases 0.1.1", "cgl", "core-foundation", "dispatch", @@ -1815,7 +1843,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" dependencies = [ - "cfg_aliases", + "cfg_aliases 0.1.1", "glutin", "raw-window-handle 0.5.2", "winit", @@ -2327,18 +2355,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "wasi", - "windows-sys 0.52.0", -] - [[package]] name = "naga" version = "0.19.2" @@ -2402,6 +2418,19 @@ dependencies = [ "memoffset 0.7.1", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", + "memoffset 0.9.1", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -2581,6 +2610,7 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.6.0", "block2 0.5.1", + "dispatch", "libc", "objc2 0.5.2", ] @@ -2619,15 +2649,6 @@ dependencies = [ "cc", ] -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - [[package]] name = "oboe" version = "0.6.1" @@ -2820,6 +2841,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -3013,6 +3040,28 @@ dependencies = [ "usvg", ] +[[package]] +name = "rfd" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f6f80a9b882647d9014673ca9925d30ffc9750f2eed2b4490e189eaebd01e8" +dependencies = [ + "ashpd", + "block2 0.5.1", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", + "pollster", + "raw-window-handle 0.6.2", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rgb" version = "0.8.50" @@ -3056,12 +3105,6 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustc-hash" version = "1.1.0" @@ -3673,30 +3716,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "tokio" -version = "1.41.0" +name = "toml" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", ] [[package]] @@ -3727,6 +3755,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.40", ] @@ -3886,6 +3916,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "usvg" version = "0.37.0" @@ -4229,7 +4265,7 @@ checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01" dependencies = [ "arrayvec", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "js-sys", "log", "parking_lot", @@ -4254,7 +4290,7 @@ dependencies = [ "arrayvec", "bit-vec", "bitflags 2.6.0", - "cfg_aliases", + "cfg_aliases 0.1.1", "codespan-reporting", "indexmap", "log", @@ -4281,7 +4317,7 @@ dependencies = [ "arrayvec", "ash", "bitflags 2.6.0", - "cfg_aliases", + "cfg_aliases 0.1.1", "core-graphics-types", "glow", "glutin_wgl_sys", @@ -4667,7 +4703,7 @@ dependencies = [ "bitflags 2.6.0", "bytemuck", "calloop 0.12.4", - "cfg_aliases", + "cfg_aliases 0.1.1", "core-foundation", "core-graphics", "cursor-icon", @@ -4722,6 +4758,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winresource" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e2aaaf8cfa92078c0c0375423d631f82f2f57979c2884fdd5f604a11e45329" +dependencies = [ + "toml 0.7.8", + "version_check", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -4834,6 +4880,7 @@ dependencies = [ "clap", "env_logger", "log", + "winresource", "xmpd-cliargs", "xmpd-gui", "xmpd-manifest", @@ -4846,17 +4893,18 @@ version = "2.0.0" dependencies = [ "anyhow", "camino", + "dirs", "eframe", - "egui 0.27.2", - "egui-aesthetix", + "egui", "egui_extras", "lazy_static", "log", - "tokio", + "rfd", "uuid", "xmpd-cache", "xmpd-cliargs", "xmpd-manifest", + "xmpd-player", "xmpd-settings", ] @@ -4867,14 +4915,20 @@ dependencies = [ "anyhow", "serde", "serde_json", + "toml 0.8.19", "url", "uuid", + "xmpd-cliargs", + "xmpd-settings", ] [[package]] name = "xmpd-player" version = "2.0.0" dependencies = [ + "anyhow", + "lazy_static", + "log", "rodio", ] @@ -4884,10 +4938,10 @@ version = "2.0.0" dependencies = [ "anyhow", "camino", - "egui 0.27.2", + "egui", "lazy_static", "serde", - "toml", + "toml 0.8.19", ] [[package]] @@ -4900,12 +4954,12 @@ version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" dependencies = [ - "async-broadcast", + "async-broadcast 0.5.1", "async-executor", - "async-fs", + "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-process", + "async-process 1.8.1", "async-recursion", "async-task", "async-trait", @@ -4918,7 +4972,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.26.4", "once_cell", "ordered-stream", "rand", @@ -4930,9 +4984,45 @@ dependencies = [ "uds_windows", "winapi", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", +] + +[[package]] +name = "zbus" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1162094dc63b1629fcc44150bcceeaa80798cd28bcbe7fa987b65a034c258608" +dependencies = [ + "async-broadcast 0.7.1", + "async-executor", + "async-fs 2.1.2", + "async-io 2.3.4", + "async-lock 3.4.0", + "async-process 2.3.0", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener 5.3.1", + "futures-core", + "futures-util", + "hex", + "nix 0.29.0", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow 0.6.20", + "xdg-home", + "zbus_macros 5.1.1", + "zbus_names 4.1.0", + "zvariant 5.1.0", ] [[package]] @@ -4946,7 +5036,22 @@ dependencies = [ "quote", "regex", "syn 1.0.109", - "zvariant_utils", + "zvariant_utils 1.0.1", +] + +[[package]] +name = "zbus_macros" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd2dcdce3e2727f7d74b7e33b5a89539b3cc31049562137faf7ae4eb86cd16d" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.87", + "zbus_names 4.1.0", + "zvariant 5.1.0", + "zvariant_utils 3.0.2", ] [[package]] @@ -4957,7 +5062,19 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 3.15.2", +] + +[[package]] +name = "zbus_names" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "856b7a38811f71846fd47856ceee8bccaec8399ff53fb370247e66081ace647b" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.6.20", + "zvariant 5.1.0", ] [[package]] @@ -4998,7 +5115,23 @@ dependencies = [ "libc", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 3.15.2", +] + +[[package]] +name = "zvariant" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1200ee6ac32f1e5a312e455a949a4794855515d34f9909f4a3e082d14e1a56f" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "winnow 0.6.20", + "zvariant_derive 5.1.0", + "zvariant_utils 3.0.2", ] [[package]] @@ -5011,7 +5144,20 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "zvariant_utils", + "zvariant_utils 1.0.1", +] + +[[package]] +name = "zvariant_derive" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687e3b97fae6c9104fbbd36c73d27d149abf04fb874e2efbd84838763daa8916" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.87", + "zvariant_utils 3.0.2", ] [[package]] @@ -5024,3 +5170,17 @@ dependencies = [ "quote", "syn 1.0.109", ] + +[[package]] +name = "zvariant_utils" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20d1d011a38f12360e5fcccceeff5e2c42a8eb7f27f0dcba97a0862ede05c9c6" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn 2.0.87", + "winnow 0.6.20", +] diff --git a/Cargo.toml b/Cargo.toml index bc9c4a5..11853d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,28 +25,25 @@ authors=[ [workspace.dependencies] anstyle = "1.0.6" anyhow = "1.0.81" -bitflags = { version = "2.6.0", features = ["serde"] } camino = { version="1.1.6", features = ["serde1"] } clap = { version = "4.5.4", features = ["derive"] } eframe = "0.27.2" egui = { version = "0.27.2", features = ["color-hex", "serde"] } egui_extras = { version = "0.27.2", features = ["all_loaders"] } env_logger = "0.11.3" -futures = "0.3.30" -html-escape = "0.2.13" lazy_static = "1.4.0" -libc = "0.2.153" log = "0.4.21" -notify-rust = "4.11.3" -open = "5.3.0" -regex = "1.11.0" -reqwest = { version = "0.12.3", features = ["blocking", "h2", "http2", "rustls-tls"], default-features = false } +# notify-rust = "4.11.3" +# open = "5.3.0" +# reqwest = { version = "0.12.3", features = ["blocking", "h2", "http2", "rustls-tls"], default-features = false } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" -# serde_traitobject = "0.2.8" -tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread", "process", "sync"] } url = { version = "2.5.0", features = ["serde"] } uuid = { version = "1.11.0", features = ["serde", "v4"] } windows = { version = "0.56.0", features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_System_Console"] } -zip-extensions = "0.6.20" +# zip-extensions = "0.6.20" dirs="5.0.1" +winresource = "0.1.17" +toml = "0.8.19" +rfd = "0.15.1" +rodio = { version = "0.20.1", features = ["symphonia-all"] } diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000..6bfeaf8 Binary files /dev/null and b/assets/icon.ico differ diff --git a/assets/info.svg b/assets/info.svg index 3a59676..cbb1591 100644 --- a/assets/info.svg +++ b/assets/info.svg @@ -1 +1 @@ - + diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000..e1f0ec6 --- /dev/null +++ b/manifest.toml @@ -0,0 +1,1373 @@ +[songs.6895e921-91f2-4713-b604-c2cdd9f3f1c2] +name = "We Didnt Start The Fire" +author = "Fall Out Boy" +url = "https://open.spotify.com/track/60glT2wsoSHV3B8yCRSB8v" +source_type = "Spotify" + +[songs.98b04764-39cc-4c82-a2e2-420dd85573ca] +name = "Tarp amzinybes" +author = "SEL" +url = "https://youtu.be/UfPj-0QpGFA" +source_type = "Youtube" + +[songs.3b2573d4-2e1b-4446-a377-5fcb2b0a70c5] +name = "18 mne uze" +author = "Ruki Verch" +url = "https://www.youtube.com/watch?v=Hxab_Sr132o" +source_type = "Youtube" + +[songs.fa339b0b-8d3a-45e7-aed9-f744afb4a666] +name = "Eik Tu NA" +author = "AVA" +url = "https://www.youtube.com/watch?v=yRf3ijaIgOg" +source_type = "Youtube" + +[songs.862ddd87-68c4-4bed-a8cd-0e2021a0ce79] +name = "Renee" +author = "SALES" +url = "https://open.spotify.com/track/5MeUMSRreLHYLhw8ZTyqpk" +source_type = "Spotify" + +[songs.95a3350c-c62f-4543-8cfe-6c512861b229] +name = "Ryk Zuvedra ryk" +author = "Zilviokas" +url = "https://www.youtube.com/watch?v=eN6BOI7UlSE" +source_type = "Youtube" + +[songs.e71a61d4-b54a-47d1-b0ad-db6695bd0739] +name = "Hey Lover!" +author = "Wabie" +url = "https://open.spotify.com/track/7rC3P7tpWriaC4hYWKwGQd" +source_type = "Spotify" + +[songs.bd85a9d7-1fb6-4154-a290-e5137590e419] +name = "I gamta" +author = "Andzikas" +url = "https://www.youtube.com/watch?v=UyLdjC-hihM" +source_type = "Youtube" + +[songs.c28f14ca-ec10-469a-b0cc-3e26e9f56007] +name = "VASARA ZJBS" +author = "Depresinis & MERAKI2004" +url = "https://www.youtube.com/watch?v=BD-pBjRy-5A" +source_type = "Youtube" + +[songs.b26f7338-0d1f-4dba-b639-3bdae9d7e10e] +name = "Po stikliuka" +author = "Tipo grupe ir Kastaneda" +url = "https://www.youtube.com/watch?v=EtmE60nE7fI" +source_type = "Youtube" + +[songs.720d5b94-ac54-4162-8da7-ba8d258139e6] +name = "KINO FILMAI" +author = "RADVIS" +url = "https://www.youtube.com/watch?v=vhAEkC3xNMo" +source_type = "Youtube" + +[songs.91629850-33e2-4e18-8c37-6eafdfcde3f4] +name = "Give It To Me" +author = "Unknown" +url = "https://www.youtube.com/watch?v=upQe8EeSyZU" +source_type = "Youtube" + +[songs.2b19ae9f-2321-41fc-8a1f-2bb4c2975380] +name = "Malunas Prie Kelio" +author = "VainHouse" +url = "https://www.youtube.com/watch?v=bbwuNjDXCiM" +source_type = "Youtube" + +[songs.dfc0782c-33f2-414d-9b56-76a77902bcc5] +name = "Baliavojam" +author = "16Hz" +url = "https://www.youtube.com/watch?v=Ia-qERX8WLs" +source_type = "Youtube" + +[songs.518e23e8-72df-42de-a918-6a9a197deb9a] +name = "Whiskey, Cola i Tequila" +author = "Maco Mamuko" +url = "https://www.youtube.com/watch?v=aBrN0k0Phtc" +source_type = "Youtube" + +[songs.e9495391-8a6c-4942-9dc6-09b764f9d1e9] +name = "Zalias Pasas" +author = "Zas" +url = "https://www.youtube.com/watch?v=SZA7IjlCfyI" +source_type = "Youtube" + +[songs.0b907d17-e3f9-4dbb-9c2d-e10327316f6e] +name = "UZ MUS IR JUS" +author = "Mr.Bullet" +url = "https://www.youtube.com/watch?v=85q_7jXEgH8" +source_type = "Youtube" + +[songs.407155fd-3174-4778-ae93-bb01b7518f9f] +name = "Cia Mano Rojus" +author = "Robertas Kupstas" +url = "https://www.youtube.com/watch?v=xij_YeEInr8" +source_type = "Youtube" + +[songs.8e8c3f6c-e34b-4f4e-b9be-f36be5901435] +name = "biznis" +author = "PROFLAME" +url = "https://www.youtube.com/watch?v=t139Vd83pgs" +source_type = "Youtube" + +[songs.eaf1cc63-3eb6-4d86-a986-e8129fff7fcb] +name = "Zalia Siera" +author = "DJ Dalgis" +url = "https://www.youtube.com/watch?v=nfentq_pez4" +source_type = "Youtube" + +[songs.05a28184-e58e-42c3-a803-512bb0817a07] +name = "Vakareja" +author = "Karaliska Erdve" +url = "https://www.youtube.com/watch?v=g0HmrlJ7fhE" +source_type = "Youtube" + +[songs.131ab436-869b-4b3b-8ce4-3b5087d3461f] +name = "1.9 TDI" +author = "Grupe MX" +url = "https://www.youtube.com/watch?v=8FBr5GQXsI8" +source_type = "Youtube" + +[songs.639dc5af-b3e6-4d38-a003-80deac01d326] +name = "Myliu kina" +author = "Zas" +url = "https://www.youtube.com/watch?v=ImFrfmi-qT8" +source_type = "Youtube" + +[songs.0e1d36ed-d07d-48c0-a101-1bf1ac6d7a26] +name = "Be taves" +author = "Funky" +url = "https://www.youtube.com/watch?v=heTDrDukLWU" +source_type = "Youtube" + +[songs.4f368ef5-08d0-4d1f-b8ba-a34ee9fc6aa2] +name = "Blizgantys Naikai" +author = "SADBOY" +url = "https://www.youtube.com/watch?v=p5KsYJGcfOM" +source_type = "Youtube" + +[songs.4eafd817-d75a-451e-b6b4-38ef29e66fdf] +name = "Ne, nereikia asaru" +author = "Rytis Cicinas" +url = "https://www.youtube.com/watch?v=48GSg1q2kPE" +source_type = "Youtube" + +[songs.f3edb436-bf04-4ad5-ad45-684a601846c3] +name = "We are the winners" +author = "LT United" +url = "https://www.youtube.com/watch?v=DBAdOlQPbwg" +source_type = "Youtube" + +[songs.75c6e1aa-21c7-4626-9def-602d656282bc] +name = "Ka Tu Ka Vakare" +author = "Unknown" +url = "https://www.youtube.com/watch?v=6SOS4ljHbJY" +source_type = "Youtube" + +[songs.870502f1-e3a9-419b-9ba6-d8100d1198a5] +name = "Is Leto Leidziasi Saule" +author = "Jovani, Karaliska Erdve" +url = "https://www.youtube.com/watch?v=VqSu8iG1_DE" +source_type = "Youtube" + +[songs.22565196-5757-4767-8f1f-f1c9b8a87dcc] +name = "I WAS MADE FOR LOVIN' YOU (TECHNO)" +author = "Unknown" +url = "https://www.youtube.com/watch?v=asVznhccYao" +source_type = "Youtube" + +[songs.73ddd372-4853-4182-b212-b021e7dc8988] +name = "Parukom" +author = "Tnn" +url = "https://www.youtube.com/watch?v=v9pBZK2RIPI" +source_type = "Youtube" + +[songs.02d90830-7b5f-430f-b82c-f45998862e81] +name = "Juodas Golfas" +author = "NL" +url = "https://www.youtube.com/watch?v=f2-ZmElSvPc" +source_type = "Youtube" + +[songs.81426b49-3511-4e48-be21-3c24acba0fb9] +name = "Kernkraft 400" +author = "Zombie Nation" +url = "https://www.youtube.com/watch?v=z5LW07FTJbI" +source_type = "Youtube" + +[songs.cd72e9db-aaa4-485e-b3a5-7fbeed2cff36] +name = 'I.M.P Jingle (From "Helluva Boss")' +author = "Geek Music" +url = "https://open.spotify.com/track/5x0bvS385Ata1irjLMyLTn" +source_type = "Spotify" + +[songs.ea41c37c-7b62-4fd6-9fec-650e94d184f2] +name = "tipo daina" +author = "Tipo Grupe" +url = "https://www.youtube.com/watch?v=PTIOaSjEgIU" +source_type = "Youtube" + +[songs.60214f0e-9a37-49b4-92bf-b7b548e501ad] +name = "Uzmerkiu akis" +author = "SEL" +url = "https://youtu.be/SdWj06XRZms?si=9TNGzjK9ITom-jaD" +source_type = "Youtube" + +[songs.858d8645-8637-4d3f-b4b7-c9c75743d90a] +name = "Dviratukas" +author = "Eugenijus Ostapenko" +url = "https://www.youtube.com/watch?v=ILFHZQK33Mw" +source_type = "Youtube" + +[songs.e37c6cb6-ad8e-43a7-83d1-8b795db8aa1c] +name = "Harness Your Hopes" +author = "Pavement" +url = "https://open.spotify.com/track/4vsoWZcvtvSsE0OiVvDDvX" +source_type = "Spotify" + +[songs.0ee56450-2942-4805-9f08-b49652472258] +name = "Tricky Disco" +author = "Unknown" +url = "https://www.youtube.com/watch?v=t78qVdbAiXw" +source_type = "Youtube" + +[songs.9ef33d55-972d-490c-95c6-bf046bf4f979] +name = "MONEY ON THE DASH" +author = "Unknown" +url = "https://open.spotify.com/track/6nVEV8CIU4dw12oVZbKJtl" +source_type = "Spotify" + +[songs.df2e369f-2fee-49e5-b52c-33f73c34ffb2] +name = "Autostrada Vilnius" +author = "16Hz" +url = "https://www.youtube.com/watch?v=ANS2TSegr40" +source_type = "Youtube" + +[songs.bc5fe406-040b-4c46-82ce-bb4505b81947] +name = "i like the way you kiss me" +author = "Artemas" +url = "https://www.youtube.com/watch?v=ODDRRXMi22E" +source_type = "Youtube" + +[songs.dc6c36b0-f595-457f-8fc3-641710b0e3b9] +name = "I Pajuri" +author = "Mercy Dance" +url = "https://www.youtube.com/watch?v=RPpkMh47l9w" +source_type = "Youtube" + +[songs.1a22e35a-0af1-4326-b59c-00d59504446b] +name = "Virs debesu" +author = "Andzikas" +url = "https://www.youtube.com/watch?v=PHJcVGhxra8" +source_type = "Youtube" + +[songs.f5a31a44-fc62-4cce-b65e-05e4085864fe] +name = "End of Beginning" +author = "Djo" +url = "https://open.spotify.com/track/3qhlB30KknSejmIvZZLjOD" +source_type = "Spotify" + +[songs.ca765223-e4e6-4b5d-8928-919c3f491b43] +name = "Kaifuok" +author = "SADBOY" +url = "https://www.youtube.com/watch?v=vclryWgfy8I" +source_type = "Youtube" + +[songs.0679475a-259c-4c98-9ae7-a58c10dfeedb] +name = "New Flesh" +author = "Current Joys" +url = "https://open.spotify.com/track/6HJxxqHWMdidwTVZmZWeHU" +source_type = "Spotify" + +[songs.b0c0d44c-86ca-4b80-a081-734a4178c870] +name = "After Marvins Dance (Marvin Gaye's 'After The Dance' Edit)" +author = "Bauhouse" +url = "https://www.youtube.com/watch?v=J-cgyYiExh8" +source_type = "Youtube" + +[songs.4cf5e323-5e79-4471-816a-5fa345854cea] +name = "rytmecio rasos" +author = "nemuno krantai" +url = "https://www.youtube.com/watch?v=2-fGbsrofv4" +source_type = "Youtube" + +[songs.2374179d-d6a8-41b9-9cac-21147303fc8e] +name = "Nebenoriu Laukt" +author = "Dzordana Butkute" +url = "https://www.youtube.com/watch?v=_AozFrAqNMk" +source_type = "Youtube" + +[songs.9866acdd-97ee-4e19-ba20-a64caa9b02ee] +name = "Where'd All the Time Go?" +author = "Dr. Dog" +url = "https://open.spotify.com/track/0UV5zxRMz6AO4ZwUOZNIKI" +source_type = "Spotify" + +[songs.27d61e87-deec-4e4c-8015-ad8b691eea40] +name = "Klaipeda On Top" +author = "Deivas" +url = "https://www.youtube.com/watch?v=g_h2M3e2OYU" +source_type = "Youtube" + +[songs.c332ce2b-6b1c-4979-9977-dc00aa6e710b] +name = "TU ESI MELAGIS (Techno Extended)" +author = "Radvis" +url = "https://www.youtube.com/watch?v=kmvvP7GW_bw" +source_type = "Youtube" + +[songs.4a7b1853-7529-498d-addf-25e894a37ccf] +name = "Temptation" +author = "Arash" +url = "https://www.youtube.com/watch?v=6X3ZJh762-I" +source_type = "Youtube" + +[songs.6c3f2503-0160-4c42-8b17-25ff402f3fa7] +name = "Visky Kola karaleva trans pola" +author = "Dzaro and hansa" +url = "https://www.youtube.com/watch?v=fflrMvZ2HtA" +source_type = "Youtube" + +[songs.18c2b9bc-6403-4a67-94bd-1e9f5413d83b] +name = "Skrendu" +author = "SEL" +url = "https://youtu.be/G5Q_asvrXlA" +source_type = "Youtube" + +[songs.d563619a-344e-41cf-99d1-5a52214ada49] +name = "Sports" +author = "Beach Bunny" +url = "https://open.spotify.com/track/77G0k1La0c5Dw8bAFANcyp" +source_type = "Spotify" + +[songs.e1cb8b00-713b-4a0e-bc61-dbf2d2596fcf] +name = "Tik Tok" +author = "SEL" +url = "https://youtu.be/RkaIUateIxg" +source_type = "Youtube" + +[songs.f81f8f9d-6c56-4ae3-8f5f-28c04632d3b5] +name = "Kcik 23" +author = "Unknown Artist" +url = "https://www.youtube.com/watch?v=SnnqDdZJpzA" +source_type = "Youtube" + +[songs.877c24e4-c0c0-4e9c-a553-221e381c8a00] +name = "Stumblin' In" +author = "CYRIL" +url = "https://open.spotify.com/track/0h3Xy4V4apMraB5NuM8U7Z" +source_type = "Spotify" + +[songs.5c2ee27e-d564-404a-8259-87d1d336f106] +name = "Money" +author = "The Drums" +url = "https://open.spotify.com/track/3VIJBrMpvimHEw5wtPh2wB" +source_type = "Spotify" + +[songs.eb91fc63-4e0e-49e9-99c7-ea7fe5770a5b] +name = "LEDINE" +author = "Depresinis" +url = "https://www.youtube.com/watch?v=qugvChkXMLk" +source_type = "Youtube" + +[songs.16dafb40-ebac-4e04-961a-99d79789f1a3] +name = "Topine Panele" +author = "Wenona Waves" +url = "https://www.youtube.com/watch?v=MPHuhmUomfE" +source_type = "Youtube" + +[songs.4b61344d-fa89-4b79-bd45-3b1fc8c8cc1c] +name = "Rycka klipas" +author = "Unknown" +url = "https://www.youtube.com/watch?v=nuTUDSQ3BBI" +source_type = "Youtube" + +[songs.3d543d58-e33d-4158-9956-049309baa35c] +name = "Movin' Out (Anthony's Song)" +author = "Billy Joel" +url = "https://open.spotify.com/track/16GUMo6u3D2qo9a19AkYct" +source_type = "Spotify" + +[songs.7e32803d-a5a9-453c-8c81-b479c51e5bc9] +name = "Looking Out for You" +author = "Joy Again" +url = "https://open.spotify.com/track/3jfZ9M23l0L7RxzYMTgBTv" +source_type = "Spotify" + +[songs.bb16708f-0cd7-4918-8014-d374d68acbd2] +name = "Not Allowed" +author = "TV Girl" +url = "https://open.spotify.com/track/3IznIgmXtrUaoPWpQTy5jB" +source_type = "Spotify" + +[songs.76f7945f-e677-4297-a98a-708314f92de8] +name = "Kanikuli" +author = "Unknown" +url = "https://www.youtube.com/watch?v=GNMiDZTL7jo" +source_type = "Youtube" + +[songs.4a56c71c-70f0-45e7-a9b8-2304d41e1877] +name = "Big Jet Plane" +author = "Restricted" +url = "https://www.youtube.com/watch?v=NpVF0z5N-tE" +source_type = "Youtube" + +[songs.201c6680-7dcf-4d75-8bdc-76ff9a715167] +name = "Gyvenimo man vieno neuztenka" +author = "SEL" +url = "https://youtu.be/7Gd9XaEG5o4" +source_type = "Youtube" + +[songs.d71c0e55-5d40-4045-853e-b32da713c0b8] +name = "Lietuva (Nebelinksmas musu kaimas)" +author = "Vytautas siskauskas" +url = "https://www.youtube.com/watch?v=31UkGzde14c" +source_type = "Youtube" + +[songs.92561031-92ae-471a-b154-8519c715011d] +name = "On The Rob" +author = "Cheap Dirty Horse" +url = "https://open.spotify.com/track/2kZ2fD3ohaGhDHMBTAppto" +source_type = "Spotify" + +[songs.9fabb799-f6aa-45a0-93b7-8cb08ab8f0a8] +name = "16 metu" +author = "69 Danguje" +url = "https://www.youtube.com/watch?v=nwjoqPcUPrw" +source_type = "Youtube" + +[songs.22f18d88-fb39-4cec-98be-02d4ebe3a6ee] +name = "Party maker" +author = "MUTA" +url = "https://www.youtube.com/watch?v=LT9VNK1aCXY" +source_type = "Youtube" + +[songs.90ae639e-0214-4a8e-b582-4949674ffaa2] +name = "Coco Jumbo" +author = "Mr President" +url = "https://www.youtube.com/watch?v=cOrc37wNUqU" +source_type = "Youtube" + +[songs.abd6a036-f17a-4a6a-8420-2cc3e7e4a181] +name = "Ten kazkur giliai" +author = "SEL" +url = "https://youtu.be/N7YNlegeiqs?si=9BBH6hjrgOjJ01Nz" +source_type = "Youtube" + +[songs.03f406b5-d5e9-4d22-b9bc-d0b36354400a] +name = "Diskoteka is 90 hit" +author = "Raim & Artur feat. Zhenis" +url = "https://www.youtube.com/watch?v=GfBhxlNhrn0" +source_type = "Youtube" + +[songs.2e9ef729-1560-446c-af6a-8a9d4c43ac9a] +name = "Big Sis" +author = "SALES" +url = "https://open.spotify.com/track/0ARp9mXXpPflIwehy25kCa" +source_type = "Spotify" + +[songs.2bd2e64e-28f0-4bd7-aee3-e1d27ed0797d] +name = "In the End" +author = "Linkin Park" +url = "https://open.spotify.com/track/60a0Rd6pjrkxjPbaKzXjfq" +source_type = "Spotify" + +[songs.9be83d96-6dfb-47a0-b58e-a1aed1cf6031] +name = "Pasitusinam" +author = "NL" +url = "https://www.youtube.com/watch?v=WhSFudvloog" +source_type = "Youtube" + +[songs.2b33d0b1-aecb-4ff9-841a-3a7b2861f28d] +name = "Degtine" +author = "Grupiokai" +url = "https://www.youtube.com/watch?v=8SqbG2VmEFw" +source_type = "Youtube" + +[songs.457bc1f5-f804-4665-a595-8e56a6558d1d] +name = "Sombrero" +author = "Kastanenda" +url = "https://www.youtube.com/watch?v=3Z3_4TknCfQ" +source_type = "Youtube" + +[songs.0491fd9f-149d-4e70-bc5c-0fae9a21d9b0] +name = "Rozovoe vino" +author = "Eldzej and Feduk" +url = "https://www.youtube.com/watch?v=S9oXj3a4gZ4" +source_type = "Youtube" + +[songs.85098bbc-86fa-4da4-b342-d2a512738060] +name = "Topolini puh" +author = "Unknown" +url = "https://www.youtube.com/watch?v=UUryvYF8tUs" +source_type = "Youtube" + +[songs.d8e93863-6102-4cda-a0b2-3728d20c9cf8] +name = "dashstar" +author = "Knock2" +url = "https://www.youtube.com/watch?v=58ml5b_On6w" +source_type = "Youtube" + +[songs.8858c7a1-ea6d-409b-9fc3-7256a39d4d8b] +name = "PENKTADIENIS" +author = "NIERKA" +url = "https://www.youtube.com/watch?v=h3TuZj_OAf0" +source_type = "Youtube" + +[songs.190a5577-124a-4232-9e6f-1d0a50f4d881] +name = "Cheri cheri lady" +author = "Unknown" +url = "https://www.youtube.com/watch?v=lrIKt5uDWZo" +source_type = "Youtube" + +[songs.08995ab0-2954-4d6b-913e-27609e90b354] +name = "Caramelldansen" +author = "Alfons, LOOKET, DJ BERIT" +url = "https://open.spotify.com/track/1v7aZHBUwKxeCgmpe6fVUH" +source_type = "Spotify" + +[songs.fc3f499b-2c33-41d0-b79c-ca68486b2a4d] +name = "Blaue Augen" +author = "08 Blumchen" +url = "https://www.youtube.com/watch?v=mE4PZcUfiwE" +source_type = "Youtube" + +[songs.5015106c-abcb-45c2-aed3-1f28674f92f6] +name = "Dance For Me" +author = "Unknown" +url = "https://www.youtube.com/watch?v=5DTSvGO_944" +source_type = "Youtube" + +[songs.4e903bfb-e9bf-49dc-a299-e08949ab78f9] +name = "DANCE" +author = "ROMANCEPLANET" +url = "https://www.youtube.com/watch?v=ircOfMb4gEw" +source_type = "Youtube" + +[songs.35877af8-65ad-4d85-9f18-93b98fd3ebd4] +name = "Le Son Dancefloor" +author = "Sweely" +url = "https://www.youtube.com/watch?v=5uEvZgmoG6Y" +source_type = "Youtube" + +[songs.4c849092-b6c4-450c-b69c-304e54f63611] +name = "Deginam" +author = "SADBOY" +url = "https://www.youtube.com/watch?v=w3R0Aq1EGXg" +source_type = "Youtube" + +[songs.fa7d62b1-2f9a-4499-b07b-ac3127c0f69f] +name = "Mano Skonis Sokolado (Matuze & Arnisxd Remix)" +author = "Sokoledas" +url = "https://soundcloud.com/matuze/sokoledas-mano-skonis-sokolado-matuze-arnisxd-remix" +source_type = "Soundcloud" + +[songs.795b22ae-d19e-4571-a5d7-fba5a66d5b6e] +name = "PLAIN WHITE TEE" +author = "ROMANCEPLANET" +url = "https://www.youtube.com/watch?v=tdVQbNwjGac" +source_type = "Youtube" + +[songs.c7867d88-60f2-483b-b435-883d4ff5b2f9] +name = "Alien Blues" +author = "Vundabar" +url = "https://open.spotify.com/track/11iIikXxC6NP0Ma8vMD27x" +source_type = "Spotify" + +[songs.eadbd827-0f71-4401-97bd-d11c365c3243] +name = "I Only See Things I Dont Have" +author = "Fidde" +url = "https://www.youtube.com/watch?v=vX_Ye_ZzI-Y" +source_type = "Youtube" + +[songs.0c5a22fc-2a61-4171-a5b9-f24da0c71466] +name = "As ziuriu i tave pasauli" +author = "SEL" +url = "https://youtu.be/_SPDjl80kKw" +source_type = "Youtube" + +[songs.8bf09666-9aba-4c71-a58a-a64200d49f9e] +name = "Cloud 9" +author = "Beach Bunny" +url = "https://open.spotify.com/track/6vFsBXYczYsP0H3lgunZOm" +source_type = "Spotify" + +[songs.65fe7b10-2395-47f4-b920-089fe0d129ac] +name = "Kelyje" +author = "Kastaneda" +url = "https://www.youtube.com/watch?v=JVE6NQqKPL4" +source_type = "Youtube" + +[songs.a0bd5ffe-4be8-498e-8f43-c5a9505a4872] +name = "Ten kur sapnai" +author = "SEL" +url = "https://youtu.be/GDj3NgjDbRo" +source_type = "Youtube" + +[songs.2eae7db0-4263-4870-b0c0-638a0d944c8e] +name = "Negeriau" +author = "DJ Dalgis" +url = "https://www.youtube.com/watch?v=c89YvG3MCcs" +source_type = "Youtube" + +[songs.80a169ba-f711-408c-834c-744bac3660ca] +name = "If Theres A Heaven I Wanna See It" +author = "Fidde" +url = "https://www.youtube.com/watch?v=l2Nw7cIh7qg" +source_type = "Youtube" + +[songs.8e82aa7c-a9e0-42ee-a845-6ba7d3439452] +name = "Apzavai" +author = "Vaidas Baumila" +url = "https://www.youtube.com/watch?v=H8uGi4ZMgHA" +source_type = "Youtube" + +[songs.2c650e29-9f87-4253-8074-146f3653051d] +name = "Satisfaction" +author = "Benny Benassi" +url = "https://www.youtube.com/watch?v=a0fkNdPiIL4" +source_type = "Youtube" + +[songs.6dd614cd-ba76-483c-bf6d-26eb1f3b6f1a] +name = "99 Red Balloons" +author = "Nena" +url = "https://open.spotify.com/track/7p8HVe22aGW1XtO1hoDHGo" +source_type = "Spotify" + +[songs.c72768c0-1f2e-4992-b66f-e569c572435a] +name = "Nezinau, Kodel..." +author = "Unknown" +url = "https://www.youtube.com/watch?v=A-i2CkCnPoc" +source_type = "Youtube" + +[songs.ae2c4c10-4fac-4d80-a114-81adf209c6a1] +name = "Kaip Diena" +author = "morre" +url = "https://www.youtube.com/watch?v=6LDgLWCQSSM" +source_type = "Youtube" + +[songs.d617c8c2-6237-40c4-8b47-b612a93c3689] +name = "vse shto nas ne Ubivaet" +author = "Pimp Schwab" +url = "https://www.youtube.com/watch?v=NTEXFyUE9Ww" +source_type = "Youtube" + +[songs.7da79c32-9eda-4897-be69-69fb39437404] +name = "Tricky Disco" +author = "DR. VODKA" +url = "https://www.youtube.com/watch?v=IknAUhl3i2o" +source_type = "Youtube" + +[songs.3525668b-4402-4fb8-b106-bed44d8c9db2] +name = "I Kluba" +author = "Raketa" +url = "https://www.youtube.com/watch?v=FkSjtpYN3EI" +source_type = "Youtube" + +[songs.c393d1a6-b265-4a73-a7bd-d33667b08445] +name = "Kauniete" +author = "DJ Dalgis" +url = "https://www.youtube.com/watch?v=b3xPE9Iyuzc" +source_type = "Youtube" + +[songs.009b9458-3205-4b13-9c65-03f16fea2293] +name = "Whiskey Cola Lietuviskai (sultys degtinele) remix" +author = "L1GHT CASH" +url = "https://www.youtube.com/watch?v=YVaqDaf1KXU" +source_type = "Youtube" + +[songs.484b9560-731b-447d-9e7f-3d32eb68b05f] +name = "Freed from Desire" +author = "Drenchill" +url = "https://www.youtube.com/watch?v=6b6FBneAENQ" +source_type = "Youtube" + +[songs.9d93859c-dae3-4c03-8f8d-d4f6bc0e287e] +name = "Jealous" +author = "Eyedress" +url = "https://open.spotify.com/track/1aXV8GrmQLvgoFtBPERP7E" +source_type = "Spotify" + +[songs.ec3edf2d-1e19-4c71-8f5c-e53d9cd06c3b] +name = "Cigarette Daydreams" +author = "Cage The Elephant" +url = "https://open.spotify.com/track/6jHvX8ZnHKC1PnrPMJ0Emt" +source_type = "Spotify" + +[songs.59c20651-6ffe-493d-886b-ccd8b7fe6dee] +name = "EVERYTHING WHAT" +author = "Unknown" +url = "https://www.youtube.com/watch?v=Gjdsq4kc5cA" +source_type = "Youtube" + +[songs.402a9066-127a-4a62-b711-50e979abbd51] +name = "Naktinis Tusas" +author = "Dove" +url = "https://www.youtube.com/watch?v=pz-HEAwFEnk" +source_type = "Youtube" + +[songs.7f2b2809-1b38-45b5-876c-cbdb42b26bdf] +name = "Volkswagina" +author = "Depresinis" +url = "https://www.youtube.com/watch?v=1lZR1VKsQHo" +source_type = "Youtube" + +[songs.9000f22e-83ff-4261-be0c-625fe1d806ab] +name = "MAMA MANE RODYS PER FARUS" +author = "Unknown" +url = "https://www.youtube.com/watch?v=F5HqXYRDZaE" +source_type = "Youtube" + +[songs.c374f3c2-b498-49b3-88c5-a2e6e741e1e8] +name = "Leisk" +author = "SEL" +url = "https://youtu.be/DDPmFMrffXQ" +source_type = "Youtube" + +[songs.0e33d04e-776e-4746-ab17-c4602d556716] +name = "1001 Naktis" +author = "SADBOY" +url = "https://www.youtube.com/watch?v=mLJIjGvWmKI" +source_type = "Youtube" + +[songs.7832d70f-2af3-417f-88dd-e193622ac599] +name = "DZIEWCZYNO Z TIKTOKA" +author = "DR. VODKA" +url = "https://www.youtube.com/watch?v=HLbw1WQt64o" +source_type = "Youtube" + +[songs.6a00704f-6da9-44d7-8fee-75cf487036f0] +name = "Lovoj Vezi" +author = "Tipo grupe" +url = "https://www.youtube.com/watch?v=M3zVMzWCy_c" +source_type = "Youtube" + +[songs.7e1d6501-ec53-4513-9917-84886d7523e5] +name = "Amerikonas grizo sunus" +author = "Zilvinas Zvagulis" +url = "https://www.youtube.com/watch?v=UvzJEz5ADY8" +source_type = "Youtube" + +[songs.e53d24bf-930d-490a-b41b-9b3382e24e3c] +name = "Truputi" +author = "Ganja" +url = "https://www.youtube.com/watch?v=Pxve7CwiCHM" +source_type = "Youtube" + +[songs.eb08806a-5fe3-46d7-a989-89f6a55187cc] +name = "Tailwhip (Lewii Edit)" +author = "Men I Trust" +url = "https://www.youtube.com/watch?v=XhyM-JUWwWQ" +source_type = "Youtube" + +[songs.78d3766c-7d79-43a1-aa37-f680cfd253e0] +name = "Perfect remix 1991" +author = "Mason" +url = "https://open.spotify.com/track/1VKWQgq0g2uKtgNfL0ceNM?si=b3f1dc504ddb41ed" +source_type = "Spotify" + +[songs.47001462-76c8-4aee-8ed4-65242600f840] +name = "Fireball" +author = "Pitbul" +url = "https://www.youtube.com/watch?v=HMqgVXSvwGo" +source_type = "Youtube" + +[songs.3453b523-e1f0-49d3-b60b-5ba063b6c26d] +name = "The Love Parade ( Bounce Invaderz )" +author = "Unknown" +url = "https://www.youtube.com/watch?v=xogT6KBWjCU3" +source_type = "Youtube" + +[songs.a6a20f00-cbf9-4506-9655-d6fd27944fea] +name = "Rhodes Trip" +author = "THEOS" +url = "https://www.youtube.com/watch?v=m7guRO0Uz_c" +source_type = "Youtube" + +[songs.9d482849-d488-4222-adc0-727f92babcab] +name = "Jau Nutilo Sirgaliai" +author = "Ciulpuoneliai" +url = "https://www.youtube.com/watch?v=s8qIVA1U0C0" +source_type = "Youtube" + +[songs.6bc8cd16-722b-42e4-9824-a1de9c67029f] +name = "Tears Drop" +author = "Baltra" +url = "https://www.youtube.com/watch?v=EXXMtKPfuzY" +source_type = "Youtube" + +[songs.34e3c90b-7763-4154-9035-367e22ed7d75] +name = "Robinzonas" +author = "Vitalija Katunskyte" +url = "https://www.youtube.com/watch?v=erDHG-QpbPY" +source_type = "Youtube" + +[songs.a59cb678-f229-43cf-b438-4ce53b7264ae] +name = "R1" +author = "NL" +url = "https://www.youtube.com/watch?v=hSgav4fYnZ8" +source_type = "Youtube" + +[songs.7d232736-f977-4645-bd64-106e94f91bb0] +name = "Judam Lietuvoj" +author = "Unknown" +url = "https://www.youtube.com/watch?v=WDzWSEgSy5U" +source_type = "Youtube" + +[songs.9e6095bb-8b05-40eb-b5d3-b6410ac65171] +name = "C'est Beau La Bourgeoisie" +author = "Discobitch" +url = "https://www.youtube.com/watch?v=RCeQN2aEWxo" +source_type = "Youtube" + +[songs.9d7a0837-04d4-40f7-92dc-48c7db70be51] +name = "As Judu" +author = "Adomas Vysniauskas" +url = "https://www.youtube.com/watch?v=dMm16TzZrjg" +source_type = "Youtube" + +[songs.2f179aab-c51b-4501-b5d1-8a2e51b19a80] +name = "Applause" +author = "Nicolas Julian" +url = "https://www.youtube.com/watch?v=9qHLELnq1B0" +source_type = "Youtube" + +[songs.1e77552d-702f-4c61-8e9f-bd02bbafe434] +name = "Morning Sex (Mochakk Remix)" +author = "Ralph Castelli" +url = "https://www.youtube.com/watch?v=6bCwJ_TIDG4" +source_type = "Youtube" + +[songs.be09f147-cda5-4e5f-ac29-eef9c3a7414f] +name = "Blue Monday" +author = "MOGUAI, Tim Hox, Iggy" +url = "https://open.spotify.com/track/4vAP9OY2Ci79fUCuc9EBdD" +source_type = "Spotify" + +[songs.7ed02ac9-cb84-4a34-870d-56b226f0a6be] +name = "Always Forever" +author = "Cults" +url = "https://open.spotify.com/track/2enPRFda84VE2wtI8c86Uf" +source_type = "Spotify" + +[songs.6d78099b-042c-4b19-b3d9-15af1bf4ef10] +name = "JUODA ORCHIDEJA" +author = "MG INTERNATIONAL" +url = "https://www.youtube.com/watch?v=HQvceFRBq9M" +source_type = "Youtube" + +[songs.56684f28-ff1a-4f65-a585-e9ea532babb2] +name = "AUDI" +author = "MC ENDRAY" +url = "https://www.youtube.com/watch?v=oIjNoMGEuRg" +source_type = "Youtube" + +[songs.f1878fda-ecec-4303-a6df-dc6adf1ea3c0] +name = "Juodas Garvezys (Remix)" +author = "Unknown" +url = "https://www.youtube.com/watch?v=D-7qQbXHSAw" +source_type = "Youtube" + +[songs.70a80d91-581e-4599-81e6-d047f28e9068] +name = "Margarita" +author = "Rondo" +url = "https://www.youtube.com/watch?v=rF4w-Rxsiv4" +source_type = "Youtube" + +[songs.192a8655-7dfc-4c4b-b351-87c75cbbe048] +name = "It Wasn't Me" +author = "Shaggy" +url = "https://www.youtube.com/watch?v=ssVj50ombaM" +source_type = "Youtube" + +[songs.7b680328-e576-4185-a5da-3c37de98ca42] +name = "cabin fever" +author = "re6ce" +url = "https://open.spotify.com/track/3c3oUMxOr2cVFBY6V3v08C" +source_type = "Spotify" + +[songs.383cb60f-13fd-4947-9924-6c5d8c39d453] +name = "Kur Tu" +author = "Patruliai" +url = "https://www.youtube.com/watch?v=OPWhiu3cvj0" +source_type = "Youtube" + +[songs.bcb9af16-7bdb-458a-b092-42225abf2645] +name = "LEDUKAI" +author = "Depresinis feat. Deivas" +url = "https://www.youtube.com/watch?v=R2-MtpkKgGI" +source_type = "Youtube" + +[songs.50186034-e8b4-4778-81e3-ab327e54dbff] +name = "We Are The People" +author = "Empire Of The Sun, southstar" +url = "https://www.youtube.com/watch?v=qguEGR5BK2k" +source_type = "Youtube" + +[songs.080d60fb-bdf1-40f3-8b81-967c5ea2fe44] +name = "moi marmeladni (paprobui mua mua)" +author = "Katja lel" +url = "https://www.youtube.com/watch?v=0JMdXFHo5SY" +source_type = "Youtube" + +[songs.4a4abe26-de77-4e0f-83c9-8eab9ca32281] +name = "Parnesk alaus OG" +author = "Unknown" +url = "https://www.youtube.com/watch?v=e7cB1JIlZ2k" +source_type = "Youtube" + +[songs.017e1086-7ca7-4788-834d-5490e0cf8276] +name = "Mersas" +author = "Tweaxx" +url = "https://www.youtube.com/watch?v=7ljAzgALPdA" +source_type = "Youtube" + +[songs.a1ab9370-70bc-488d-a78b-5cdc09c82f73] +name = "Trys Trys Trys" +author = "Riaukenzo" +url = "https://www.youtube.com/watch?v=qJv6GRQCnCk" +source_type = "Youtube" + +[songs.0e969066-b7f9-4e60-a24f-989aad28dfac] +name = "Svajoklis" +author = "Vairas" +url = "https://www.youtube.com/watch?v=hs8_KTV0Vrw" +source_type = "Youtube" + +[songs.8c641f7f-e151-4abc-932c-a9895823a278] +name = "Nevaidink" +author = "SixthBoi" +url = "https://www.youtube.com/watch?v=nOTNnnrqTII" +source_type = "Youtube" + +[songs.cbc90bff-5476-408c-9cc8-afd1af5b536d] +name = "Vienna" +author = "Billy Joel" +url = "https://open.spotify.com/track/4U45aEWtQhrm8A5mxPaFZ7" +source_type = "Spotify" + +[songs.d01635a4-1a28-4d86-a524-9876eb3094de] +name = "VAIKAI PO LELIJOM (REMIX)" +author = "Unknown" +url = "https://www.youtube.com/watch?v=k1amBbsAZuo" +source_type = "Youtube" + +[songs.d286a3a7-ab7b-488c-9c68-b7521e290c5e] +name = "Bossa Nova (Lewii Edit)" +author = "Billie Eilish" +url = "https://www.youtube.com/watch?v=gNawHj2NCxA" +source_type = "Youtube" + +[songs.0c77785e-7149-45a7-84a1-a9c8ccaa9f7f] +name = "Lyja" +author = "SEL" +url = "https://www.youtube.com/watch?v=KL6JBWnXCxw" +source_type = "Youtube" + +[songs.3ea2a490-749f-4956-b7ef-bb0c428663a9] +name = "Dabar Geriausi Musu Vakarai" +author = "Vilija ir Marijonas mikutavicius" +url = "https://www.youtube.com/watch?v=MPnZkEscWo0" +source_type = "Youtube" + +[songs.8fcad64e-bb63-414b-9cad-243f1f4c4293] +name = "FALL FROM THE SKY" +author = "ROMANCEPLANET" +url = "https://www.youtube.com/watch?v=HMhzxzXBisw" +source_type = "Youtube" + +[songs.88fe04aa-a7be-4f6c-b32f-d3d25e58bbf8] +name = "Because I Got High" +author = "Afroman" +url = "https://www.youtube.com/watch?v=WeYsTmIzjkw" +source_type = "Youtube" + +[songs.d8423579-1225-4865-9955-149e6878b59d] +name = "Black Sabbath" +author = "Unknown" +url = "https://www.youtube.com/watch?v=BOTIIw76qiE" +source_type = "Youtube" + +[songs.b23f9b7f-1668-43f0-a1bd-9471759db18f] +name = "Juda Tavo rankos" +author = "Elektra" +url = "https://www.youtube.com/watch?v=k2RuDoudnOE" +source_type = "Youtube" + +[songs.615d63ee-51aa-4ac2-b826-9a41f59b8622] +name = "I Love It" +author = "Icona Pop" +url = "https://www.youtube.com/watch?v=UxxajLWwzqY" +source_type = "Youtube" + +[songs.41a8d7c8-4b75-46f6-9940-7f0b8f5f5feb] +name = "Beggin' (Techno)" +author = "Unknown" +url = "https://www.youtube.com/watch?v=tXPs1FwW6lk" +source_type = "Youtube" + +[songs.bf529d54-1ad0-4396-84c7-82bd7fe495c6] +name = "P.R.O.T.E.C.T.T.R.A.N.S.K.I.D.S." +author = "Cheap Dirty Horse" +url = "https://open.spotify.com/track/1ytHY16pP1P6A2noeiPXuU" +source_type = "Spotify" + +[songs.83ff90a9-4a19-4a66-a452-c2bafdfb884b] +name = "You're My Heart, You're My Soul" +author = "Modern Talking" +url = "https://www.youtube.com/watch?v=4kHl4FoK1Ys" +source_type = "Youtube" + +[songs.ee1e8d12-75ac-43f7-bf85-a1b69eb66e86] +name = "Vanished" +author = "Crystal Castles" +url = "https://open.spotify.com/track/3gGMsx3jxYKfhXq8LMj1tz" +source_type = "Spotify" + +[songs.83808446-bd43-4140-86ff-853fea897a89] +name = "Bla Bla Bla" +author = "Gigi D'Agostino" +url = "https://www.youtube.com/watch?v=yKapqR2XRJE" +source_type = "Youtube" + +[songs.a950fac9-3b5f-4215-8a49-7680fd5b90bf] +name = "Gyvenu" +author = "69 Danguje" +url = "https://www.youtube.com/watch?v=HMXlhmAoux4" +source_type = "Youtube" + +[songs.b0732ead-9a8c-4537-b98a-a4618d33959f] +name = "O Mazuti" +author = "Depresinis, Jypas" +url = "https://www.youtube.com/watch?v=4t_DPbe2r3M" +source_type = "Youtube" + +[songs.101166d0-1b7c-4d1c-b0ce-35b9a89b0822] +name = "Nes as tik vejas" +author = "SEL" +url = "https://youtu.be/acMG37IZ6z8" +source_type = "Youtube" + +[songs.2645c0f2-fade-489a-87ad-261d5d983ef6] +name = "Bad Boys" +author = "Unknown" +url = "https://www.youtube.com/watch?v=NTC7RD8xzCY" +source_type = "Youtube" + +[songs.6bfe21f8-b6e5-409b-b6cb-a5692f6dfeeb] +name = "Welcome To The Club" +author = "Manian" +url = "https://www.youtube.com/watch?v=7F9xDewtgNA" +source_type = "Youtube" + +[songs.8dca8d6c-3388-4133-b773-79b9f076e467] +name = "0,7" +author = "Depresinis feat. Deivas" +url = "https://www.youtube.com/watch?v=rjwFjBgTzAA" +source_type = "Youtube" + +[songs.afdc69fa-c2ee-4dee-9794-e3166fc9dd20] +name = "Pedro (Jaxomy & Agatino Romero Remix)" +author = "Raffaella Carra" +url = "https://www.youtube.com/watch?v=AIGnRc7F86Q" +source_type = "Youtube" + +[songs.47f2a63e-e9eb-48df-a61b-dbcdfa3aaf35] +name = "Everlong" +author = "Foo Fighters" +url = "https://open.spotify.com/track/5UWwZ5lm5PKu6eKsHAGxOk" +source_type = "Spotify" + +[songs.cec368bd-6b4c-4c89-9eeb-1b88bed0efc3] +name = "PARIS (TECHNO)" +author = "$UICIDEBOY$" +url = "https://www.youtube.com/watch?v=YYDJmGDkEyw" +source_type = "Youtube" + +[songs.83b50be2-c286-4dcc-9e7f-cacf5e4031fe] +name = "Not Fair" +author = "Lily Allen" +url = "https://www.youtube.com/watch?v=WON_YIbeLis" +source_type = "Youtube" + +[songs.6f28b04a-588e-4a81-8b4e-aa4ed4f88e31] +name = "Pavasaris" +author = "Depresinis feat. Deivas" +url = "https://www.youtube.com/watch?v=yWWAucfQdN4" +source_type = "Youtube" + +[songs.20945b3f-e9d6-4023-9a97-4a04424cc8a3] +name = "Basket Case" +author = "Green Day" +url = "https://www.youtube.com/watch?v=wZ8eZRxFA-0" +source_type = "Youtube" + +[playlists.ba68f47d-384d-4808-a69d-48c6a85be479] +name = "electronic" +author = "Unknown" +songs = [ + "81426b49-3511-4e48-be21-3c24acba0fb9", + "2c650e29-9f87-4253-8074-146f3653051d", + "9ef33d55-972d-490c-95c6-bf046bf4f979", +] + +[playlists.8e806ac3-63d9-4366-95d6-04f5a0aae31e] +name = "rusiskos" +author = "Unknown" +songs = [ + "76f7945f-e677-4297-a98a-708314f92de8", + "0491fd9f-149d-4e70-bc5c-0fae9a21d9b0", + "4a7b1853-7529-498d-addf-25e894a37ccf", + "6c3f2503-0160-4c42-8b17-25ff402f3fa7", + "3b2573d4-2e1b-4446-a377-5fcb2b0a70c5", + "03f406b5-d5e9-4d22-b9bc-d0b36354400a", + "85098bbc-86fa-4da4-b342-d2a512738060", + "d617c8c2-6237-40c4-8b47-b612a93c3689", + "080d60fb-bdf1-40f3-8b81-967c5ea2fe44", +] + +[playlists.27afdb2f-2672-43f1-8a55-b7c6bbb7927a] +name = "lietuviskos" +author = "Unknown" +songs = [ + "8e8c3f6c-e34b-4f4e-b9be-f36be5901435", + "7d232736-f977-4645-bd64-106e94f91bb0", + "ae2c4c10-4fac-4d80-a114-81adf209c6a1", + "34e3c90b-7763-4154-9035-367e22ed7d75", + "858d8645-8637-4d3f-b4b7-c9c75743d90a", + "a1ab9370-70bc-488d-a78b-5cdc09c82f73", + "8858c7a1-ea6d-409b-9fc3-7256a39d4d8b", + "009b9458-3205-4b13-9c65-03f16fea2293", + "8dca8d6c-3388-4133-b773-79b9f076e467", + "9be83d96-6dfb-47a0-b58e-a1aed1cf6031", + "0e969066-b7f9-4e60-a24f-989aad28dfac", + "9d482849-d488-4222-adc0-727f92babcab", + "6d78099b-042c-4b19-b3d9-15af1bf4ef10", + "bd85a9d7-1fb6-4154-a290-e5137590e419", + "131ab436-869b-4b3b-8ce4-3b5087d3461f", + "1a22e35a-0af1-4326-b59c-00d59504446b", + "bcb9af16-7bdb-458a-b092-42225abf2645", + "3525668b-4402-4fb8-b106-bed44d8c9db2", + "4c849092-b6c4-450c-b69c-304e54f63611", + "8c641f7f-e151-4abc-932c-a9895823a278", + "c393d1a6-b265-4a73-a7bd-d33667b08445", + "ea41c37c-7b62-4fd6-9fec-650e94d184f2", + "8e82aa7c-a9e0-42ee-a845-6ba7d3439452", + "9000f22e-83ff-4261-be0c-625fe1d806ab", + "402a9066-127a-4a62-b711-50e979abbd51", + "4b61344d-fa89-4b79-bd45-3b1fc8c8cc1c", + "7e1d6501-ec53-4513-9917-84886d7523e5", + "9fabb799-f6aa-45a0-93b7-8cb08ab8f0a8", + "ca765223-e4e6-4b5d-8928-919c3f491b43", + "16dafb40-ebac-4e04-961a-99d79789f1a3", + "95a3350c-c62f-4543-8cfe-6c512861b229", + "720d5b94-ac54-4162-8da7-ba8d258139e6", + "c28f14ca-ec10-469a-b0cc-3e26e9f56007", + "6a00704f-6da9-44d7-8fee-75cf487036f0", + "4eafd817-d75a-451e-b6b4-38ef29e66fdf", + "b0732ead-9a8c-4537-b98a-a4618d33959f", + "2b33d0b1-aecb-4ff9-841a-3a7b2861f28d", + "2374179d-d6a8-41b9-9cac-21147303fc8e", + "f1878fda-ecec-4303-a6df-dc6adf1ea3c0", + "7f2b2809-1b38-45b5-876c-cbdb42b26bdf", + "65fe7b10-2395-47f4-b920-089fe0d129ac", + "dfc0782c-33f2-414d-9b56-76a77902bcc5", + "b23f9b7f-1668-43f0-a1bd-9471759db18f", + "0e33d04e-776e-4746-ab17-c4602d556716", + "0b907d17-e3f9-4dbb-9c2d-e10327316f6e", + "fa339b0b-8d3a-45e7-aed9-f744afb4a666", + "eb91fc63-4e0e-49e9-99c7-ea7fe5770a5b", + "4cf5e323-5e79-4471-816a-5fa345854cea", + "d01635a4-1a28-4d86-a524-9876eb3094de", + "017e1086-7ca7-4788-834d-5490e0cf8276", + "c332ce2b-6b1c-4979-9977-dc00aa6e710b", + "d71c0e55-5d40-4045-853e-b32da713c0b8", + "70a80d91-581e-4599-81e6-d047f28e9068", + "3ea2a490-749f-4956-b7ef-bb0c428663a9", + "4f368ef5-08d0-4d1f-b8ba-a34ee9fc6aa2", + "870502f1-e3a9-419b-9ba6-d8100d1198a5", + "75c6e1aa-21c7-4626-9def-602d656282bc", + "a59cb678-f229-43cf-b438-4ce53b7264ae", + "a950fac9-3b5f-4215-8a49-7680fd5b90bf", + "9d7a0837-04d4-40f7-92dc-48c7db70be51", + "e9495391-8a6c-4942-9dc6-09b764f9d1e9", + "2eae7db0-4263-4870-b0c0-638a0d944c8e", + "6f28b04a-588e-4a81-8b4e-aa4ed4f88e31", + "05a28184-e58e-42c3-a803-512bb0817a07", + "457bc1f5-f804-4665-a595-8e56a6558d1d", + "4a4abe26-de77-4e0f-83c9-8eab9ca32281", + "dc6c36b0-f595-457f-8fc3-641710b0e3b9", + "0e1d36ed-d07d-48c0-a101-1bf1ac6d7a26", + "56684f28-ff1a-4f65-a585-e9ea532babb2", + "73ddd372-4853-4182-b212-b021e7dc8988", + "b26f7338-0d1f-4dba-b639-3bdae9d7e10e", + "639dc5af-b3e6-4d38-a003-80deac01d326", + "e53d24bf-930d-490a-b41b-9b3382e24e3c", + "02d90830-7b5f-430f-b82c-f45998862e81", + "407155fd-3174-4778-ae93-bb01b7518f9f", + "df2e369f-2fee-49e5-b52c-33f73c34ffb2", + "27d61e87-deec-4e4c-8015-ad8b691eea40", + "383cb60f-13fd-4947-9924-6c5d8c39d453", + "c72768c0-1f2e-4992-b66f-e569c572435a", + "eaf1cc63-3eb6-4d86-a986-e8129fff7fcb", +] + +[playlists.e4203363-48dd-430c-8a63-f997ebe7e2bc] +name = "hip-hop" +author = "Unknown" +songs = [ + "88fe04aa-a7be-4f6c-b32f-d3d25e58bbf8", + "484b9560-731b-447d-9e7f-3d32eb68b05f", +] + +[playlists.a906d80f-2028-407e-8263-6eacb53325a2] +name = "lietuviskos/rave" +author = "Unknown" +songs = [ + "2b19ae9f-2321-41fc-8a1f-2bb4c2975380", + "fa7d62b1-2f9a-4499-b07b-ac3127c0f69f", +] + +[playlists.b633b0c7-8151-4b5c-bf18-a0b8d2f85f27] +name = "Ours <3" +author = "Unknown" +songs = [ + "e71a61d4-b54a-47d1-b0ad-db6695bd0739", + "bf529d54-1ad0-4396-84c7-82bd7fe495c6", + "7e32803d-a5a9-453c-8c81-b479c51e5bc9", + "6dd614cd-ba76-483c-bf6d-26eb1f3b6f1a", + "9866acdd-97ee-4e19-ba20-a64caa9b02ee", + "ee1e8d12-75ac-43f7-bf85-a1b69eb66e86", + "5c2ee27e-d564-404a-8259-87d1d336f106", + "f5a31a44-fc62-4cce-b65e-05e4085864fe", + "7b680328-e576-4185-a5da-3c37de98ca42", + "877c24e4-c0c0-4e9c-a553-221e381c8a00", + "d563619a-344e-41cf-99d1-5a52214ada49", + "92561031-92ae-471a-b154-8519c715011d", + "cd72e9db-aaa4-485e-b3a5-7fbeed2cff36", + "9d93859c-dae3-4c03-8f8d-d4f6bc0e287e", + "bb16708f-0cd7-4918-8014-d374d68acbd2", + "be09f147-cda5-4e5f-ac29-eef9c3a7414f", + "7ed02ac9-cb84-4a34-870d-56b226f0a6be", + "47f2a63e-e9eb-48df-a61b-dbcdfa3aaf35", + "e37c6cb6-ad8e-43a7-83d1-8b795db8aa1c", + "3d543d58-e33d-4158-9956-049309baa35c", + "2e9ef729-1560-446c-af6a-8a9d4c43ac9a", + "ec3edf2d-1e19-4c71-8f5c-e53d9cd06c3b", + "c7867d88-60f2-483b-b435-883d4ff5b2f9", + "cbc90bff-5476-408c-9cc8-afd1af5b536d", + "2bd2e64e-28f0-4bd7-aee3-e1d27ed0797d", + "08995ab0-2954-4d6b-913e-27609e90b354", + "862ddd87-68c4-4bed-a8cd-0e2021a0ce79", + "0679475a-259c-4c98-9ae7-a58c10dfeedb", + "6895e921-91f2-4713-b604-c2cdd9f3f1c2", + "8bf09666-9aba-4c71-a58a-a64200d49f9e", +] + +[playlists.2391911d-2d2c-4c33-b8f5-1a6e543512cc] +name = "noclue" +author = "Unknown" +songs = [ + "9e6095bb-8b05-40eb-b5d3-b6410ac65171", + "7832d70f-2af3-417f-88dd-e193622ac599", + "518e23e8-72df-42de-a918-6a9a197deb9a", + "2645c0f2-fade-489a-87ad-261d5d983ef6", +] + +[playlists.c3ebcdd5-82b6-49b3-a340-dc786a66eee6] +name = "reggea" +author = "Unknown" +songs = ["192a8655-7dfc-4c4b-b351-87c75cbbe048"] + +[playlists.5f2e4043-cb32-4e90-9fb6-69f0466d6398] +name = "house" +author = "Unknown" +songs = [ + "80a169ba-f711-408c-834c-744bac3660ca", + "b0c0d44c-86ca-4b80-a081-734a4178c870", + "eadbd827-0f71-4401-97bd-d11c365c3243", + "eb08806a-5fe3-46d7-a989-89f6a55187cc", + "6bc8cd16-722b-42e4-9824-a1de9c67029f", + "1e77552d-702f-4c61-8e9f-bd02bbafe434", + "35877af8-65ad-4d85-9f18-93b98fd3ebd4", + "a6a20f00-cbf9-4506-9655-d6fd27944fea", + "d286a3a7-ab7b-488c-9c68-b7521e290c5e", + "f81f8f9d-6c56-4ae3-8f5f-28c04632d3b5", +] + +[playlists.8c9d2cf1-6f0b-4ea9-993a-c3193867a914] +name = "rave" +author = "Unknown" +songs = [ + "59c20651-6ffe-493d-886b-ccd8b7fe6dee", + "78d3766c-7d79-43a1-aa37-f680cfd253e0", + "7da79c32-9eda-4897-be69-69fb39437404", + "0ee56450-2942-4805-9f08-b49652472258", +] + +[playlists.7d7c0020-7daa-4d85-8aa9-311f24eeb702] +name = "lietuviskos/sel" +author = "Unknown" +songs = [ + "60214f0e-9a37-49b4-92bf-b7b548e501ad", + "e1cb8b00-713b-4a0e-bc61-dbf2d2596fcf", + "abd6a036-f17a-4a6a-8420-2cc3e7e4a181", + "a0bd5ffe-4be8-498e-8f43-c5a9505a4872", + "201c6680-7dcf-4d75-8bdc-76ff9a715167", + "18c2b9bc-6403-4a67-94bd-1e9f5413d83b", + "c374f3c2-b498-49b3-88c5-a2e6e741e1e8", + "0c5a22fc-2a61-4171-a5b9-f24da0c71466", + "0c77785e-7149-45a7-84a1-a9c8ccaa9f7f", + "98b04764-39cc-4c82-a2e2-420dd85573ca", + "101166d0-1b7c-4d1c-b0ce-35b9a89b0822", +] + +[playlists.4230f218-7de4-463c-a42f-ad05c745de5a] +name = "techno" +author = "Unknown" +songs = [ + "3453b523-e1f0-49d3-b60b-5ba063b6c26d", + "6bfe21f8-b6e5-409b-b6cb-a5692f6dfeeb", + "41a8d7c8-4b75-46f6-9940-7f0b8f5f5feb", + "fc3f499b-2c33-41d0-b79c-ca68486b2a4d", + "22f18d88-fb39-4cec-98be-02d4ebe3a6ee", + "4a56c71c-70f0-45e7-a9b8-2304d41e1877", + "5015106c-abcb-45c2-aed3-1f28674f92f6", + "2f179aab-c51b-4501-b5d1-8a2e51b19a80", + "83b50be2-c286-4dcc-9e7f-cacf5e4031fe", + "22565196-5757-4767-8f1f-f1c9b8a87dcc", + "83808446-bd43-4140-86ff-853fea897a89", + "50186034-e8b4-4778-81e3-ab327e54dbff", + "afdc69fa-c2ee-4dee-9794-e3166fc9dd20", + "91629850-33e2-4e18-8c37-6eafdfcde3f4", + "d8e93863-6102-4cda-a0b2-3728d20c9cf8", + "cec368bd-6b4c-4c89-9eeb-1b88bed0efc3", +] + +[playlists.a37e3c7c-584d-4803-981b-5be9244dd7c1] +name = "rock" +author = "Unknown" +songs = ["d8423579-1225-4865-9955-149e6878b59d"] + +[playlists.cb15d471-58bc-4d5a-9e3c-b13e1433818c] +name = "pop" +author = "Unknown" +songs = [ + "83ff90a9-4a19-4a66-a452-c2bafdfb884b", + "f3edb436-bf04-4ad5-ad45-684a601846c3", + "20945b3f-e9d6-4023-9a97-4a04424cc8a3", + "90ae639e-0214-4a8e-b582-4949674ffaa2", + "615d63ee-51aa-4ac2-b826-9a41f59b8622", + "190a5577-124a-4232-9e6f-1d0a50f4d881", + "47001462-76c8-4aee-8ed4-65242600f840", +] + +[playlists.ff11b5bc-6bf7-4cdd-a47a-023dcc68a8c3] +name = "alt" +author = "Unknown" +songs = [ + "4e903bfb-e9bf-49dc-a299-e08949ab78f9", + "bc5fe406-040b-4c46-82ce-bb4505b81947", + "8fcad64e-bb63-414b-9cad-243f1f4c4293", + "795b22ae-d19e-4571-a5d7-fba5a66d5b6e", +] diff --git a/xmpd-cache/src/downloader/song.rs b/xmpd-cache/src/downloader/song.rs index d2b5627..11f7cee 100644 --- a/xmpd-cache/src/downloader/song.rs +++ b/xmpd-cache/src/downloader/song.rs @@ -108,11 +108,12 @@ impl SongCacheDl { } let mut from = song_p.clone(); from.pop(); - from.push("{song_format}.{song_format}"); + from.push(format!("{song_format}.{song_format}")); let mut to = song_p.clone(); to.pop(); to.set_extension(&song_format); + log::debug!("from: {from:?} to: {to:?}"); std::fs::copy(&from, &to).unwrap(); from.pop(); std::fs::remove_dir_all(from).unwrap(); diff --git a/xmpd-cache/src/lib.rs b/xmpd-cache/src/lib.rs index 91e7bc1..ed3774d 100644 --- a/xmpd-cache/src/lib.rs +++ b/xmpd-cache/src/lib.rs @@ -1,6 +1,5 @@ use std::{collections::HashMap, str::FromStr, sync::{mpsc::{self, Receiver, Sender}, Arc, Mutex, MutexGuard}, time::Duration}; use downloader::song::SongStatus; -use log::warn; use xmpd_manifest::song::Song; pub mod downloader; @@ -106,7 +105,6 @@ fn start_cache_mv_thread(tx: Sender) { song_p.push("songs"); song_p.push(sid.clone().to_string()); let song_p = song_p.with_extension(&song_format); - log::debug!("Found done: {:?}: {}", song_p, song_p.exists()); if song_p.exists() { let _ = tx.send(Message::DownloadDone(sid.clone())); cache.song_cache.insert(sid.clone(), DlStatus::Done(song_p)); diff --git a/xmpd-core/Cargo.toml b/xmpd-core/Cargo.toml index ec37421..b15e1d4 100644 --- a/xmpd-core/Cargo.toml +++ b/xmpd-core/Cargo.toml @@ -30,3 +30,6 @@ camino.workspace = true anyhow.workspace = true log.workspace = true env_logger.workspace = true + +[build-dependencies] +winresource.workspace = true diff --git a/xmpd-core/build.rs b/xmpd-core/build.rs new file mode 100644 index 0000000..bfe89d0 --- /dev/null +++ b/xmpd-core/build.rs @@ -0,0 +1,11 @@ +use winresource::WindowsResource; + +fn main() -> std::io::Result<()> { + if std::env::var_os("CARGO_CFG_WINDOWS").is_some() { + WindowsResource::new() + // This path can be absolute, or relative to your crate root. + .set_icon("../assets/icon.ico") + .compile()?; + } + Ok(()) +} diff --git a/xmpd-gui/Cargo.toml b/xmpd-gui/Cargo.toml index 7d43d71..8e7a187 100644 --- a/xmpd-gui/Cargo.toml +++ b/xmpd-gui/Cargo.toml @@ -22,13 +22,14 @@ xmpd-manifest.path = "../xmpd-manifest" xmpd-settings.path = "../xmpd-settings" xmpd-cliargs.path = "../xmpd-cliargs" xmpd-cache.path = "../xmpd-cache" +xmpd-player.path = "../xmpd-player" egui.workspace = true eframe.workspace = true -tokio.workspace = true anyhow.workspace = true lazy_static.workspace = true log.workspace = true egui_extras.workspace = true -egui-aesthetix = "0.2.4" uuid.workspace = true camino.workspace = true +rfd.workspace = true +dirs.workspace = true diff --git a/xmpd-gui/src/components/left_nav.rs b/xmpd-gui/src/components/left_nav.rs index 11d1b63..824c13e 100644 --- a/xmpd-gui/src/components/left_nav.rs +++ b/xmpd-gui/src/components/left_nav.rs @@ -1,4 +1,4 @@ -use egui::RichText; +use egui::{CursorIcon, RichText, Sense}; use xmpd_manifest::store::BaseStore; use super::{CompGetter, CompUi}; @@ -50,6 +50,7 @@ fn add_playlist_tab(ui: &mut egui::Ui, pid: &Option, title: &str, au ui.add( egui::Image::new(crate::data::NOTE_ICON) .tint(theme.accent_color) + .sense(Sense::click()) .fit_to_exact_size(egui::Vec2::new(32.0, 32.0)) ); ui.vertical(|ui| { @@ -83,9 +84,13 @@ fn add_playlist_tab(ui: &mut egui::Ui, pid: &Option, title: &str, au }); }).response.rect; - if ui.interact(wdg_rect, format!("left_nav_playlist_{pid:?}").into(), egui::Sense::click()).clicked() { + let blob = ui.interact(wdg_rect, format!("left_nav_playlist_{pid:?}").into(), egui::Sense::click()); + if blob.clicked() { handle_error_ui!(LeftNav::get()).selected_playlist_id = pid.clone(); } + if blob.hovered() { + ui.output_mut(|o| o.cursor_icon = CursorIcon::PointingHand); + } ui.separator(); } diff --git a/xmpd-gui/src/components/player.rs b/xmpd-gui/src/components/player.rs index b3832ac..bfd97ec 100644 --- a/xmpd-gui/src/components/player.rs +++ b/xmpd-gui/src/components/player.rs @@ -1,19 +1,30 @@ use egui::{Sense, Stroke, Vec2}; -use super::{CompGetter, CompUi}; +use super::{song_list::SongList, CompGetter, CompUi}; -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Player { slider_progress: usize, - is_playing: bool, + old_slider_progress: usize, + volume_slider: f64, +} + +impl Default for Player { + fn default() -> Self { + Self { + volume_slider: 1.0, + old_slider_progress: 0, + slider_progress: 0 + } + } } component_register!(Player); impl CompUi for Player { - fn draw(ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> { + fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> { let theme = xmpd_settings::Settings::get()?.theme.clone(); let avail = ui.available_size(); ui.vertical_centered_justified(|ui| { @@ -21,10 +32,7 @@ impl CompUi for Player { ui.horizontal(|ui| { { ui.add_space(avail.x * 0.05 / 2.0); - let mut slf = handle_error_ui!(Player::get()); - let slider = egui::Slider::new(&mut slf.slider_progress, 0..=100) - .show_value(false); - ui.style_mut().spacing.slider_width = avail.x * 0.90; + ui.style_mut().spacing.slider_width = avail.x * 0.87; let s = Stroke { color: theme.accent_color, width: 2.0 @@ -32,19 +40,35 @@ impl CompUi for Player { ui.style_mut().visuals.widgets.inactive.fg_stroke = s; ui.style_mut().visuals.widgets.active.fg_stroke = s; ui.style_mut().visuals.widgets.hovered.fg_stroke = s; - ui.add(slider); - ui.label("00:00"); + + let mut slf = handle_error_ui!(Player::get()); + ui.add( + egui::Slider::new(&mut slf.slider_progress, 0..=100) + .show_value(false) + ); + if slf.slider_progress == slf.old_slider_progress { + slf.slider_progress = (state.player.get_played_f() * 100.0) as usize; + slf.old_slider_progress = slf.slider_progress; + } else { + handle_error_ui!(state.player.seek_to_f(slf.slider_progress as f64 / 100.0 )); + slf.old_slider_progress = slf.slider_progress; + } + let secs_left = state.player.get_ms_left() as f64 / 1000.0; + let h = (secs_left/60.0/60.0).floor(); + let m = ((secs_left - h * 60.0)/60.0).floor(); + let s = (secs_left - m * 60.0).floor(); + + ui.label(format!("{h:02}:{m:02}:{s:02}")); } }); ui.horizontal(|ui| { ui.add_space((avail.x / 2.0) - 16.0 - 8.0 - ui.spacing().item_spacing.x); - let pp = if handle_error_ui!(Player::get()).is_playing { - crate::data::PAUSE_ICON - } else { + let pp = if state.player.is_paused() { crate::data::PLAY_ICON + } else { + crate::data::PAUSE_ICON }; - let prev = egui::Image::new(crate::data::PREV_ICON) .tint(theme.accent_color) .sense(Sense::click()) @@ -57,12 +81,43 @@ impl CompUi for Player { .tint(theme.accent_color) .sense(Sense::click()) .max_size(Vec2::new(16.0, 16.0)); - if ui.add(prev).clicked() {} - if ui.add(pp).clicked() { - let mut slf = handle_error_ui!(Player::get()); - slf.is_playing = !slf.is_playing; + if ui.add(prev).clicked() { + handle_error_ui!(handle_error_ui!(SongList::get()).play_prev(state)); } - if ui.add(next).clicked() {} + if ui.add(pp).clicked() { + if state.player.is_paused() { + state.player.play(); + } else { + state.player.pause(); + } + } + if ui.add(next).clicked() || state.player.just_stopped() { + handle_error_ui!(handle_error_ui!(SongList::get()).play_next(state)); + } + + + + ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| { + ui.add_space(15.0); + ui.style_mut().spacing.slider_width = avail.x * 0.15; + let s = Stroke { + color: theme.accent_color, + width: 1.0 + }; + ui.style_mut().visuals.widgets.inactive.fg_stroke = s; + ui.style_mut().visuals.widgets.active.fg_stroke = s; + ui.style_mut().visuals.widgets.hovered.fg_stroke = s; + + let mut slf = handle_error_ui!(Player::get()); + let slider =ui.add( + egui::Slider::new(&mut slf.volume_slider, 0.0..=1.0) + .show_value(false) + ); + + if slider.changed() { + state.player.set_volume(slf.volume_slider); + } + }); }); ui.add_space(3.0); }); diff --git a/xmpd-gui/src/components/song_list/mod.rs b/xmpd-gui/src/components/song_list/mod.rs index d4842d8..0c4e158 100644 --- a/xmpd-gui/src/components/song_list/mod.rs +++ b/xmpd-gui/src/components/song_list/mod.rs @@ -1,6 +1,4 @@ -use std::fmt::write; - -use egui::{Color32, RichText, Sense, Vec2}; +use egui::{Color32, CursorIcon, RichText, Sense, Vec2}; use song_list_nav::SearchType; use xmpd_cache::DlStatus; use xmpd_manifest::{song::Song, store::BaseStore}; @@ -10,171 +8,264 @@ pub mod song_list_nav; #[derive(Debug, Default)] pub struct SongList { - selected_song_id: uuid::Uuid + selected_sid: uuid::Uuid, + playable_songs: Vec, } component_register!(SongList); impl CompUi for SongList { fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> { + let songs = Self::get_and_sort_songs(state)?; + let disp_songs = Self::get_songs_to_display(&songs)?; + { + let mut sl = SongList::get()?; + sl.playable_songs = Self::get_playable_songs(&songs)?; + if let Some((sid, _)) = songs.first() { + if sl.selected_sid == Default::default() { + sl.selected_sid = sid.clone(); + } + } + } egui::ScrollArea::vertical() .id_source("song_list") .drag_to_scroll(false) .show(ui, |ui| { ui.vertical(|ui| { ui.add_space(3.0); - let pid = {handle_error_ui!(super::left_nav::LeftNav::get()).selected_playlist_id.clone()}; - match pid { - None => { - let mut songs: Vec<_> = state.manifest.store().get_songs().iter().collect(); - songs.sort_by(|a, b| { - let a = a.1.name().to_lowercase(); - let b = b.1.name().to_lowercase(); - a.cmp(&b) - }); - - for (sid, song) in songs { - let query = {handle_error_ui!(song_list_nav::SongListNav::get()).parse_search()}.clone(); - let should_display = match query { - SearchType::Source(s) if !s.is_empty() => format!("{:?}", &song.source_type()).to_lowercase().contains(&s), - SearchType::Author(s) if !s.is_empty() => song.author().to_lowercase().contains(&s), - SearchType::Name(s) if !s.is_empty() => song.name().to_owned().contains(&s), - _ => true - }; - if should_display { - display_song_tab(ui, sid, song); - } - } - } - Some(pid) => { - if let Some(playlist) = state.manifest.store().get_playlist(&pid) { - let mut songs = Vec::new(); - for sid in playlist.songs() { - if let Some(song) = state.manifest.store().get_song(&sid) { - songs.push((sid, song)); - } - } - songs.sort_by(|a, b| { - let a = a.1.name().to_lowercase(); - let b = b.1.name().to_lowercase(); - a.cmp(&b) - }); - let query = {handle_error_ui!(song_list_nav::SongListNav::get()).parse_search()}.clone(); - for (sid, song) in songs { - let should_display = match query { - SearchType::Source(ref s) if !s.is_empty() => format!("{:?}", &song.source_type()).to_lowercase().contains(s), - SearchType::Author(ref s) if !s.is_empty() => song.author().to_lowercase().contains(s), - SearchType::Name(ref s) if !s.is_empty() => song.name().to_owned().contains(s), - _ => true - }; - if should_display { - display_song_tab(ui, sid, song); - } - } - } - } + for (sid, song) in disp_songs { + handle_error_ui!(Self::display_song_tab(ui, state, &sid, &song)); } - }); }); Ok(()) } } -fn display_song_tab(ui: &mut egui::Ui, sid: &uuid::Uuid, song: &Song) { - let theme = handle_error_ui!(xmpd_settings::Settings::get()).theme.clone(); - ui.horizontal(|ui| { - let mut clicked = ui.add( - egui::Image::new(crate::data::NOTE_ICON) - .tint(theme.accent_color) - .sense(Sense::click()) - .fit_to_exact_size(Vec2::new(32.0, 32.0)) - ).clicked(); +impl SongList { + fn get_and_sort_songs(state: &mut crate::GuiState) -> crate::Result> { + let pid = super::left_nav::LeftNav::get()?.selected_playlist_id.clone(); + match pid { + None => { + let songs = state.manifest.store().get_songs().clone().into_iter(); + let mut songs: Vec<_> = songs.collect(); + songs.sort_by(|a, b| { + let a = a.1.name().to_lowercase(); + let b = b.1.name().to_lowercase(); + a.cmp(&b) + }); + Ok(songs) + } + Some(pid) => { + let Some(playlist) = state.manifest.store().get_playlist(&pid) else { + anyhow::bail!("Couldnt find playlist (corruption?)"); + }; + let mut songs = Vec::new(); + for sid in playlist.songs() { + if let Some(song) = state.manifest.store().get_song(&sid) { + songs.push((sid.clone(), song.clone())); + } + } + songs.sort_by(|a, b| { + let a = a.1.name().to_lowercase(); + let b = b.1.name().to_lowercase(); + a.cmp(&b) + }); + Ok(songs) + } + } + } - ui.vertical(|ui| { - let selected_song_id = {handle_error_ui!(SongList::get()).selected_song_id}; - let label = if selected_song_id == *sid { - ui.label( - RichText::new(song.name()) - .color(theme.accent_color) - ) - } else { - ui.label( - RichText::new(song.name()) - .color(theme.text_color) - ) + fn get_songs_to_display(songs: &Vec<(uuid::Uuid, Song)>) -> crate::Result>{ + let mut to_display = Vec::new(); + let query = {song_list_nav::SongListNav::get()?.parse_search()}.clone(); + for (sid, song) in songs { + let should_display = match &query { + SearchType::Name(s) | + SearchType::Author(s) | + SearchType::Source(s) if s.is_empty() => true, + + SearchType::Source(s) => { + song.source_type().to_string() + .to_lowercase() + .contains(s) + }, + SearchType::Author(s) => { + song.author() + .to_lowercase() + .contains(s) + }, + SearchType::Name(s) => { + song.name() + .to_lowercase() + .contains(s) + }, }; - if label.clicked() { - clicked = true; + if should_display { + to_display.push((sid.clone(), song.clone())); } - ui.monospace( - RichText::new(format!("By {}", song.author())) - .color(theme.dim_text_color) - .size(10.0) - ); + } + Ok(to_display) + } - }); - - ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| { - ui.add_space(3.0); + fn display_song_tab(ui: &mut egui::Ui, state: &mut crate::GuiState, sid: &uuid::Uuid, song: &Song) -> crate::Result<()> { + let mut clicked = false; + ui.horizontal(|ui| { + let theme = handle_error_ui!(xmpd_settings::Settings::get()).theme.clone(); + let img = ui.add( + egui::Image::new(crate::data::NOTE_ICON) + .tint(theme.accent_color) + .sense(Sense::click()) + .fit_to_exact_size(Vec2::new(32.0, 32.0)) + ); let status = { handle_error_ui!(xmpd_cache::Cache::get()).get_cached_song_status(&sid).clone() }; - match status { - Some(DlStatus::Done(p)) => { - let img = ui.add( - egui::Image::new(crate::data::CHECK_ICON) - .tint(Color32::LIGHT_GREEN) - .sense(Sense::hover()) - .fit_to_exact_size(Vec2::new(16.0, 16.0)) - ); - - img.on_hover_ui(|ui| { - ui.label(format!("Path: {p}")); - }); - } - Some(DlStatus::Downloading) => { - ui.add( - egui::Spinner::new() - .color(theme.accent_color) - .size(16.0) - ); - } - Some(DlStatus::Error(e)) => { - let img = ui.add( - egui::Image::new(crate::data::WARN_ICON) - .tint(Color32::LIGHT_YELLOW) - .sense(Sense::hover()) - .fit_to_exact_size(Vec2::new(16.0, 16.0)) - ); - img.on_hover_ui(|ui| { - ui.label(e); - }); - } - None => { - let img = ui.add( - egui::Image::new(crate::data::DL_ICON) - .tint(theme.accent_color) - .sense(Sense::click()) - .fit_to_exact_size(Vec2::new(16.0, 16.0)) - ); - if img.clicked() { - handle_error_ui!(xmpd_cache::Cache::get()).download_to_cache(sid.clone(), song.clone()); - let mut toast = handle_error_ui!(crate::components::toast::Toast::get()); - toast.show_toast( - "Downloading Song", - &format!("Started downloading {} by {}", song.name(), song.author()), - super::toast::ToastType::Info - ); - } + if img.clicked() { + clicked = true; + } + if img.hovered() { + if matches!(status, Some(DlStatus::Done(_))) { + ui.output_mut(|o| o.cursor_icon = CursorIcon::PointingHand); + } else { + ui.output_mut(|o| o.cursor_icon = CursorIcon::Default); } } + + ui.vertical(|ui| { + let slf = handle_error_ui!(SongList::get()); + let label = if slf.selected_sid == *sid { + RichText::new(song.name()) + .color(theme.accent_color) + } else if matches!(status, Some(DlStatus::Done(_))) { + RichText::new(song.name()) + .color(theme.text_color) + } else { + RichText::new(song.name()) + .color(theme.dim_text_color) + }; + let label = ui.label(label); + + if label.clicked() { + clicked = true; + } + if label.hovered() { + if matches!(status, Some(DlStatus::Done(_))) { + ui.output_mut(|o| o.cursor_icon = CursorIcon::PointingHand); + } else { + ui.output_mut(|o| o.cursor_icon = CursorIcon::Default); + } + } + ui.monospace( + RichText::new(format!("By {}", song.author())) + .color(theme.dim_text_color) + .size(10.0) + ); + + }); + + ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| { + ui.add_space(3.0); + + match status { + Some(DlStatus::Done(_p)) => { + //let img = egui::Image::new(crate::data::CHECK_ICON) + // .tint(Color32::LIGHT_GREEN) + // .sense(Sense::hover()) + // .fit_to_exact_size(Vec2::new(16.0, 16.0)); + + //ui.add(img).on_hover_ui(|ui| { + // ui.label(format!("Path: {p}")); + //}); + } + Some(DlStatus::Downloading) => { + let spinner = egui::Spinner::new() + .color(theme.accent_color) + .size(16.0); + ui.add(spinner); + } + Some(DlStatus::Error(e)) => { + let img = egui::Image::new(crate::data::WARN_ICON) + .tint(Color32::LIGHT_YELLOW) + .sense(Sense::hover()) + .fit_to_exact_size(Vec2::new(16.0, 16.0)); + + ui.add(img).on_hover_ui(|ui| { + ui.label(e); + }); + } + None => { + let img = egui::Image::new(crate::data::DL_ICON) + .tint(theme.accent_color) + .sense(Sense::click()) + .fit_to_exact_size(Vec2::new(16.0, 16.0)); + + if ui.add(img).clicked() { + handle_error_ui!(xmpd_cache::Cache::get()).download_to_cache(sid.clone(), song.clone()); + let mut toast = handle_error_ui!(crate::components::toast::Toast::get()); + toast.show_toast( + "Downloading Song", + &format!("Started downloading {} by {}", song.name(), song.author()), + super::toast::ToastType::Info + ); + } + } + } + }); }); + ui.separator(); if clicked { - handle_error_ui!(SongList::get()).selected_song_id = sid.clone(); + let mut sl = SongList::get()?; + sl.play_song(sid.clone(), state)?; } - }); - - ui.separator(); + + Ok(()) + } + pub fn play_song(&mut self, sid: uuid::Uuid, state: &mut crate::GuiState) -> crate::Result<()> { + if self.playable_songs.contains(&sid) { + self.selected_sid = sid.clone(); + let path = state.manifest.get_song_as_path(sid)?; + state.player.play_song(&path)?; + } + Ok(()) + } + pub fn play_prev(&mut self, state: &mut crate::GuiState) -> crate::Result<()> { + let Some(mut prev) = self.playable_songs.last().cloned() else { + anyhow::bail!("Trying to play a song in an empty playlist (impossible)") + }; + for sid in self.playable_songs.clone() { + if sid == self.selected_sid { + self.play_song(prev, state)?; + } + prev = sid; + } + Ok(()) + } + pub fn play_next(&mut self, state: &mut crate::GuiState) -> crate::Result<()> { + let Some(mut next) = self.playable_songs.first().cloned() else { + anyhow::bail!("Trying to play a song in an empty playlist (impossible)") + }; + let mut found = false; + for sid in self.playable_songs.clone() { + if sid == self.selected_sid { + found = true; + } else if found { + next = sid; + break; + } + } + self.play_song(next, state)?; + Ok(()) + } + fn get_playable_songs(songs: &Vec<(uuid::Uuid, Song)>) -> crate::Result> { + let mut playable_songs = Vec::new(); + + for (sid, _) in songs { + if let Some(DlStatus::Done(_)) = xmpd_cache::Cache::get()?.get_cached_song_status(&sid) { + playable_songs.push(sid.clone()); + } + } + Ok(playable_songs) + } } diff --git a/xmpd-gui/src/components/song_list/song_list_nav.rs b/xmpd-gui/src/components/song_list/song_list_nav.rs index 0224ed7..7dc3c80 100644 --- a/xmpd-gui/src/components/song_list/song_list_nav.rs +++ b/xmpd-gui/src/components/song_list/song_list_nav.rs @@ -1,8 +1,11 @@ use uuid::Uuid; -use xmpd_manifest::store::BaseStore; +use xmpd_cache::DlStatus; +use xmpd_manifest::{song::Song, store::BaseStore}; use crate::components::{left_nav::LeftNav, toast::ToastType, CompGetter, CompUi}; +use super::SongList; + #[derive(Debug, Clone)] pub enum SearchType { Name(String), @@ -53,8 +56,9 @@ impl CompUi for SongListNav { None => { songs = state.manifest.store().get_songs().keys().cloned().collect(); } + } - for sid in &songs { + for sid in handle_error_ui!(Self::get_songs_to_download(&songs)) { if let Some(song) = state.manifest.store().get_song(&sid) { handle_error_ui!(xmpd_cache::Cache::get()).download_to_cache(sid.clone(), song.clone()) } @@ -86,6 +90,16 @@ impl SongListNav { i @ _ => SearchType::Name(i.to_string().to_lowercase()) } } + fn get_songs_to_download(songs: &Vec) -> crate::Result> { + let mut songs2 = Vec::new(); + + for sid in songs { + if let None = xmpd_cache::Cache::get()?.get_cached_song_status(&sid) { + songs2.push(sid.clone()); + } + } + Ok(songs2) + } } diff --git a/xmpd-gui/src/components/toast.rs b/xmpd-gui/src/components/toast.rs index d9ac3f9..c9a7591 100644 --- a/xmpd-gui/src/components/toast.rs +++ b/xmpd-gui/src/components/toast.rs @@ -1,7 +1,7 @@ use std::{collections::VecDeque, time::SystemTime}; -use egui::{epaint::Shadow, load::TexturePoll, Align2, Color32, Frame, Image, Margin, Pos2, Rect, RichText, Rounding, Stroke, Style, Vec2}; +use egui::{epaint::Shadow, load::TexturePoll, Align2, Color32, Frame, Image, ImageSource, Margin, Pos2, Rect, RichText, Rounding, Stroke, Style, TextureFilter, TextureOptions, TextureWrapMode, Vec2}; use super::{CompGetter, CompUi}; @@ -43,19 +43,24 @@ impl CompUi for Toast { ToastType::Info => { color = theme.accent_color; img = Image::new(crate::data::INFO_ICON) - .max_size(Vec2::new(16.0, 16.0)) + .fit_to_exact_size(Vec2::new(16.0, 16.0)) .tint(color); } ToastType::Warn => { color = crate::data::C_WARN; img = Image::new(crate::data::WARN_ICON) - .max_size(Vec2::new(16.0, 16.0)) + .fit_to_exact_size(Vec2::new(16.0, 16.0)) + .texture_options(TextureOptions { + magnification: TextureFilter::Linear, + minification: TextureFilter::Linear, + wrap_mode: TextureWrapMode::ClampToEdge, + }) .tint(color); } ToastType::Error => { color = Color32::LIGHT_RED; img = Image::new(crate::data::ERROR_ICON) - .max_size(Vec2::new(16.0, 16.0)) + .fit_to_exact_size(Vec2::new(16.0, 16.0)) .tint(color); } } diff --git a/xmpd-gui/src/components/top_nav.rs b/xmpd-gui/src/components/top_nav.rs index 5684558..c2d7988 100644 --- a/xmpd-gui/src/components/top_nav.rs +++ b/xmpd-gui/src/components/top_nav.rs @@ -1,9 +1,19 @@ +use std::path::PathBuf; + +use egui::TextBuffer; +use xmpd_manifest::store::{JsonStore, TomlStore}; + use crate::windows::WindowId; -use super::CompUi; +use super::{CompGetter, CompUi}; #[derive(Debug, Default)] -pub struct TopNav; +pub struct TopNav { + // for dialog + manifest_path: Option<(PathBuf, String)> +} + +component_register!(TopNav); impl CompUi for TopNav { fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> { @@ -22,6 +32,25 @@ impl CompUi for TopNav { handle_error_ui!(state.manifest.save()); ui.close_menu(); } + if ui.button("Save As").clicked() { + std::thread::spawn(|| -> crate::Result<()> { + let mut dialog = rfd::FileDialog::new() + .add_filter("Json", &["json"]) + .add_filter("Toml", &["toml"]) + .set_title("Save Manifest As") + .set_can_create_directories(true) + .set_file_name("manifest"); + if let Some(home_dir) = dirs::home_dir() { + dialog = dialog.set_directory(home_dir); + } + if let Some(path) = dialog.save_file() { + if let Some(ext) = path.extension() { + TopNav::get()?.manifest_path = Some((path.clone(), ext.to_string_lossy().to_string())) + } + } + Ok(()) + }); + } }); ui.menu_button("Help", |ui| { if ui.button("Source").clicked() { @@ -39,7 +68,20 @@ impl CompUi for TopNav { }); }); - - Ok(()) + let mut used = false; + if let Some((path, ext)) = &TopNav::get()?.manifest_path { + match ext.as_str() { + "json" => state.manifest.convert_and_save_to::(&path)?, + "toml" => state.manifest.convert_and_save_to::(&path)?, + _ => () + } + used = true; + } + if used { + TopNav::get()?.manifest_path = None; + } + Ok(()) } } + + diff --git a/xmpd-gui/src/lib.rs b/xmpd-gui/src/lib.rs index c7c2d10..8604124 100644 --- a/xmpd-gui/src/lib.rs +++ b/xmpd-gui/src/lib.rs @@ -36,11 +36,13 @@ pub fn start() -> Result<()> { pub struct GuiState { pub manifest: Manifest, pub windows: windows::Windows, + pub player: xmpd_player::Player, } impl GuiState { pub fn new() -> Result { Ok(Self { + player: xmpd_player::Player::new(), manifest: Manifest::new(&xmpd_cliargs::CLIARGS.manifest_path())?, windows: windows::Windows::new(), }) diff --git a/xmpd-gui/src/macros.rs b/xmpd-gui/src/macros.rs index 3497e4c..79d9668 100644 --- a/xmpd-gui/src/macros.rs +++ b/xmpd-gui/src/macros.rs @@ -35,3 +35,14 @@ macro_rules! handle_error_ui { } }; } + +macro_rules! handle_option { + ($reason:expr, $val:expr) => { + if let Some(v) = $val { + v + } else { + handle_error_ui!(Err(anyhow::anyhow!($reason))); + return; + } + }; +} diff --git a/xmpd-manifest/Cargo.toml b/xmpd-manifest/Cargo.toml index b8df441..48a1fd6 100644 --- a/xmpd-manifest/Cargo.toml +++ b/xmpd-manifest/Cargo.toml @@ -18,8 +18,11 @@ crate-type = ["rlib"] bench = false [dependencies] +xmpd-cliargs.path = "../xmpd-cliargs" +xmpd-settings.path = "../xmpd-settings" anyhow.workspace = true uuid.workspace = true serde.workspace = true serde_json.workspace = true url.workspace = true +toml.workspace = true diff --git a/xmpd-manifest/src/lib.rs b/xmpd-manifest/src/lib.rs index 864230d..353c0d0 100644 --- a/xmpd-manifest/src/lib.rs +++ b/xmpd-manifest/src/lib.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; #[cfg(test)] @@ -43,6 +43,29 @@ impl Manifest { self.store_mut().load_from(&p)?; Ok(()) } + pub fn convert_to(&self) -> ST2 { + let songs = self.store().get_songs().clone(); + let playlists = self.store().get_playlists().clone(); + let mut st2 = ST2::empty(); + *st2.get_songs_mut() = songs; + *st2.get_playlists_mut() = playlists; + st2 + } + + pub fn convert_and_save_to(&self, path: &Path) -> Result<()> { + let st2 = self.convert_to::(); + std::fs::write(path, st2.to_bytes()?)?; + Ok(()) + } + + pub fn get_song_as_path(&self, sid: uuid::Uuid) -> Result { + let ext = &xmpd_settings::Settings::get()?.tooling.song_format; + let mut p = xmpd_cliargs::CLIARGS.cache_path().into_std_path_buf(); + p.push("songs"); + p.push(sid.to_string()); + p.set_extension(ext); + Ok(p) + } } diff --git a/xmpd-manifest/src/song.rs b/xmpd-manifest/src/song.rs index b5986cc..9bbf5d3 100644 --- a/xmpd-manifest/src/song.rs +++ b/xmpd-manifest/src/song.rs @@ -1,4 +1,4 @@ -use std::{path::PathBuf, str::FromStr}; +use std::{fmt::Display, path::PathBuf, str::FromStr}; @@ -72,3 +72,14 @@ impl SourceType { } } +impl Display for SourceType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Youtube => write!(f, "YouTube"), + Self::Soundcloud => write!(f, "SoundCloud"), + Self::Spotify => write!(f, "Spotify"), + s => write!(f, "{s:?}"), + } + } +} + diff --git a/xmpd-manifest/src/store/mod.rs b/xmpd-manifest/src/store/mod.rs index acb4392..a7fbe8c 100644 --- a/xmpd-manifest/src/store/mod.rs +++ b/xmpd-manifest/src/store/mod.rs @@ -5,7 +5,9 @@ use uuid::Uuid; use crate::{playlist::Playlist, song::Song}; mod json; +mod toml; pub use json::JsonStore; +pub use toml::TomlStore; pub trait BaseStore { fn get_songs(&self) -> &HashMap; diff --git a/xmpd-manifest/src/store/toml.rs b/xmpd-manifest/src/store/toml.rs new file mode 100644 index 0000000..be4ec0b --- /dev/null +++ b/xmpd-manifest/src/store/toml.rs @@ -0,0 +1,71 @@ +use std::{collections::HashMap, path::PathBuf}; +use uuid::Uuid; +use crate::{playlist::Playlist, song::Song}; + +const DEFAULT_TEXT: &str = r#"{ + "songs": {}, + "playlists": {} +}"#; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)] +pub struct TomlStore { + #[serde(skip)] + original_path: PathBuf, + songs: HashMap, + playlists: HashMap +} + +impl super::BaseStore for TomlStore { + fn get_default_file_contents() -> &'static str { + &DEFAULT_TEXT + } + fn get_file_extension() -> &'static str { + "toml" + } + fn empty() -> Self where Self: Sized { + Self { + original_path: PathBuf::new(), + songs: HashMap::default(), + playlists: HashMap::default(), + } + } + fn to_bytes(&self) -> crate::Result> { + let s: Vec = toml::to_string_pretty(self)?.chars().map(|c| c as u8).collect(); + Ok(s) + } + fn from_bytes(s: &[u8]) -> crate::Result where Self: Sized { + let s: Self = toml::from_str(&String::from_utf8(s.to_vec())?)?; + Ok(s) + } + fn get_songs(&self) -> &HashMap { + &self.songs + } + fn get_songs_mut(&mut self) -> &mut HashMap { + &mut self.songs + } + fn get_song(&self, id: &Uuid) -> Option<&Song> { + self.songs.get(id) + } + fn get_song_mut(&mut self, id: &Uuid) -> Option<&mut Song> { + self.songs.get_mut(id) + } + fn get_playlists(&self) -> &HashMap { + &self.playlists + } + fn get_playlists_mut(&mut self) -> &mut HashMap { + &mut self.playlists + } + fn get_playlist(&self, id: &Uuid) -> Option<&Playlist> { + self.playlists.get(id) + } + fn get_playlist_mut(&mut self, id: &Uuid) -> Option<&mut Playlist> { + self.playlists.get_mut(id) + } + fn save_original_path(&mut self, p: &std::path::Path) { + self.original_path = p.to_path_buf(); + } + fn get_original_path(&self) -> &std::path::Path { + &self.original_path + } +} + diff --git a/xmpd-player/Cargo.toml b/xmpd-player/Cargo.toml index f3dc537..e4164a8 100644 --- a/xmpd-player/Cargo.toml +++ b/xmpd-player/Cargo.toml @@ -7,4 +7,7 @@ license.workspace = true authors.workspace = true [dependencies] -rodio = { version = "0.20.1", features = ["symphonia-all"] } +rodio.workspace = true +lazy_static.workspace = true +anyhow.workspace = true +log.workspace = true diff --git a/xmpd-player/src/lib.rs b/xmpd-player/src/lib.rs index e69de29..4ed8f25 100644 --- a/xmpd-player/src/lib.rs +++ b/xmpd-player/src/lib.rs @@ -0,0 +1,101 @@ +use std::{path::Path, time::Duration}; + +use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink, Source}; + +type Result = anyhow::Result; + +pub struct Player { + _stream: OutputStream, + _stream_handle: OutputStreamHandle, + sink: Sink, + source_len: Duration, + tested_for_song_end: bool, +} + +impl Player { + pub fn new() -> Self { + let (_stream, _stream_handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&_stream_handle).unwrap(); + sink.pause(); + Self { + _stream, + _stream_handle, + sink, + source_len: Default::default(), + tested_for_song_end: true, + } + } + + + pub fn play_song(&mut self, path: &Path) -> Result<()> { + let file = std::io::BufReader::new(std::fs::File::open(path)?); + let source = Decoder::new(file)?; + self.tested_for_song_end = false; + self.source_len = source.total_duration().unwrap(); + self.sink.clear(); + self.sink.append(source); + self.sink.play(); + Ok(()) + } + + pub fn get_played_f(&self) -> f64 { + let source_len = self.source_len.as_millis(); + let curr_len = self.sink.get_pos().as_millis(); + if source_len == 0 || curr_len == 0 { + return 0.0; + } + curr_len as f64 / source_len as f64 + } + + pub fn get_played_len(&self) -> Duration { + self.sink.get_pos() + } + + pub fn get_ms_left(&self) -> u64 { + let source_len = self.source_len.as_millis(); + let curr_len = self.sink.get_pos().as_millis(); + if source_len < curr_len { + return 0; + } + (source_len - curr_len) as u64 + } + + pub fn just_stopped(&mut self) -> bool { + if self.sink.len() == 0 && !self.tested_for_song_end { + self.tested_for_song_end = true; + true + } else { + false + } + } + + pub fn play(&self) { + self.sink.play() + } + + pub fn pause(&self) { + self.sink.pause() + } + + pub fn seek_to_f(&self, f: f64) -> Result<()> { + let dur = self.source_len.as_millis() as f64 * f.clamp(0.0, 1.0); + self.seek(Duration::from_millis(dur as u64))?; + Ok(()) + } + + pub fn seek(&self, d: Duration) -> Result<()> { + if let Err(e) = self.sink.try_seek(d) { + anyhow::bail!("{e:?}"); + } + Ok(()) + } + + pub fn is_paused(&self) -> bool { + self.sink.is_paused() + } + + pub fn set_volume(&self, vol: f64) { + // clamped for the safety of my, and your ears + self.sink.set_volume(vol.clamp(0.0, 1.0) as f32); + } +} diff --git a/xmpd-settings/Cargo.toml b/xmpd-settings/Cargo.toml index ff2c216..2f701f7 100644 --- a/xmpd-settings/Cargo.toml +++ b/xmpd-settings/Cargo.toml @@ -12,4 +12,4 @@ camino.workspace = true egui.workspace = true lazy_static.workspace = true serde.workspace = true -toml = "0.8.19" +toml.workspace = true