diff --git a/Cargo.lock b/Cargo.lock index 94d403d0b..5631a9d46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aes" version = "0.6.0" @@ -65,18 +80,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alsa" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" -dependencies = [ - "alsa-sys", - "bitflags", - "libc", - "nix 0.20.0", -] - [[package]] name = "alsa" version = "0.6.0" @@ -101,9 +104,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.53" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ "proc-macro2", "quote", @@ -127,6 +130,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base-x" version = "0.2.10" @@ -190,15 +208,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "bytecount" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" +checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" [[package]] name = "byteorder" @@ -274,9 +292,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21" +checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" dependencies = [ "glob", "libc", @@ -285,9 +303,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.13" +version = "3.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b3ee449efa0c4f95cd48b00539829d3655a98e189a90617246492788d22404" +checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" dependencies = [ "atty", "bitflags", @@ -420,7 +438,7 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116" dependencies = [ - "alsa 0.6.0", + "alsa", "core-foundation-sys", "coreaudio-rs", "jni", @@ -432,7 +450,7 @@ dependencies = [ "ndk-glue", "nix 0.23.1", "oboe", - "parking_lot", + "parking_lot 0.11.2", "stdweb 0.1.3", "thiserror", "web-sys", @@ -691,18 +709,18 @@ dependencies = [ [[package]] name = "enum-map" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0348b2a57c82f98b9dbd8098b1abb2416f221823d3e50cbe24eaebdd16896826" +checksum = "1284d66c2ebd284a159491ebc005c6608ef684f4f5db99c960b1837cb74b7067" dependencies = [ "enum-map-derive", ] [[package]] name = "enum-map-derive" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a63b7a0ddec6f38dcec5e36257750b7a8fcaf4227e12ceb306e341d63634da05" +checksum = "00d1c54e25a57236a790ecf051c2befbb57740c9b86c4273eac378ba84d620d6" dependencies = [ "proc-macro2", "quote", @@ -895,6 +913,12 @@ dependencies = [ "wasi 0.10.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "glob" version = "0.3.0" @@ -916,7 +940,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.1", + "tokio-util", "tracing", ] @@ -993,9 +1017,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", @@ -1004,9 +1028,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -1027,9 +1051,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.18" +version = "0.14.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" dependencies = [ "bytes", "futures-channel", @@ -1096,9 +1120,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", "hashbrown", @@ -1130,9 +1154,9 @@ checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "jni" @@ -1197,9 +1221,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libdbus-sys" @@ -1276,9 +1300,9 @@ dependencies = [ [[package]] name = "librespot-audio" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f7cc7e4d1c2596191be523668c933e07ec8a318d099fd66658258a4fe4a2dc" +checksum = "735f611dc3326848621fc7ed805b83854b9a1d8cfedfb4b57ed3fe61b54df379" dependencies = [ "aes-ctr", "byteorder", @@ -1292,9 +1316,9 @@ dependencies = [ [[package]] name = "librespot-core" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255e8d8d719c020895079d140baf0b0edec8447d39a7e4760708f33b7cafaafb" +checksum = "998986b329ebeb586b93c9d27e3d90c42756cdd7c7cc75812fd2f0ddb999b8c8" dependencies = [ "aes", "base64", @@ -1325,7 +1349,7 @@ dependencies = [ "thiserror", "tokio", "tokio-stream", - "tokio-util 0.6.9", + "tokio-util", "url", "uuid", "vergen", @@ -1333,9 +1357,9 @@ dependencies = [ [[package]] name = "librespot-metadata" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624ac29bb3ad2e565ef78a049a6c554d94e48b673aaba0bf7e7efd946d0b66cd" +checksum = "174737c59421237e33527589f793ba2b1a548c1eca59ab58af9e4f2a56de18f5" dependencies = [ "async-trait", "byteorder", @@ -1347,11 +1371,11 @@ dependencies = [ [[package]] name = "librespot-playback" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "188b252b690ae7387f84a481ff4211df1a5c21eb9bddfc25cbde48793f2e0ef2" +checksum = "4175b33a26625aa9bd7059cc1688e1e4f87b30ee6a6f7c63dc5118a3c14ec3b8" dependencies = [ - "alsa 0.5.0", + "alsa", "byteorder", "cpal", "futures-executor", @@ -1364,6 +1388,7 @@ dependencies = [ "librespot-metadata", "log", "ogg", + "parking_lot 0.12.1", "portaudio-rs", "rand", "rand_distr", @@ -1376,9 +1401,9 @@ dependencies = [ [[package]] name = "librespot-protocol" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b3699b05cb4c50caa5a5b7f5b3aadb928dfcc91cf1aa632c0dabce3ccc3ee4" +checksum = "2e21de16aa66ab2a7b3c40a5a847a659b1b3cb66a67da6a63731d28d4788535d" dependencies = [ "glob", "protobuf", @@ -1397,9 +1422,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] @@ -1486,26 +1511,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "mio" -version = "0.8.2" +name = "miniz_oxide" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "wasi 0.11.0+wasi-snapshot-preview1", - "winapi", + "adler", ] [[package]] -name = "miow" -version = "0.3.7" +name = "mio" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" dependencies = [ - "winapi", + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] @@ -1528,7 +1551,7 @@ dependencies = [ [[package]] name = "ncspot" -version = "0.9.8" +version = "0.10.0" dependencies = [ "chrono", "clap", @@ -1634,18 +1657,6 @@ dependencies = [ "jni-sys", ] -[[package]] -name = "nix" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", -] - [[package]] name = "nix" version = "0.22.3" @@ -1693,15 +1704,6 @@ dependencies = [ "winrt-notification", ] -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - [[package]] name = "num" version = "0.2.1" @@ -1828,9 +1830,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", "libm", @@ -1869,9 +1871,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" dependencies = [ "libc", ] @@ -1911,6 +1913,15 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + [[package]] name = "oboe" version = "0.4.6" @@ -1945,9 +1956,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" @@ -1957,18 +1968,30 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.38" +version = "0.10.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -1977,9 +2000,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.72" +version = "0.9.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" dependencies = [ "autocfg", "cc", @@ -2000,9 +2023,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" [[package]] name = "owning_ref" @@ -2034,7 +2057,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", ] [[package]] @@ -2051,6 +2084,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "backtrace", + "cfg-if", + "libc", + "petgraph", + "redox_syscall", + "smallvec", + "thread-id", + "windows-sys", +] + [[package]] name = "parse_duration" version = "2.1.1" @@ -2096,9 +2145,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "petgraph" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" dependencies = [ "fixedbitset", "indexmap", @@ -2160,9 +2209,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "priority-queue" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ba480ac08d3cfc40dea10fd466fd2c14dee3ea6fc7873bc4079eda2727caf0" +checksum = "de9cde7493f5f5d2d163b174be9f9a72d756b79b0f6ed85654128d238c347c1e" dependencies = [ "autocfg", "indexmap", @@ -2186,11 +2235,11 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2316,9 +2365,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -2327,9 +2376,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "remove_dir_all" @@ -2393,9 +2442,9 @@ dependencies = [ [[package]] name = "rodio" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d98f5e557b61525057e2bc142c8cd7f0e70d75dc32852309bec440e6e046bf9" +checksum = "ec0939e9f626e6c6f1989adb6226a039c855ca483053f0ee7c98b90e41cf731e" dependencies = [ "cpal", ] @@ -2453,6 +2502,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2480,14 +2535,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.7", + "semver 1.0.10", ] [[package]] name = "rustls" -version = "0.20.4" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" dependencies = [ "log", "ring", @@ -2503,9 +2558,9 @@ checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "same-file" @@ -2518,12 +2573,12 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "winapi", + "windows-sys", ] [[package]] @@ -2576,9 +2631,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" [[package]] name = "semver-parser" @@ -2588,9 +2643,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] @@ -2607,9 +2662,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -2618,9 +2673,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", @@ -2712,9 +2767,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" dependencies = [ "libc", "signal-hook-registry", @@ -2884,13 +2939,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.92" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2958,24 +3013,35 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "thread-id" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "time" version = "0.1.44" @@ -3053,9 +3119,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.18.0" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" dependencies = [ "bytes", "libc", @@ -3063,6 +3129,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", + "parking_lot 0.12.1", "pin-project-lite", "socket2", "tokio-macros", @@ -3071,9 +3138,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -3092,34 +3159,20 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.6.9" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" dependencies = [ - "bytes", "futures-core", - "futures-sink", - "log", "pin-project-lite", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" dependencies = [ "bytes", "futures-core", @@ -3146,34 +3199,22 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if", "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] @@ -3208,6 +3249,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -3231,9 +3278,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "untrusted" @@ -3275,9 +3322,9 @@ dependencies = [ [[package]] name = "uuid" -version = "0.8.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "c6d5d669b51467dcf7b2f1a796ce0f955f05f01cafda6c19d6e95f730df29238" dependencies = [ "getrandom", ] @@ -3529,36 +3576,79 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9f39345ae0c8ab072c0ac7fe8a8b411636aa34f89be19ddd0d9226544f13944" dependencies = [ - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_i686_gnu 0.24.0", + "windows_i686_msvc 0.24.0", + "windows_x86_64_gnu 0.24.0", + "windows_x86_64_msvc 0.24.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_i686_gnu" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0866510a3eca9aed73a077490bbbf03e5eaac4e1fd70849d89539e5830501fd" +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + [[package]] name = "windows_i686_msvc" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6" +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_x86_64_gnu" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384a173630588044205a2993b6864a2f56e5a8c1e7668c07b93ec18cf4888dc4" +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + [[package]] name = "windows_x86_64_msvc" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "winreg" version = "0.5.1" @@ -3639,9 +3729,9 @@ checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" [[package]] name = "zerocopy" -version = "0.3.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" +checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" dependencies = [ "byteorder", "zerocopy-derive", @@ -3649,9 +3739,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" +checksum = "a0fbc82b82efe24da867ee52e015e58178684bd9dd64c34e66bdf21da2582a9f" dependencies = [ "proc-macro2", "syn", diff --git a/Cargo.toml b/Cargo.toml index 264e3d187..fb46e7b91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "ncspot" description = "ncurses Spotify client written in Rust using librespot, inspired by ncmpc and the likes." exclude = ["images/**"] -version = "0.9.8" +version = "0.10.0" authors = ["Henrik Friedrichsen "] repository = "https://github.com/hrkfdn/ncspot" keywords = ["spotify", "ncurses", "librespot", "terminal"] @@ -14,7 +14,7 @@ edition = "2021" maintenance = { status = "actively-developed" } [dependencies] -clap = "3.1.12" +clap = "3.1.18" chrono = "0.4" reqwest = { version = "0.11", features = ["blocking", "json"] } crossbeam-channel = "0.5" @@ -22,14 +22,14 @@ platform-dirs = "0.3.0" fern = "0.6" futures = "0.3" lazy_static = "1.3.0" -librespot-core = "0.3.1" -librespot-playback = "0.3.1" -librespot-protocol = "0.3.1" +librespot-core = "0.4.0" +librespot-playback = "0.4.0" +librespot-protocol = "0.4.0" log = "0.4.16" serde = "1.0" serde_json = "1.0" tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } -tokio-stream = "0.1.8" +tokio-stream = "0.1.9" toml = "0.5" unicode-width = "0.1.9" dbus = { version = "0.9.5", optional = true } @@ -88,5 +88,6 @@ It is heavily inspired by ncurses MPD clients, such as ncmpc.""" license-file = ["LICENSE"] assets = [ ["target/release/ncspot", "usr/bin/", "755"], + ["misc/ncspot.desktop", "usr/share/applications/", "644"], ["README.md", "usr/share/doc/ncspot/README.md", "644"], ] diff --git a/README.md b/README.md index 3f8381070..da7445388 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- logo + logo

# ncspot @@ -46,6 +46,7 @@ as the \*BSDs. - [Custom Keybindings](#custom-keybindings) - [Proxy](#proxy) - [Theming](#theming) + - [Track Formatting](#track-formatting) - [Cover Drawing](#cover-drawing) - [Authentication](#authentication) @@ -307,28 +308,30 @@ runtime use the command prompt by typing `:reload`. Possible configuration values are: -| Name | Description | Possible values | Default | -| :----------------------- | :------------------------------------------ |:--------------------------------------------------|:-----------:| -| `command_key` | Key to open command line | Single character | `:` | -| `initial_screen` | Screen to show after startup | `"library"`, `"search"`, `"queue"`, `"cover"`[^2] | `"library"` | -| `use_nerdfont` | Turn nerdfont glyphs on/off | `true`, `false` | `false` | -| `flip_status_indicators` | Reverse play/pause icon meaning[^1] | `true`, `false` | `false` | -| `backend` | Audio backend to use | String [^3] | | -| `backend_device` | Audio device to configure the backend | String | | -| `audio_cache` | Enable caching of audio files | `true`, `false` | `true` | -| `audio_cache_size` | Maximum size of audio cache in MiB | Number | | -| `volnorm` | Enable volume normalization | `true`, `false` | `false` | -| `volnorm_pregain` | Normalization pregain to apply (if enabled) | Number | 0 | -| `default_keybindings` | Enable default keybindings | `true`, `false` | `false` | -| `notify` | Enable desktop notifications | `true`, `false` | `false` | -| `bitrate` | Audio bitrate to use for streaming | `96`, `160`, `320` | `320` | -| `album_column` | Show album column for tracks | `true`, `false` | `true` | -| `gapless` | Enable gapless playback | `true`, `false` | `true` | -| `shuffle` | Set default shuffle state | `true`, `false` | `false` | -| `repeat` | Set default repeat mode | `off`, `track`, `playlist` | `off` | -| `playback_state` | Set default playback state | `"Stopped"`, `"Paused"`, `"Playing"`, `"Default"` | `"Paused"` | -| `[theme]` | Custom theme | See [custom theme](#theming) | | -| `[keybindings]` | Custom keybindings | See [custom keybindings](#custom-keybindings) | | +| Name | Description | Possible values | Default | +|--------------------------|---------------------------------------------------|-----------------------------------------------------------------|-------------| +| `command_key` | Key to open command line | Single character | `:` | +| `initial_screen` | Screen to show after startup | `"library"`, `"search"`, `"queue"`, `"cover"`[^2] | `"library"` | +| `use_nerdfont` | Turn nerdfont glyphs on/off | `true`, `false` | `false` | +| `flip_status_indicators` | Reverse play/pause icon meaning[^1] | `true`, `false` | `false` | +| `backend` | Audio backend to use | String [^3] | | +| `backend_device` | Audio device to configure the backend | String | | +| `audio_cache` | Enable caching of audio files | `true`, `false` | `true` | +| `audio_cache_size` | Maximum size of audio cache in MiB | Number | | +| `volnorm` | Enable volume normalization | `true`, `false` | `false` | +| `volnorm_pregain` | Normalization pregain to apply in dB (if enabled) | Number | `0.0` | +| `default_keybindings` | Enable default keybindings | `true`, `false` | `false` | +| `notify` | Enable desktop notifications | `true`, `false` | `false` | +| `bitrate` | Audio bitrate to use for streaming | `96`, `160`, `320` | `320` | +| `album_column` | Show album column for tracks | `true`, `false` | `true` | +| `gapless` | Enable gapless playback | `true`, `false` | `true` | +| `shuffle` | Set default shuffle state | `true`, `false` | `false` | +| `repeat` | Set default repeat mode | `off`, `track`, `playlist` | `off` | +| `playback_state` | Set default playback state | `"Stopped"`, `"Paused"`, `"Playing"`, `"Default"` | `"Paused"` | +| `library_tabs` | Tabs to show in library screen | Array of `tracks`, `albums`, `artists`, `playlists`, `podcasts` | All tabs | +| `[track_format]` | Set active fields shown in Library/Queue views | See [track formatting](#track-formatting) | | +| `[theme]` | Custom theme | See [custom theme](#theming) | | +| `[keybindings]` | Custom keybindings | See [custom keybindings](#custom-keybindings) | | [^1]: By default the statusbar will show a play icon when a track is playing and @@ -384,6 +387,65 @@ search_match = "light red" More examples can be found in [this pull request](https://github.com/hrkfdn/ncspot/pull/40). +### Track Formatting +It's possible to customize which fields are shown in Queue/Library views. +If you don't define `center` for example, the default value will be used. +Available options for tracks: +`%artists`, `%title`, `%album`, `%saved`, `%duration` +Default configuration: + +```toml +[track_format] +left = "%artists - %title" +center = "%album" +right = "%saved %duration" +``` + +
Examples: (Click to show/hide) + + +Example 1 - Show only album name and track name after it: + +```toml +[track_format] +left = "%album" +center = "%title" +right = "" +``` + +Example 2 - Show track title before artists, and don't show album at all: + +```toml +[track_format] +left = "%title - %artists" +center = "" +``` + +Example 3 - Show everything as default, but hide saved status and track length: + +```toml +[track_format] +right = "" +``` + +Example 4 - Show everything as default, except show title before artists: + +```toml +[track_format] +left = "%title - %artists" +``` + +Example 5 - Show saved status and duration first, followed by track title and artists, with the album last: + +```toml +[track_format] +left = "|%saved| %duration | %title - %artists" +center = "" +right = "%album" +``` + +
+ ## Cover Drawing When compiled with the `cover` feature, `ncspot` can draw the album art of the diff --git a/misc/ncspot.desktop b/misc/ncspot.desktop new file mode 100755 index 000000000..c4096e7f7 --- /dev/null +++ b/misc/ncspot.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Name=ncspot +Comment=Cross-platform ncurses Spotify client written in Rust +TryExec=ncspot +Exec=ncspot +Icon=ncspot +Terminal=true +Categories=AudioVideo;Audio;Player;ConsoleOnly +Keywords=spotify;music;player diff --git a/src/command.rs b/src/command.rs index 4d1ef77ce..ce4b4c05b 100644 --- a/src/command.rs +++ b/src/command.rs @@ -138,6 +138,7 @@ pub enum Command { VolumeDown(u16), Repeat(Option), Shuffle(Option), + #[cfg(feature = "share_clipboard")] Share(TargetMode), Back, Open(TargetMode), @@ -174,6 +175,7 @@ impl fmt::Display for Command { Some(b) => vec![(if *b { "on" } else { "off" }).into()], None => vec![], }, + #[cfg(feature = "share_clipboard")] Command::Share(mode) => vec![mode.to_string()], Command::Open(mode) => vec![mode.to_string()], Command::Goto(mode) => vec![mode.to_string()], @@ -243,6 +245,7 @@ impl Command { Command::VolumeDown(_) => "voldown", Command::Repeat(_) => "repeat", Command::Shuffle(_) => "shuffle", + #[cfg(feature = "share_clipboard")] Command::Share(_) => "share", Command::Back => "back", Command::Open(_) => "open", @@ -499,6 +502,7 @@ pub fn parse(input: &str) -> Result, CommandParseError> { }?; Command::Shuffle(switch) } + #[cfg(feature = "share_clipboard")] "share" => { let &target_mode_raw = args.get(0).ok_or(InsufficientArgs { cmd: command.into(), @@ -631,18 +635,18 @@ pub fn parse(input: &str) -> Result, CommandParseError> { match args.get(0).cloned() { #[cfg(feature = "share_clipboard")] Some("") | None => Ok(InsertSource::Clipboard), + // if clipboard feature is disabled and args is empty + #[cfg(not(feature = "share_clipboard"))] + None => Err(InsufficientArgs { + cmd: command.into(), + hint: Some("a Spotify URL".into()), + }), Some(url) => SpotifyUrl::from_url(url).map(InsertSource::Input).ok_or( ArgParseError { arg: url.into(), err: "Invalid Spotify URL".into(), }, ), - // if clipboard feature is disabled and args is empty - #[allow(unreachable_patterns)] - None => Err(InsufficientArgs { - cmd: command.into(), - hint: Some("a Spotify URL".into()), - }), }?; Command::Insert(insert_source) } diff --git a/src/commands.rs b/src/commands.rs index fe0a8916d..03f140535 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3,8 +3,7 @@ use std::sync::Arc; use std::time::Duration; use crate::command::{ - parse, Command, GotoMode, InsertSource, JumpMode, MoveAmount, MoveMode, SeekDirection, - ShiftMode, TargetMode, + parse, Command, GotoMode, JumpMode, MoveAmount, MoveMode, SeekDirection, ShiftMode, TargetMode, }; use crate::config::Config; use crate::events::EventManager; @@ -275,7 +274,6 @@ impl CommandManager { | Command::SaveQueue | Command::Delete | Command::Focus(_) - | Command::Share(_) | Command::Back | Command::Open(_) | Command::Goto(_) @@ -288,6 +286,11 @@ impl CommandManager { "The command \"{}\" is unsupported in this view", cmd.basename() )), + #[cfg(feature = "share_clipboard")] + Command::Share(_) => Err(format!( + "The command \"{}\" is unsupported in this view", + cmd.basename() + )), } } @@ -424,8 +427,12 @@ impl CommandManager { kb.insert("r".into(), vec![Command::Repeat(None)]); kb.insert("z".into(), vec![Command::Shuffle(None)]); - kb.insert("x".into(), vec![Command::Share(TargetMode::Selected)]); - kb.insert("Shift+x".into(), vec![Command::Share(TargetMode::Current)]); + + #[cfg(feature = "share_clipboard")] + { + kb.insert("x".into(), vec![Command::Share(TargetMode::Selected)]); + kb.insert("Shift+x".into(), vec![Command::Share(TargetMode::Current)]); + } kb.insert("F1".into(), vec![Command::Focus("queue".into())]); kb.insert("F2".into(), vec![Command::Focus("search".into())]); @@ -528,7 +535,7 @@ impl CommandManager { #[cfg(feature = "share_clipboard")] kb.insert( "Ctrl+v".into(), - vec![Command::Insert(InsertSource::Clipboard)], + vec![Command::Insert(crate::command::InsertSource::Clipboard)], ); kb diff --git a/src/config.rs b/src/config.rs index 94f7519c5..0d28707b0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,6 +23,33 @@ pub enum PlaybackState { Default, } +#[derive(Clone, Serialize, Deserialize, Debug, Hash, strum::EnumIter)] +#[serde(rename_all = "lowercase")] +pub enum LibraryTab { + Tracks, + Albums, + Artists, + Playlists, + Podcasts, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct TrackFormat { + pub left: Option, + pub center: Option, + pub right: Option, +} + +impl TrackFormat { + pub fn default() -> Self { + TrackFormat { + left: Some(String::from("%artists - %title")), + center: Some(String::from("%album")), + right: Some(String::from("%saved %duration")), + } + } +} + #[derive(Clone, Serialize, Deserialize, Debug, Default)] pub struct ConfigValues { pub command_key: Option, @@ -40,12 +67,13 @@ pub struct ConfigValues { pub volnorm_pregain: Option, pub notify: Option, pub bitrate: Option, - pub album_column: Option, pub gapless: Option, pub shuffle: Option, pub repeat: Option, pub cover_max_scale: Option, pub playback_state: Option, + pub track_format: Option, + pub library_tabs: Option>, } #[derive(Serialize, Deserialize, Debug, Default, Clone)] diff --git a/src/main.rs b/src/main.rs index 56545fc44..753447b47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -146,14 +146,9 @@ async fn main() -> Result<(), String> { let cfg: Arc = Arc::new(Config::new( matches.value_of("config").unwrap_or("config.toml"), )); - - let cache = Cache::new( - Some(config::cache_path("librespot")), - Some(config::cache_path("librespot").join("files")), - None, - ) - .expect("Could not create librespot cache"); let mut credentials = { + let cache = Cache::new(Some(config::cache_path("librespot")), None, None, None) + .expect("Could not create librespot cache"); let cached_credentials = cache.credentials(); match cached_credentials { Some(c) => { diff --git a/src/model/album.rs b/src/model/album.rs index 4bf363679..37e5fc27e 100644 --- a/src/model/album.rs +++ b/src/model/album.rs @@ -165,11 +165,7 @@ impl ListItem for Album { } } - fn as_listitem(&self) -> Box { - Box::new(self.clone()) - } - - fn display_left(&self) -> String { + fn display_left(&self, _library: Arc) -> String { format!("{}", self) } @@ -219,14 +215,6 @@ impl ListItem for Album { } } - fn save(&mut self, library: Arc) { - library.save_album(self); - } - - fn unsave(&mut self, library: Arc) { - library.unsave_album(self); - } - fn toggle_saved(&mut self, library: Arc) { if library.is_saved_album(self) { library.unsave_album(self); @@ -235,6 +223,14 @@ impl ListItem for Album { } } + fn save(&mut self, library: Arc) { + library.save_album(self); + } + + fn unsave(&mut self, library: Arc) { + library.unsave_album(self); + } + fn open(&self, queue: Arc, library: Arc) -> Option> { Some(AlbumView::new(queue, library, self).into_boxed_view_ext()) } @@ -301,4 +297,8 @@ impl ListItem for Album { .collect(), ) } + + fn as_listitem(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/src/model/artist.rs b/src/model/artist.rs index 4ac4c45ee..8028e640c 100644 --- a/src/model/artist.rs +++ b/src/model/artist.rs @@ -94,11 +94,7 @@ impl ListItem for Artist { } } - fn as_listitem(&self) -> Box { - Box::new(self.clone()) - } - - fn display_left(&self) -> String { + fn display_left(&self, _library: Arc) -> String { format!("{}", self) } @@ -155,14 +151,6 @@ impl ListItem for Artist { } } - fn save(&mut self, library: Arc) { - library.follow_artist(self); - } - - fn unsave(&mut self, library: Arc) { - library.unfollow_artist(self); - } - fn toggle_saved(&mut self, library: Arc) { if library.is_followed_artist(self) { library.unfollow_artist(self); @@ -171,6 +159,14 @@ impl ListItem for Artist { } } + fn save(&mut self, library: Arc) { + library.follow_artist(self); + } + + fn unsave(&mut self, library: Arc) { + library.unfollow_artist(self); + } + fn open(&self, queue: Arc, library: Arc) -> Option> { Some(ArtistView::new(queue, library, self).into_boxed_view_ext()) } @@ -205,4 +201,8 @@ impl ListItem for Artist { .clone() .map(|id| format!("https://open.spotify.com/artist/{}", id)) } + + fn as_listitem(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/src/model/episode.rs b/src/model/episode.rs index 3bdab083e..90208a2a7 100644 --- a/src/model/episode.rs +++ b/src/model/episode.rs @@ -75,7 +75,7 @@ impl ListItem for Episode { .unwrap_or(false) } - fn display_left(&self) -> String { + fn display_left(&self, _library: Arc) -> String { self.name.clone() } diff --git a/src/model/playable.rs b/src/model/playable.rs index b887f20e3..1977cff9d 100644 --- a/src/model/playable.rs +++ b/src/model/playable.rs @@ -19,6 +19,55 @@ pub enum Playable { } impl Playable { + pub fn format(playable: Playable, formatting: String, library: Arc) -> String { + formatting + .replace( + "%artists", + if let Some(artists) = playable.artists() { + artists + .iter() + .map(|artist| artist.clone().name) + .collect::>() + .join(", ") + } else { + String::new() + } + .as_str(), + ) + .replace( + "%title", + match playable.clone() { + Playable::Episode(episode) => episode.name, + Playable::Track(track) => track.title, + } + .as_str(), + ) + .replace( + "%album", + match playable.clone() { + Playable::Track(track) => track.album.unwrap_or_default(), + _ => String::new(), + } + .as_str(), + ) + .replace( + "%saved", + if library.is_saved_track(&match playable.clone() { + Playable::Episode(episode) => Playable::Episode(episode), + Playable::Track(track) => Playable::Track(track), + }) { + if library.cfg.values().use_nerdfont.unwrap_or_default() { + "\u{f62b}" + } else { + "✓" + } + } else { + "" + }, + ) + .replace("%duration", playable.duration_str().as_str()) + } + pub fn id(&self) -> Option { match self { Playable::Track(track) => track.id.clone(), @@ -106,8 +155,8 @@ impl ListItem for Playable { self.as_listitem().is_playing(queue) } - fn display_left(&self) -> String { - self.as_listitem().display_left() + fn display_left(&self, library: Arc) -> String { + self.as_listitem().display_left(library) } fn display_center(&self, library: Arc) -> String { diff --git a/src/model/playlist.rs b/src/model/playlist.rs index 4804a66d9..cdf44a636 100644 --- a/src/model/playlist.rs +++ b/src/model/playlist.rs @@ -191,11 +191,7 @@ impl ListItem for Playlist { } } - fn as_listitem(&self) -> Box { - Box::new(self.clone()) - } - - fn display_left(&self) -> String { + fn display_left(&self, _library: Arc) -> String { match self.owner_name.as_ref() { Some(owner) => format!("{} • {}", self.name, owner), None => self.name.clone(), @@ -251,14 +247,6 @@ impl ListItem for Playlist { } } - fn save(&mut self, library: Arc) { - library.follow_playlist(self); - } - - fn unsave(&mut self, library: Arc) { - library.delete_playlist(&self.id); - } - fn toggle_saved(&mut self, library: Arc) { // Don't allow users to unsave their own playlists with one keypress if !library.is_followed_playlist(self) { @@ -272,6 +260,14 @@ impl ListItem for Playlist { } } + fn save(&mut self, library: Arc) { + library.follow_playlist(self); + } + + fn unsave(&mut self, library: Arc) { + library.delete_playlist(&self.id); + } + fn open(&self, queue: Arc, library: Arc) -> Option> { Some(PlaylistView::new(queue, library, self).into_boxed_view_ext()) } @@ -326,4 +322,8 @@ impl ListItem for Playlist { self.owner_id, self.id )) } + + fn as_listitem(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/src/model/show.rs b/src/model/show.rs index 94240f5e0..9dcabd750 100644 --- a/src/model/show.rs +++ b/src/model/show.rs @@ -76,7 +76,7 @@ impl ListItem for Show { false } - fn display_left(&self) -> String { + fn display_left(&self, _library: Arc) -> String { format!("{}", self) } diff --git a/src/model/track.rs b/src/model/track.rs index 3e32ff988..13ba7626c 100644 --- a/src/model/track.rs +++ b/src/model/track.rs @@ -1,6 +1,7 @@ use std::fmt; use std::sync::{Arc, RwLock}; +use crate::config; use chrono::{DateTime, Utc}; use rspotify::model::album::FullAlbum; use rspotify::model::track::{FullTrack, SavedTrack, SimplifiedTrack}; @@ -181,33 +182,61 @@ impl ListItem for Track { current.map(|t| t.id() == self.id).unwrap_or(false) } - fn as_listitem(&self) -> Box { - Box::new(self.clone()) - } - - fn display_left(&self) -> String { - format!("{}", self) + fn display_left(&self, library: Arc) -> String { + let formatting = library + .cfg + .values() + .track_format + .clone() + .unwrap_or_default(); + let default = config::TrackFormat::default().left.unwrap(); + let left = formatting.left.unwrap_or_else(|| default.clone()); + if left != default { + Playable::format(Playable::Track(self.clone()), left, library) + } else { + format!("{}", self) + } } fn display_center(&self, library: Arc) -> String { - if library.cfg.values().album_column.unwrap_or(true) { - self.album.clone().unwrap_or_default() + let formatting = library + .cfg + .values() + .track_format + .clone() + .unwrap_or_default(); + let default = config::TrackFormat::default().center.unwrap(); + let center = formatting.center.unwrap_or_else(|| default.clone()); + if center != default { + Playable::format(Playable::Track(self.clone()), center, library) } else { - "".to_string() + self.album.clone().unwrap_or_default() } } fn display_right(&self, library: Arc) -> String { - let saved = if library.is_saved_track(&Playable::Track(self.clone())) { - if library.cfg.values().use_nerdfont.unwrap_or(false) { - "\u{f62b} " - } else { - "✓ " - } + let formatting = library + .cfg + .values() + .track_format + .clone() + .unwrap_or_default(); + let default = config::TrackFormat::default().right.unwrap(); + let right = formatting.right.unwrap_or_else(|| default.clone()); + if right != default { + Playable::format(Playable::Track(self.clone()), right, library) } else { - "" - }; - format!("{}{}", saved, self.duration_str()) + let saved = if library.is_saved_track(&Playable::Track(self.clone())) { + if library.cfg.values().use_nerdfont.unwrap_or(false) { + "\u{f62b}" + } else { + "✓" + } + } else { + "" + }; + format!("{} {}", saved, self.duration_str()) + } } fn play(&mut self, queue: Arc) { @@ -223,14 +252,6 @@ impl ListItem for Track { queue.append(Playable::Track(self.clone())); } - fn save(&mut self, library: Arc) { - library.save_tracks(vec![self], true); - } - - fn unsave(&mut self, library: Arc) { - library.unsave_tracks(vec![self], true); - } - fn toggle_saved(&mut self, library: Arc) { if library.is_saved_track(&Playable::Track(self.clone())) { library.unsave_tracks(vec![self], true); @@ -239,6 +260,14 @@ impl ListItem for Track { } } + fn save(&mut self, library: Arc) { + library.save_tracks(vec![self], true); + } + + fn unsave(&mut self, library: Arc) { + library.unsave_tracks(vec![self], true); + } + fn open(&self, _queue: Arc, _library: Arc) -> Option> { None } @@ -303,4 +332,8 @@ impl ListItem for Track { fn track(&self) -> Option { Some(self.clone()) } + + fn as_listitem(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/src/queue.rs b/src/queue.rs index 352e5fe55..84bb5f3ac 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,10 +1,11 @@ use std::cmp::Ordering; +#[cfg(feature = "notify")] use std::sync::atomic::AtomicU32; use std::sync::{Arc, RwLock}; use log::{debug, error, info}; #[cfg(feature = "notify")] -use notify_rust::Notification; +use notify_rust::{Hint, Notification, Urgency}; use rand::prelude::*; use strum_macros::Display; @@ -14,9 +15,6 @@ use crate::model::playable::Playable; use crate::spotify::Spotify; use crate::{config::Config, spotify::PlayerEvent}; -#[cfg(feature = "cover")] -use crate::ui; - #[derive(Display, Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] pub enum RepeatSetting { #[serde(rename = "off")] @@ -38,6 +36,7 @@ pub struct Queue { current_track: RwLock>, spotify: Spotify, cfg: Arc, + #[cfg(feature = "notify")] notification_id: Arc, } @@ -51,6 +50,7 @@ impl Queue { current_track: RwLock::new(queue_state.current_track), random_order: RwLock::new(queue_state.random_order), cfg, + #[cfg(feature = "notify")] notification_id: Arc::new(AtomicU32::new(0)), }; @@ -65,7 +65,7 @@ impl Queue { PlaybackState::Stopped => { spotify.stop(); } - PlaybackState::Paused | PlaybackState::Default | _ => { + PlaybackState::Paused | PlaybackState::Playing | PlaybackState::Default => { spotify.pause(); } } @@ -433,47 +433,47 @@ impl Queue { #[cfg(feature = "notify")] pub fn send_notification( track_name: &str, - _cover_url: Option, + cover_url: Option, notification_id: Arc, ) { let current_notification_id = notification_id.load(std::sync::atomic::Ordering::Relaxed); - let res = if let Some(u) = _cover_url { - // download album cover image - let path = crate::utils::cache_path_for_url(u.to_string()); + let mut n = Notification::new(); + n.appname("ncspot") + .id(current_notification_id) + .summary(track_name); + + // album cover image + if let Some(u) = cover_url { + let path = crate::utils::cache_path_for_url(u.to_string()); if !path.exists() { if let Err(e) = crate::utils::download(u, path.clone()) { error!("Failed to download cover: {}", e); } } + n.icon(path.to_str().unwrap()); + } - Notification::new() - .appname("ncspot") - .id(current_notification_id) - .summary(track_name) - .icon(path.to_str().unwrap()) - .show() - } else { - Notification::new() - .appname("ncspot") - .id(current_notification_id) - .summary(track_name) - .show() - }; - - if let Ok(n) = res { - // only available for XDG - #[cfg(all(unix, not(target_os = "macos")))] - { - let new_notification_id = n.id(); - log::debug!( - "new notification id: {}, previously: {}", - new_notification_id, - current_notification_id - ); - notification_id.store(new_notification_id, std::sync::atomic::Ordering::Relaxed); + // XDG desktop entry hints + #[cfg(all(unix, not(target_os = "macos")))] + n.urgency(Urgency::Low) + .hint(Hint::Transient(true)) + .hint(Hint::DesktopEntry("ncspot".into())); + + match n.show() { + Ok(_handle) => { + // only available for XDG + #[cfg(all(unix, not(target_os = "macos")))] + { + let new_notification_id = _handle.id(); + log::debug!( + "new notification id: {}, previously: {}", + new_notification_id, + current_notification_id + ); + notification_id.store(new_notification_id, std::sync::atomic::Ordering::Relaxed); + } } - } else if let Err(e) = res { - error!("Failed to send notification cover: {}", e); + Err(e) => error!("Failed to send notification cover: {}", e), } } diff --git a/src/sharing.rs b/src/sharing.rs index 7e23a0627..3779a1a03 100644 --- a/src/sharing.rs +++ b/src/sharing.rs @@ -14,7 +14,7 @@ use { #[cfg(feature = "share_selection")] use clipboard::{x11_clipboard, x11_clipboard::X11ClipboardContext}; -#[cfg(feature = "share_selection")] +#[cfg(all(feature = "share_selection", feature = "wayland_clipboard"))] use wl_clipboard_rs::utils::{is_primary_selection_supported, PrimarySelectionCheckError}; #[cfg(not(feature = "share_selection"))] @@ -80,8 +80,8 @@ pub fn read_share() -> Option { #[cfg(feature = "wayland_clipboard")] { //use wayland clipboard - match is_primary_selection_supported() { - Ok(supported) => { + string = match is_primary_selection_supported() { + Ok(_supported) => { let result = get_contents( paste::ClipboardType::Primary, Seat::Unspecified, @@ -124,11 +124,7 @@ pub fn read_share() -> Option { } } } - if let Some(s) = string { - Some(s) - } else { - None - } + string } else { //use x11 clipboard ClipboardProvider::new() diff --git a/src/spotify.rs b/src/spotify.rs index 998156b72..705dbb310 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -126,29 +126,33 @@ impl Spotify { pub fn test_credentials(credentials: Credentials) -> Result { let config = Self::session_config(); let handle = tokio::runtime::Handle::current(); - let jh = handle.spawn(async { Session::connect(config, credentials, None).await }); - futures::executor::block_on(jh).unwrap() + let jh = handle.spawn(async { Session::connect(config, credentials, None, true).await }); + futures::executor::block_on(jh).unwrap().map(|r| r.0) } async fn create_session( cfg: &config::Config, credentials: Credentials, ) -> Result { - let session_config = Self::session_config(); + let librespot_cache_path = config::cache_path("librespot"); let audio_cache_path = match cfg.values().audio_cache.unwrap_or(true) { - true => Some(config::cache_path("librespot").join("files")), + true => Some(librespot_cache_path.join("files")), false => None, }; let cache = Cache::new( - Some(config::cache_path("librespot")), + Some(librespot_cache_path.clone()), audio_cache_path, + Some(librespot_cache_path.join("volume")), cfg.values() .audio_cache_size - .map(|size| (size * 1048576) as u64), + .map(|size| (size as u64 * 1048576)), ) .expect("Could not create cache"); debug!("opening spotify session"); - Session::connect(session_config, credentials, Some(cache)).await + let session_config = Self::session_config(); + Session::connect(session_config, credentials, Some(cache), true) + .await + .map(|r| r.0) } async fn worker( @@ -170,7 +174,7 @@ impl Spotify { gapless: cfg.values().gapless.unwrap_or(true), bitrate: bitrate.unwrap_or(Bitrate::Bitrate320), normalisation: cfg.values().volnorm.unwrap_or(false), - normalisation_pregain: cfg.values().volnorm_pregain.unwrap_or(0.0), + normalisation_pregain_db: cfg.values().volnorm_pregain.unwrap_or(0.0), ..Default::default() }; @@ -189,7 +193,7 @@ impl Spotify { let (player, player_events) = Player::new( player_config, session.clone(), - mixer.get_audio_filter(), + mixer.get_soft_volume(), move || (backend)(cfg.values().backend_device.clone(), audio_format), ); diff --git a/src/traits.rs b/src/traits.rs index b1139ae94..426a0a229 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -14,14 +14,14 @@ use crate::queue::Queue; pub trait ListItem: Sync + Send + 'static { fn is_playing(&self, queue: Arc) -> bool; - fn display_left(&self) -> String; + fn display_left(&self, library: Arc) -> String; fn display_center(&self, _library: Arc) -> String { "".to_string() } fn display_right(&self, library: Arc) -> String; fn play(&mut self, queue: Arc); - fn queue(&mut self, queue: Arc); fn play_next(&mut self, queue: Arc); + fn queue(&mut self, queue: Arc); fn toggle_saved(&mut self, library: Arc); fn save(&mut self, library: Arc); fn unsave(&mut self, library: Arc); diff --git a/src/ui/contextmenu.rs b/src/ui/contextmenu.rs index 1307d280c..2cadd509d 100644 --- a/src/ui/contextmenu.rs +++ b/src/ui/contextmenu.rs @@ -43,6 +43,7 @@ enum ContextMenuAction { PlayTrack(Box), ShowItem(Box), SelectArtist(Vec), + #[cfg(feature = "share_clipboard")] ShareUrl(String), AddToPlaylist(Box), ShowRecommendations(Box), @@ -183,13 +184,14 @@ impl ContextMenu { if let Some(a) = item.album(queue.clone()) { content.add_item("Show album", ContextMenuAction::ShowItem(Box::new(a))); } - if let Some(url) = item.share_url() { - #[cfg(feature = "share_clipboard")] - content.add_item("Share", ContextMenuAction::ShareUrl(url)); - } - if let Some(url) = item.album(queue.clone()).and_then(|a| a.share_url()) { - #[cfg(feature = "share_clipboard")] - content.add_item("Share album", ContextMenuAction::ShareUrl(url)); + #[cfg(feature = "share_clipboard")] + { + if let Some(url) = item.share_url() { + content.add_item("Share", ContextMenuAction::ShareUrl(url)); + } + if let Some(url) = item.album(queue.clone()).and_then(|a| a.share_url()) { + content.add_item("Share album", ContextMenuAction::ShareUrl(url)); + } } if let Some(t) = item.track() { content.insert_item( @@ -215,48 +217,51 @@ impl ContextMenu { } // open detail view of artist/album - content.set_on_submit(move |s: &mut Cursive, action: &ContextMenuAction| { - s.pop_layer(); - let queue = queue.clone(); + { let library = library.clone(); + content.set_on_submit(move |s: &mut Cursive, action: &ContextMenuAction| { + let queue = queue.clone(); + let library = library.clone(); + s.pop_layer(); - match action { - ContextMenuAction::PlayTrack(track) => { - let dialog = Self::play_track_dialog(queue, *track.clone()); - s.add_layer(dialog); - } - ContextMenuAction::ShowItem(item) => { - if let Some(view) = item.open(queue, library) { - s.call_on_name("main", move |v: &mut Layout| v.push_view(view)); + match action { + ContextMenuAction::PlayTrack(track) => { + let dialog = Self::play_track_dialog(queue, *track.clone()); + s.add_layer(dialog); + } + ContextMenuAction::ShowItem(item) => { + if let Some(view) = item.open(queue, library) { + s.call_on_name("main", move |v: &mut Layout| v.push_view(view)); + } } - } - ContextMenuAction::ShareUrl(url) => { #[cfg(feature = "share_clipboard")] - write_share(url.to_string()); - } - ContextMenuAction::AddToPlaylist(track) => { - let dialog = - Self::add_track_dialog(library, queue.get_spotify(), *track.clone()); - s.add_layer(dialog); - } - ContextMenuAction::ShowRecommendations(item) => { - if let Some(view) = item.to_owned().open_recommendations(queue, library) { - s.call_on_name("main", move |v: &mut Layout| v.push_view(view)); + ContextMenuAction::ShareUrl(url) => { + write_share(url.to_string()); + } + ContextMenuAction::AddToPlaylist(track) => { + let dialog = + Self::add_track_dialog(library, queue.get_spotify(), *track.clone()); + s.add_layer(dialog); + } + ContextMenuAction::ShowRecommendations(item) => { + if let Some(view) = item.to_owned().open_recommendations(queue, library) { + s.call_on_name("main", move |v: &mut Layout| v.push_view(view)); + } + } + ContextMenuAction::ToggleTrackSavedStatus(track) => { + let mut track: Track = *track.clone(); + track.toggle_saved(library); + } + ContextMenuAction::SelectArtist(artists) => { + let dialog = Self::select_artist_dialog(library, queue, artists.clone()); + s.add_layer(dialog); } } - ContextMenuAction::ToggleTrackSavedStatus(track) => { - let mut track: Track = *track.clone(); - track.toggle_saved(library); - } - ContextMenuAction::SelectArtist(artists) => { - let dialog = Self::select_artist_dialog(library, queue, artists.clone()); - s.add_layer(dialog); - } - } - }); + }); + } let dialog = Dialog::new() - .title(item.display_left()) + .title(item.display_left(library)) .dismiss_button("Cancel") .padding(Margins::lrtb(1, 1, 1, 0)) .content(content.with_name("contextmenu_select")); diff --git a/src/ui/cover.rs b/src/ui/cover.rs index 4cd794037..e0ef4d28c 100644 --- a/src/ui/cover.rs +++ b/src/ui/cover.rs @@ -1,5 +1,4 @@ use std::collections::HashSet; -use std::fs::File; use std::io::Write; use std::path::PathBuf; use std::process::{Child, Stdio}; @@ -240,6 +239,7 @@ impl ViewExt for CoverView { track.unsave(self.library.clone()); } } + #[cfg(feature = "share_clipboard")] Command::Share(_mode) => { let url = self .queue @@ -247,7 +247,6 @@ impl ViewExt for CoverView { .and_then(|t| t.as_listitem().share_url()); if let Some(url) = url { - #[cfg(feature = "share_clipboard")] crate::sharing::write_share(url); } diff --git a/src/ui/library.rs b/src/ui/library.rs index bbbc09393..b103e4416 100644 --- a/src/ui/library.rs +++ b/src/ui/library.rs @@ -2,9 +2,11 @@ use std::sync::Arc; use cursive::view::ViewWrapper; use cursive::Cursive; +use strum::IntoEnumIterator; use crate::command::Command; use crate::commands::CommandResult; +use crate::config::LibraryTab; use crate::library::Library; use crate::queue::Queue; use crate::traits::ViewExt; @@ -19,35 +21,46 @@ pub struct LibraryView { impl LibraryView { pub fn new(queue: Arc, library: Arc) -> Self { - let tabs = TabView::new() - .tab( - "tracks", - "Tracks", - ListView::new(library.tracks.clone(), queue.clone(), library.clone()), - ) - .tab( - "albums", - "Albums", - ListView::new(library.albums.clone(), queue.clone(), library.clone()), - ) - .tab( - "artists", - "Artists", - ListView::new(library.artists.clone(), queue.clone(), library.clone()), - ) - .tab( - "playlists", - "Playlists", - PlaylistsView::new(queue.clone(), library.clone()), - ) - .tab( - "podcasts", - "Podcasts", - ListView::new(library.shows.clone(), queue, library.clone()), - ); + let mut tabview = TabView::new(); + let selected_tabs = library + .cfg + .values() + .library_tabs + .clone() + .unwrap_or_else(|| Vec::from_iter(LibraryTab::iter())); + + for tab in selected_tabs { + match tab { + LibraryTab::Tracks => tabview.add_tab( + "tracks", + "Tracks", + ListView::new(library.tracks.clone(), queue.clone(), library.clone()), + ), + LibraryTab::Albums => tabview.add_tab( + "albums", + "Albums", + ListView::new(library.albums.clone(), queue.clone(), library.clone()), + ), + LibraryTab::Artists => tabview.add_tab( + "artists", + "Artists", + ListView::new(library.artists.clone(), queue.clone(), library.clone()), + ), + LibraryTab::Playlists => tabview.add_tab( + "playlists", + "Playlists", + PlaylistsView::new(queue.clone(), library.clone()), + ), + LibraryTab::Podcasts => tabview.add_tab( + "podcasts", + "Podcasts", + ListView::new(library.shows.clone(), queue.clone(), library.clone()), + ), + } + } Self { - tabs, + tabs: tabview, display_name: library.display_name.clone(), } } diff --git a/src/ui/listview.rs b/src/ui/listview.rs index 1f5a3e6c7..6277fa2a5 100644 --- a/src/ui/listview.rs +++ b/src/ui/listview.rs @@ -24,12 +24,12 @@ use crate::model::track::Track; use crate::queue::Queue; #[cfg(feature = "share_clipboard")] use crate::sharing::{read_share, write_share}; +use crate::spotify::UriType; use crate::traits::{IntoBoxedViewExt, ListItem, ViewExt}; use crate::ui::album::AlbumView; use crate::ui::artist::ArtistView; use crate::ui::contextmenu::ContextMenu; use crate::ui::pagination::Pagination; -use crate::{spotify::UriType, spotify_url::SpotifyUrl}; pub struct ListView { content: Arc>>, @@ -108,7 +108,7 @@ impl ListView { .iter() .enumerate() .filter(|(_, i)| { - i.display_left() + i.display_left(self.library.clone()) .to_lowercase() .contains(&query[..].to_lowercase()) }) @@ -189,7 +189,7 @@ impl View for ListView { ColorStyle::primary() }; - let left = item.display_left(); + let left = item.display_left(self.library.clone()); let center = item.display_center(self.library.clone()); let right = item.display_right(self.library.clone()); let draw_center = !center.is_empty(); @@ -400,6 +400,7 @@ impl ViewExt for ListView { return Ok(CommandResult::Consumed(None)); } + #[cfg(feature = "share_clipboard")] Command::Share(mode) => { let url = match mode { TargetMode::Selected => self.content.read().ok().and_then(|content| { @@ -412,7 +413,6 @@ impl ViewExt for ListView { }; if let Some(url) = url { - #[cfg(feature = "share_clipboard")] write_share(url); } @@ -428,7 +428,7 @@ impl ViewExt for ListView { self.move_focus_to(index); return Ok(CommandResult::Consumed(None)); } - None => return Ok(CommandResult::Ignored), + None => return Ok(CommandResult::Consumed(None)), } } JumpMode::Next => { @@ -550,7 +550,9 @@ impl ViewExt for ListView { let url = match source { InsertSource::Input(url) => Some(url.clone()), #[cfg(feature = "share_clipboard")] - InsertSource::Clipboard => read_share().and_then(SpotifyUrl::from_url), + InsertSource::Clipboard => { + read_share().and_then(crate::spotify_url::SpotifyUrl::from_url) + } }; let spotify = self.queue.get_spotify(); diff --git a/src/utils.rs b/src/utils.rs index ac5c1c3ee..1fdc81117 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + /// Returns a human readable String of a Duration /// /// Example: `3h 12m 53s`