feat: improvements and bug fixes (sarcasm)

- `rest/getArtists` and `rest/getArtist`
- Improved artist formatting algorithm
- Other dispersed improvements
This commit is contained in:
Lys 2023-10-18 23:05:09 +03:00
parent d3c1db04c2
commit 7b78375402
Signed by: lyssieth
GPG key ID: C9CF3D614FAA3940
15 changed files with 513 additions and 694 deletions

629
Cargo.lock generated
View file

@ -198,9 +198,9 @@ dependencies = [
[[package]] [[package]]
name = "async-compression" name = "async-compression"
version = "0.4.3" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb42b2197bf15ccb092b62c74515dbd8b86d0effd934795f6687c93b6e679a2c" checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2"
dependencies = [ dependencies = [
"brotli", "brotli",
"flate2", "flate2",
@ -212,9 +212,9 @@ dependencies = [
[[package]] [[package]]
name = "async-executor" name = "async-executor"
version = "1.5.4" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1da3ae8dabd9c00f453a329dfe1fb28da3c0a72e2478cdcd93171740c20499" checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0"
dependencies = [ dependencies = [
"async-lock", "async-lock",
"async-task", "async-task",
@ -254,7 +254,7 @@ dependencies = [
"log", "log",
"parking", "parking",
"polling", "polling",
"rustix 0.37.24", "rustix 0.37.25",
"slab", "slab",
"socket2 0.4.9", "socket2 0.4.9",
"waker-fn", "waker-fn",
@ -320,15 +320,15 @@ dependencies = [
[[package]] [[package]]
name = "async-task" name = "async-task"
version = "4.4.1" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9441c6b2fe128a7c2bf680a44c34d0df31ce09e5b7e401fcca3faa483dbc921" checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.73" version = "0.1.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -417,9 +417,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -677,16 +677,6 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.4" version = "0.8.4"
@ -840,16 +830,6 @@ dependencies = [
"syn 2.0.38", "syn 2.0.38",
] ]
[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
dependencies = [
"serde",
"uuid",
]
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.8" version = "0.7.8"
@ -863,10 +843,11 @@ dependencies = [
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
dependencies = [ dependencies = [
"powerfmt",
"serde", "serde",
] ]
@ -908,15 +889,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "encoding_rs"
version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "entities" name = "entities"
version = "0.1.0" version = "0.1.0"
@ -1009,18 +981,6 @@ dependencies = [
"simd-adler32", "simd-adler32",
] ]
[[package]]
name = "findshlibs"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
dependencies = [
"cc",
"lazy_static",
"libc",
"winapi",
]
[[package]] [[package]]
name = "finl_unicode" name = "finl_unicode"
version = "1.2.0" version = "1.2.0"
@ -1029,9 +989,9 @@ checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.27" version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
@ -1054,21 +1014,6 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.2.0" version = "1.2.0"
@ -1383,17 +1328,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.9" version = "0.2.9"
@ -1452,45 +1386,18 @@ dependencies = [
"want", "want",
] ]
[[package]]
name = "hyper-rustls"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
dependencies = [
"futures-util",
"http",
"hyper",
"rustls",
"tokio",
"tokio-rustls",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.57" version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
"iana-time-zone-haiku", "iana-time-zone-haiku",
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
"windows", "windows-core",
] ]
[[package]] [[package]]
@ -1508,7 +1415,7 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a85caa20f41eef2391fd1dd42b015d0eba17171cdb1a162246a7cc03cd73ab1e" checksum = "a85caa20f41eef2391fd1dd42b015d0eba17171cdb1a162246a7cc03cd73ab1e"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.1",
"byteorder", "byteorder",
"flate2", "flate2",
] ]
@ -1614,12 +1521,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "ipnet"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.11.0" version = "0.11.0"
@ -1714,9 +1615,9 @@ checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.10" version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"scopeguard", "scopeguard",
@ -1731,12 +1632,6 @@ dependencies = [
"value-bag", "value-bag",
] ]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -1881,24 +1776,6 @@ dependencies = [
"syn 2.0.38", "syn 2.0.38",
] ]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.3" version = "7.1.3"
@ -2032,50 +1909,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "ordered-float" name = "ordered-float"
version = "3.9.2" version = "3.9.2"
@ -2085,17 +1918,6 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "os_info"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e"
dependencies = [
"log",
"serde",
"winapi",
]
[[package]] [[package]]
name = "ouroboros" name = "ouroboros"
version = "0.17.2" version = "0.17.2"
@ -2134,9 +1956,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
@ -2150,13 +1972,13 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.9.8" version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall", "redox_syscall 0.4.1",
"smallvec", "smallvec",
"windows-targets", "windows-targets",
] ]
@ -2345,6 +2167,12 @@ dependencies = [
"universal-hash", "universal-hash",
] ]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -2480,8 +2308,6 @@ dependencies = [
"poem", "poem",
"quick-xml", "quick-xml",
"sea-orm", "sea-orm",
"sentry",
"sentry-tracing",
"serde", "serde",
"serde_json", "serde_json",
"time", "time",
@ -2529,15 +2355,24 @@ dependencies = [
] ]
[[package]] [[package]]
name = "regex" name = "redox_syscall"
version = "1.10.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata 0.4.1", "regex-automata 0.4.3",
"regex-syntax 0.8.1", "regex-syntax 0.8.2",
] ]
[[package]] [[package]]
@ -2551,13 +2386,13 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.1" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax 0.8.1", "regex-syntax 0.8.2",
] ]
[[package]] [[package]]
@ -2568,52 +2403,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56d84fdd47036b038fc80dd333d10b6aab10d5d31f4a366e20014def75328d33" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reqwest"
version = "0.11.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-rustls",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots 0.25.2",
"winreg",
]
[[package]] [[package]]
name = "rfc7239" name = "rfc7239"
@ -2667,20 +2459,11 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.37.24" version = "0.37.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d" checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"errno", "errno",
@ -2692,11 +2475,11 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.18" version = "0.38.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a74ee2d7c2581cd139b42447d7d9389b889bdaad3a73f1ebb16f2a3237bb19c" checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.1",
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.4.10", "linux-raw-sys 0.4.10",
@ -2709,7 +2492,6 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
dependencies = [ dependencies = [
"log",
"ring", "ring",
"rustls-webpki", "rustls-webpki",
"sct", "sct",
@ -2740,15 +2522,6 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -2909,171 +2682,20 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "semver"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
[[package]]
name = "sentry"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0097a48cd1999d983909f07cb03b15241c5af29e5e679379efac1c06296abecc"
dependencies = [
"httpdate",
"native-tls",
"reqwest",
"rustls",
"sentry-backtrace",
"sentry-contexts",
"sentry-core",
"sentry-debug-images",
"sentry-panic",
"sentry-tower",
"sentry-tracing",
"tokio",
"ureq",
"webpki-roots 0.25.2",
]
[[package]]
name = "sentry-backtrace"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a7b80fa1dd6830a348d38a8d3a9761179047757b7dca29aef82db0118b9670"
dependencies = [
"backtrace",
"once_cell",
"regex",
"sentry-core",
]
[[package]]
name = "sentry-contexts"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7615dc588930f1fd2e721774f25844ae93add2dbe2d3c2f995ce5049af898147"
dependencies = [
"hostname",
"libc",
"os_info",
"rustc_version",
"sentry-core",
"uname",
]
[[package]]
name = "sentry-core"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f51264e4013ed9b16558cce43917b983fa38170de2ca480349ceb57d71d6053"
dependencies = [
"once_cell",
"rand",
"sentry-types",
"serde",
"serde_json",
]
[[package]]
name = "sentry-debug-images"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fe6180fa564d40bb942c9f0084ffb5de691c7357ead6a2b7a3154fae9e401dd"
dependencies = [
"findshlibs",
"once_cell",
"sentry-core",
]
[[package]]
name = "sentry-panic"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "323160213bba549f9737317b152af116af35c0410f4468772ee9b606d3d6e0fa"
dependencies = [
"sentry-backtrace",
"sentry-core",
]
[[package]]
name = "sentry-tower"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffe3ab7bf7f65c9f8ccd20aa136ce5b2140aa6d6a11339e823cd43a7d694a9e"
dependencies = [
"sentry-core",
"tower-layer",
"tower-service",
]
[[package]]
name = "sentry-tracing"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38033822128e73f7b6ca74c1631cef8868890c6cb4008a291cf73530f87b4eac"
dependencies = [
"sentry-backtrace",
"sentry-core",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "sentry-types"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e663b3eb62ddfc023c9cf5432daf5f1a4f6acb1df4d78dd80b740b32dd1a740"
dependencies = [
"debugid",
"hex",
"rand",
"serde",
"serde_json",
"thiserror",
"time",
"url",
"uuid",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.188" version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.188" version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3284,7 +2906,7 @@ dependencies = [
"tokio-stream", "tokio-stream",
"tracing", "tracing",
"url", "url",
"webpki-roots 0.24.0", "webpki-roots",
] ]
[[package]] [[package]]
@ -3334,7 +2956,7 @@ checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
dependencies = [ dependencies = [
"atoi", "atoi",
"base64", "base64",
"bitflags 2.4.0", "bitflags 2.4.1",
"byteorder", "byteorder",
"bytes", "bytes",
"crc", "crc",
@ -3377,7 +2999,7 @@ checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
dependencies = [ dependencies = [
"atoi", "atoi",
"base64", "base64",
"bitflags 2.4.0", "bitflags 2.4.1",
"byteorder", "byteorder",
"crc", "crc",
"dotenvy", "dotenvy",
@ -3489,27 +3111,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.8.0" version = "3.8.0"
@ -3518,8 +3119,8 @@ checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand 2.0.1", "fastrand 2.0.1",
"redox_syscall", "redox_syscall 0.3.5",
"rustix 0.38.18", "rustix 0.38.19",
"windows-sys", "windows-sys",
] ]
@ -3566,14 +3167,15 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.29" version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa", "itoa",
"libc", "libc",
"num_threads", "num_threads",
"powerfmt",
"serde", "serde",
"time-core", "time-core",
"time-macros", "time-macros",
@ -3639,26 +3241,6 @@ dependencies = [
"syn 2.0.38", "syn 2.0.38",
] ]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls",
"tokio",
]
[[package]] [[package]]
name = "tokio-stream" name = "tokio-stream"
version = "0.1.14" version = "0.1.14"
@ -3732,11 +3314,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.37" version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9"
dependencies = [ dependencies = [
"cfg-if",
"log", "log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
@ -3756,9 +3337,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.26" version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3767,9 +3348,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.31" version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable", "valuable",
@ -3841,15 +3422,6 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "uname"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "uncased" name = "uncased"
version = "0.9.9" version = "0.9.9"
@ -3917,22 +3489,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3"
dependencies = [
"base64",
"log",
"native-tls",
"once_cell",
"rustls",
"rustls-webpki",
"url",
"webpki-roots 0.25.2",
]
[[package]] [[package]]
name = "url" name = "url"
version = "2.4.1" version = "2.4.1"
@ -3960,15 +3516,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"
@ -4099,12 +3646,6 @@ dependencies = [
"rustls-webpki", "rustls-webpki",
] ]
[[package]]
name = "webpki-roots"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
[[package]] [[package]]
name = "weezl" name = "weezl"
version = "0.1.7" version = "0.1.7"
@ -4140,10 +3681,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows" name = "windows-core"
version = "0.48.0" version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [ dependencies = [
"windows-targets", "windows-targets",
] ]
@ -4216,23 +3757,13 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.16" version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.6.0" version = "1.6.0"

View file

@ -11,10 +11,10 @@ sea-orm = { version = "0.12", default-features = false, features = [
"with-time", "with-time",
"postgres-array", "postgres-array",
] } ] }
time = { version = "0.3.29", features = [ time = { version = "0.3", features = [
"serde-human-readable", "serde-human-readable",
"macros", "macros",
"parsing", "parsing",
] } ] }
tracing = { version = "0.1.37", features = ["async-await"] } tracing = { version = "0.1", features = ["async-await"] }
serde = { version = "1.0.188", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View file

@ -12,6 +12,9 @@ unmount:
run: mount run: mount
RAVE_STORAGE_DIR=/tmp/media-for-rave RAVE_CACHE_DIR=/tmp/cache-for-rave cargo r RAVE_STORAGE_DIR=/tmp/media-for-rave RAVE_CACHE_DIR=/tmp/cache-for-rave cargo r
run-custom:
cargo r
refresh: refresh:
sea migrate fresh sea migrate fresh
sea generate entity -o ./entities/src --with-serde both --date-time-crate time --lib sea generate entity -o ./entities/src --with-serde both --date-time-crate time --lib

View file

@ -9,9 +9,9 @@ default-run = "rave"
[dependencies] [dependencies]
cfg-if = "1.0.0" cfg-if = "1.0.0"
color-eyre = "0.6.2" color-eyre = "0.6"
md5 = "0.7.0" md5 = "0.7"
poem = { version = "1.3.58", features = [ poem = { version = "1.3", features = [
"compression", "compression",
"cookie", "cookie",
"session", "session",
@ -19,40 +19,28 @@ poem = { version = "1.3.58", features = [
"xml", "xml",
"tower-compat", "tower-compat",
] } ] }
quick-xml = { version = "0.30.0", features = ["serialize"] } quick-xml = { version = "0.30", features = ["serialize"] }
serde = { workspace = true } serde = { workspace = true }
serde_json = "1.0.107" serde_json = "1.0"
time = { workspace = true, features = ["local-offset"] } time = { workspace = true, features = ["local-offset"] }
tokio = { version = "1.32.0", features = ["full"] } tokio = { version = "1.33", features = ["full"] }
tracing = { workspace = true } tracing = { workspace = true }
tracing-subscriber = { version = "0.3.17", features = [ tracing-subscriber = { version = "0.3", features = [
"env-filter", "env-filter",
"tracing", "tracing",
"parking_lot", "parking_lot",
"time", "time",
"json", "json",
] } ] }
url = { version = "2.4.1", features = ["serde"] } url = { version = "2.4", features = ["serde"] }
url-escape = "0.1.1" url-escape = "0.1"
sea-orm = { workspace = true } sea-orm = { workspace = true }
entities = { workspace = true } entities = { workspace = true }
migration = { workspace = true } migration = { workspace = true }
once_cell = { version = "1.18.0", features = ["parking_lot"] } once_cell = { version = "1.18", features = ["parking_lot"] }
futures = "0.3" futures = "0.3"
audiotags = "0.4.1" audiotags = "0.4"
tracing-appender = "0.2.2" tracing-appender = "0.2"
sentry = { version = "0.31.7", default-features = false, features = [ blake3 = "1.5"
"backtrace", image = "0.24"
"contexts", nate = "0.4"
"panic",
"transport",
"debug-images",
"reqwest",
"rustls",
"tower",
"tracing",
] }
sentry-tracing = { version = "0.31.7", features = ["backtrace"] }
blake3 = "1.5.0"
image = "0.24.7"
nate = "0.4.0"

View file

@ -11,13 +11,12 @@ use migration::{Migrator, MigratorTrait};
use poem::{ use poem::{
http::StatusCode, http::StatusCode,
listener::TcpListener, listener::TcpListener,
middleware::{self, TowerLayerCompatExt}, middleware,
web::{CompressionAlgo, CompressionLevel}, web::{CompressionAlgo, CompressionLevel},
Endpoint, EndpointExt, Request, Route, Endpoint, EndpointExt, Route,
}; };
use sea_orm::{ConnectOptions, Database, DatabaseConnection}; use sea_orm::{ConnectOptions, Database, DatabaseConnection};
use sentry::integrations::tower::NewSentryLayer; use tracing::info;
use tracing::{debug, info};
use tracing_appender::non_blocking::WorkerGuard; use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::{ use tracing_subscriber::{
fmt, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, fmt, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer,
@ -40,21 +39,6 @@ async fn main() -> Result<()> {
color_eyre::install()?; color_eyre::install()?;
let _guards = install_tracing().await?; let _guards = install_tracing().await?;
let _sentry = if let Ok(dsn) = std::env::var("RAVE_SENTRY_DSN") {
let guard = sentry::init(sentry::ClientOptions {
dsn: Some(dsn.parse()?),
release: sentry::release_name!(),
traces_sample_rate: 1.0,
..Default::default()
});
debug!("Sentry initialized");
Some(guard)
} else {
None
};
let route = create_route(); let route = create_route();
let dbc = create_pool().await?; let dbc = create_pool().await?;
@ -89,7 +73,6 @@ fn create_route() -> Box<dyn Endpoint<Output = poem::Response>> {
Route::new() Route::new()
.nest("/", ui::build()) .nest("/", ui::build())
.nest("/rest", rest::build()) .nest("/rest", rest::build())
.with(NewSentryLayer::<Request>::new_from_top().compat())
.with(middleware::CatchPanic::new()) .with(middleware::CatchPanic::new())
.with( .with(
middleware::Compression::new() middleware::Compression::new()
@ -135,7 +118,6 @@ async fn install_tracing() -> Result<[WorkerGuard; 1]> {
.with_writer(non_blocking) .with_writer(non_blocking)
.with_filter(filter), .with_filter(filter),
) )
.with(sentry_tracing::layer())
.try_init()?; .try_init()?;
Ok([guard]) Ok([guard])

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
authentication::Authentication, authentication::Authentication,
subsonic::{Album as AlbumId3, Child, Error, SubsonicResponse}, subsonic::{Album as AlbumId3, Artist as ArtistId3, Child, Error, SubsonicResponse},
utils, utils,
}; };
@ -9,7 +9,7 @@ use entities::prelude::{Album, Artist, Genre, Track};
use poem::web::{Data, Query}; use poem::web::{Data, Query};
use sea_orm::{EntityTrait, ModelTrait}; use sea_orm::{EntityTrait, ModelTrait};
use serde::Deserialize; use serde::Deserialize;
use tracing::{error, instrument}; use tracing::{error, instrument, warn};
#[poem::handler] #[poem::handler]
#[instrument(skip(txn, auth))] #[instrument(skip(txn, auth))]
@ -107,10 +107,30 @@ pub async fn get_album(
} }
}; };
let mut tracks_with_artists = Vec::with_capacity(tracks.len());
for track in tracks {
let find = crate::utils::find_track_artist(track, txn.clone());
tracks_with_artists.push(find);
}
let tracks_with_artists = futures::future::join_all(tracks_with_artists).await;
let mut actual = vec![];
for track in tracks_with_artists {
match track {
Ok((track, artist)) => actual.push((track, artist)),
Err(e) => {
warn!("Error getting artist: {e}");
}
}
}
let album = AlbumId3::new(album, artist, genre); let album = AlbumId3::new(album, artist, genre);
let mut tracks = tracks let mut tracks = actual
.into_iter() .into_iter()
.map(|t| Child::new(&t, &album)) .map(|(track, artist)| Child::new(&track, &album, &ArtistId3::from(artist)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
tracks.sort_by_cached_key(|tr| tr.track.unwrap_or_default()); tracks.sort_by_cached_key(|tr| tr.track.unwrap_or_default());

View file

@ -0,0 +1,62 @@
use crate::{
authentication::Authentication,
subsonic::{Error, SubsonicResponse},
utils,
};
use crate::utils::db::DbTxn;
use entities::prelude::Artist;
use poem::web::{Data, Query};
use sea_orm::EntityTrait;
use serde::Deserialize;
use tracing::{error, instrument};
#[poem::handler]
#[instrument(skip(txn, auth))]
pub async fn get_artist(
Data(txn): Data<&DbTxn>,
auth: Authentication,
Query(params): Query<GetArtistParams>,
) -> SubsonicResponse {
let u = utils::verify_user(txn.clone(), auth).await;
match u {
Ok(_) => {}
Err(e) => return e,
}
let id = params.id.split_once('-');
if id.is_none() {
return SubsonicResponse::new_error(Error::Generic(None));
}
let id = id.expect("none checked").1;
let Ok(id) = id.parse::<i64>() else {
return SubsonicResponse::new_error(Error::Generic(None));
};
let artist = Artist::find_by_id(id).one(&**txn).await.map_err(|e| {
error!(
error = &e as &dyn std::error::Error,
"failed to get artist: {e}"
);
Error::Generic(None)
});
let artist = match artist {
Ok(Some(v)) => v,
Ok(None) => return SubsonicResponse::new_error(Error::RequestedDataWasNotFound(None)),
Err(e) => return SubsonicResponse::new_error(e),
};
let artist = artist.into();
SubsonicResponse::new_artist(artist)
}
#[derive(Debug, Deserialize)]
pub struct GetArtistParams {
id: String,
}

View file

@ -0,0 +1,36 @@
use crate::{
authentication::Authentication,
subsonic::{Artist as ArtistId3, Error, SubsonicResponse},
utils,
};
use crate::utils::db::DbTxn;
use entities::prelude::Artist;
use poem::web::Data;
use sea_orm::EntityTrait;
use tracing::{error, instrument};
#[poem::handler]
#[instrument(skip(txn, auth))]
pub async fn get_artists(Data(txn): Data<&DbTxn>, auth: Authentication) -> SubsonicResponse {
let u = utils::verify_user(txn.clone(), auth).await;
match u {
Ok(_) => {}
Err(e) => return e,
}
let artists = Artist::find().all(&**txn).await;
let artists = match artists {
Ok(artists) => artists,
Err(e) => {
error!("Failed to get artists: {}", e);
return SubsonicResponse::new_error(Error::RequestedDataWasNotFound(None));
}
};
let artists = artists.into_iter().map(ArtistId3::from).collect();
SubsonicResponse::new_artists(artists)
}

View file

@ -20,6 +20,10 @@ mod get_scan_status;
mod search3; mod search3;
// rest/getCoverArt // rest/getCoverArt
mod get_cover_art; mod get_cover_art;
// rest/getArtists
mod get_artists;
// rest/getArtist
mod get_artist;
pub fn build() -> Box<dyn Endpoint<Output = poem::Response>> { pub fn build() -> Box<dyn Endpoint<Output = poem::Response>> {
Route::new() Route::new()
@ -34,5 +38,7 @@ pub fn build() -> Box<dyn Endpoint<Output = poem::Response>> {
.at("/getScanStatus", get_scan_status::get_scan_status) .at("/getScanStatus", get_scan_status::get_scan_status)
.at("/search3", search3::search3) .at("/search3", search3::search3)
.at("/getCoverArt", get_cover_art::get_cover_art) .at("/getCoverArt", get_cover_art::get_cover_art)
.at("/getArtists", get_artists::get_artists)
.at("/getArtist", get_artist::get_artist)
.boxed() .boxed()
} }

View file

@ -58,24 +58,22 @@ pub async fn search3(
} }
async fn search_artists(txn: DbTxn, params: &Search3Params) -> Result<Vec<ArtistId3>, Report> { async fn search_artists(txn: DbTxn, params: &Search3Params) -> Result<Vec<ArtistId3>, Report> {
if params.query.is_empty() { let artists = if params.query.is_empty() {
let artists = Artist::find() Artist::find()
.limit(params.artist_count) .limit(params.artist_count)
.offset(params.artist_offset) .offset(params.artist_offset)
.all(&*txn) .all(&*txn)
.await?; .await?
Ok(artists.into_iter().map(Into::into).collect())
} else { } else {
let artists = Artist::find() Artist::find()
.filter(artist::Column::Name.contains(&params.query)) .filter(artist::Column::Name.contains(&params.query))
.limit(params.artist_count) .limit(params.artist_count)
.offset(params.artist_offset) .offset(params.artist_offset)
.all(&*txn) .all(&*txn)
.await?; .await?
};
Ok(artists.into_iter().map(Into::into).collect()) Ok(artists.into_iter().map(Into::into).collect())
}
} }
async fn search_albums(txn: DbTxn, params: &Search3Params) -> Result<Vec<AlbumId3>, Report> { async fn search_albums(txn: DbTxn, params: &Search3Params) -> Result<Vec<AlbumId3>, Report> {
@ -106,36 +104,73 @@ async fn search_albums(txn: DbTxn, params: &Search3Params) -> Result<Vec<AlbumId
} }
async fn search_songs(txn: DbTxn, params: &Search3Params) -> Result<Vec<ChildId3>, Report> { async fn search_songs(txn: DbTxn, params: &Search3Params) -> Result<Vec<ChildId3>, Report> {
if params.query.is_empty() { let tracks_with_albums = if params.query.is_empty() {
let songs = Track::find() Track::find()
.limit(params.song_count) .limit(params.song_count)
.offset(params.song_offset) .offset(params.song_offset)
.find_also_related(Album) .find_also_related(Album)
.all(&*txn) .all(&*txn)
.await?; .await?
Ok(songs
.into_iter()
.filter_map(|(track, album)| {
album.map(|album| ChildId3::new(&track, &AlbumId3::new(album, None, None)))
})
.collect())
} else { } else {
let songs = Track::find() Track::find()
.filter(track::Column::Title.contains(&params.query)) .filter(track::Column::Title.contains(&params.query))
.limit(params.song_count) .limit(params.song_count)
.offset(params.song_offset) .offset(params.song_offset)
.find_also_related(Album) .find_also_related(Album)
.all(&*txn) .all(&*txn)
.await?; .await?
};
Ok(songs let (tracks, albums): (Vec<_>, Vec<_>) = tracks_with_albums.into_iter().unzip();
let albums_with_artists = futures::future::join_all(
albums
.into_iter() .into_iter()
.filter_map(|(track, album)| { .flatten()
album.map(|album| ChildId3::new(&track, &AlbumId3::new(album, None, None))) .map(|album| utils::find_album_artist(album, txn.clone())),
)
.await;
let mut actual_albums = vec![];
for album in albums_with_artists {
match album {
Ok((album, artist)) => actual_albums.push((album, artist)),
Err(e) => {
error!("Error getting artist: {e}");
}
}
}
let tracks_with_artists = futures::future::join_all(
tracks
.into_iter()
.map(|track| utils::find_track_artist(track, txn.clone())),
)
.await;
let mut actual_tracks = vec![];
for track in tracks_with_artists {
match track {
Ok((track, artist)) => actual_tracks.push((track, artist)),
Err(e) => {
error!("Error getting artist: {e}");
}
}
}
Ok(actual_tracks
.into_iter()
.zip(actual_albums)
.map(|((track, artist), (album, album_artist))| {
ChildId3::new(
&track,
&AlbumId3::new(album, Some(album_artist), None),
&ArtistId3::from(artist),
)
}) })
.collect()) .collect())
}
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]

View file

@ -35,9 +35,9 @@ pub async fn handle(
FlacTag::from(tag) FlacTag::from(tag)
}; };
let artist = find_artist(tx, &tag).await?; let album_artist = find_album_artist(tx, &tag).await?;
let album = find_album(tx, artist.as_ref().map(|c| c.id), &tag, state.clone()).await?; let album = find_album(tx, album_artist.as_ref().map(|c| c.id), &tag, state.clone()).await?;
if let Some(track) = Track::find() if let Some(track) = Track::find()
.filter(track::Column::Path.eq(path.to_string_lossy())) .filter(track::Column::Path.eq(path.to_string_lossy()))
@ -53,9 +53,11 @@ pub async fn handle(
let title = tag.title().unwrap_or(&stem).to_string(); let title = tag.title().unwrap_or(&stem).to_string();
let title = title.replace("\0 ", "").replace('\0', ""); // fuck NULLs. let title = title.replace("\0 ", "").replace('\0', ""); // fuck NULLs.
let track_artist = find_track_artist(tx, &tag).await?;
am.title = Set(title); am.title = Set(title);
am.album_id = Set(Some(album.id)); am.album_id = Set(Some(album.id));
am.artist_id = Set(artist.as_ref().map(|c| c.id)); am.artist_id = Set(track_artist.as_ref().map(|c| c.id));
am.content_type = Set("audio/flac".to_string()); am.content_type = Set("audio/flac".to_string());
am.suffix = Set("flac".to_string()); am.suffix = Set("flac".to_string());
am.path = Set(path.to_string_lossy().to_string()); am.path = Set(path.to_string_lossy().to_string());
@ -208,35 +210,30 @@ async fn find_album(
} }
#[instrument(skip(tx, tag))] #[instrument(skip(tx, tag))]
async fn find_artist( async fn find_album_artist(
tx: &DatabaseTransaction, tx: &DatabaseTransaction,
tag: &FlacTag, tag: &FlacTag,
) -> Result<Option<artist::Model>, Report> { ) -> Result<Option<artist::Model>, Report> {
let artist_to_search = match (tag.album_artist(), tag.artists()) { let artist_to_search = crate::utils::format_flac_artist_for_album(tag);
(Some(tag_artist), None) => Some(tag_artist.to_string()),
(None, Some(tag_artists)) => {
let tag_artists = tag_artists
.iter()
.flat_map(|artist| artist.split('\0'))
.map(str::trim)
.collect::<Vec<_>>();
Some(tag_artists.join(", "))
}
(Some(tag_artist), Some(tag_artists)) => {
let mut artists = tag_artists.clone();
artists.push(tag_artist);
let artists = artists find_artist(tx, artist_to_search).await
.iter() }
.flat_map(|artist| artist.split('\0'))
.map(str::trim)
.collect::<Vec<_>>();
Some(artists.join(", ")) #[instrument(skip(tx, tag))]
} async fn find_track_artist(
_ => None, tx: &DatabaseTransaction,
}; tag: &FlacTag,
) -> Result<Option<artist::Model>, Report> {
let artist_to_search = crate::utils::format_flac_artist_for_track(tag);
find_artist(tx, artist_to_search).await
}
#[instrument(skip(tx))]
async fn find_artist(
tx: &DatabaseTransaction,
artist_to_search: Option<String>,
) -> Result<Option<artist::Model>, Report> {
match &artist_to_search { match &artist_to_search {
Some(artist_to_search) => { Some(artist_to_search) => {
let artist_to_search = artist_to_search.trim(); let artist_to_search = artist_to_search.trim();

View file

@ -35,9 +35,9 @@ pub async fn handle(
audiotags::Id3v2Tag::from(tag) audiotags::Id3v2Tag::from(tag)
}; };
let artist = find_artist(tx, &tag).await?; let album_artist = find_album_artist(tx, &tag).await?;
let album = find_album(tx, artist.as_ref().map(|c| c.id), &tag, state.clone()).await?; let album = find_album(tx, album_artist.as_ref().map(|c| c.id), &tag, state.clone()).await?;
if let Some(track) = Track::find() if let Some(track) = Track::find()
.filter(track::Column::Path.eq(path.to_string_lossy())) .filter(track::Column::Path.eq(path.to_string_lossy()))
@ -53,9 +53,11 @@ pub async fn handle(
let title = tag.title().unwrap_or(&stem).to_string(); let title = tag.title().unwrap_or(&stem).to_string();
let title = title.replace("\0 ", "").replace('\0', ""); // fuck NULLs. let title = title.replace("\0 ", "").replace('\0', ""); // fuck NULLs.
let track_artist = find_track_artist(tx, &tag).await?;
am.title = Set(title); am.title = Set(title);
am.album_id = Set(Some(album.id)); am.album_id = Set(Some(album.id));
am.artist_id = Set(artist.as_ref().map(|c| c.id)); am.artist_id = Set(track_artist.as_ref().map(|c| c.id));
am.content_type = Set("audio/mpeg".to_string()); am.content_type = Set("audio/mpeg".to_string());
am.suffix = Set("mp3".to_string()); am.suffix = Set("mp3".to_string());
am.path = Set(path.to_string_lossy().to_string()); am.path = Set(path.to_string_lossy().to_string());
@ -208,35 +210,30 @@ async fn find_album(
} }
#[instrument(skip(tx, tag))] #[instrument(skip(tx, tag))]
async fn find_artist( async fn find_album_artist(
tx: &DatabaseTransaction, tx: &DatabaseTransaction,
tag: &Id3v2Tag, tag: &Id3v2Tag,
) -> Result<Option<artist::Model>, Report> { ) -> Result<Option<artist::Model>, Report> {
let artist_to_search = match (tag.album_artist(), tag.artists()) { let artist_to_search = crate::utils::format_id3_artist_for_album(tag);
(Some(tag_artist), None) => Some(tag_artist.to_string()),
(None, Some(tag_artists)) => {
let tag_artists = tag_artists
.iter()
.flat_map(|artist| artist.split('\0'))
.map(str::trim)
.collect::<Vec<_>>();
Some(tag_artists.join(", "))
}
(Some(tag_artist), Some(tag_artists)) => {
let mut artists = tag_artists.clone();
artists.push(tag_artist);
let artists = artists find_artist(tx, artist_to_search).await
.iter() }
.flat_map(|artist| artist.split('\0'))
.map(str::trim)
.collect::<Vec<_>>();
Some(artists.join(", ")) #[instrument(skip(tx, tag))]
} async fn find_track_artist(
_ => None, tx: &DatabaseTransaction,
}; tag: &Id3v2Tag,
) -> Result<Option<artist::Model>, Report> {
let artist_to_search = crate::utils::format_id3_artist_for_track(tag);
find_artist(tx, artist_to_search).await
}
#[instrument(skip(tx))]
async fn find_artist(
tx: &DatabaseTransaction,
artist_to_search: Option<String>,
) -> Result<Option<artist::Model>, Report> {
match &artist_to_search { match &artist_to_search {
Some(artist_to_search) => { Some(artist_to_search) => {
let artist_to_search = artist_to_search.trim(); let artist_to_search = artist_to_search.trim();

View file

@ -69,6 +69,10 @@ impl SubsonicResponse {
}) })
} }
pub fn new_artists(artists: Vec<Artist>) -> Self {
Self::new(SubResponseType::Artists { artists })
}
pub fn new_empty() -> Self { pub fn new_empty() -> Self {
Self::new(SubResponseType::Empty) Self::new(SubResponseType::Empty)
} }
@ -83,12 +87,13 @@ impl SubsonicResponse {
} }
pub fn new_scan_status(scanning: bool, count: u64) -> Self { pub fn new_scan_status(scanning: bool, count: u64) -> Self {
Self { Self::new(SubResponseType::ScanStatus { scanning, count })
xmlns: "http://subsonic.org/restapi".to_string(),
status: ResponseStatus::Ok,
version: VersionTriple(1, 16, 1),
value: Box::new(SubResponseType::ScanStatus { scanning, count }),
} }
pub fn new_artist(artist: Artist) -> Self {
Self::new(SubResponseType::Artist {
artist: Box::new(artist),
})
} }
} }
@ -139,6 +144,16 @@ pub enum SubResponseType {
#[serde(rename = "song")] #[serde(rename = "song")]
songs: Vec<Child>, songs: Vec<Child>,
}, },
#[serde(rename = "artists")]
Artists {
#[serde(rename = "artist")]
artists: Vec<Artist>,
},
#[serde(rename = "artist")]
Artist {
#[serde(flatten)]
artist: Box<Artist>,
},
Empty, Empty,
} }

View file

@ -2,7 +2,7 @@ use entities::track;
use serde::Serialize; use serde::Serialize;
use time::format_description::well_known::Iso8601; use time::format_description::well_known::Iso8601;
use crate::subsonic::Album; use crate::subsonic::{Album, Artist};
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct Child { pub struct Child {
@ -44,6 +44,8 @@ pub struct Child {
pub album_id: Option<String>, pub album_id: Option<String>,
#[serde(rename = "@artistId", skip_serializing_if = "Option::is_none")] #[serde(rename = "@artistId", skip_serializing_if = "Option::is_none")]
pub artist_id: Option<String>, pub artist_id: Option<String>,
#[serde(rename = "@artist")]
pub artist: String,
#[serde(rename = "@type")] #[serde(rename = "@type")]
pub child_type: String, pub child_type: String,
#[serde(rename = "@isVideo")] #[serde(rename = "@isVideo")]
@ -53,7 +55,7 @@ pub struct Child {
impl Child { impl Child {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
#[must_use] #[must_use]
pub fn new(track: &track::Model, album: &Album) -> Self { pub fn new(track: &track::Model, album: &Album, artist: &Artist) -> Self {
Self { Self {
id: format!("tr-{}", track.id), id: format!("tr-{}", track.id),
is_dir: false, is_dir: false,
@ -78,7 +80,8 @@ impl Child {
.format(&Iso8601::DEFAULT) .format(&Iso8601::DEFAULT)
.expect("Failed to format date"), .expect("Failed to format date"),
album_id: Some(format!("al-{}", album.id)), album_id: Some(format!("al-{}", album.id)),
artist_id: album.artist_id.clone(), artist_id: track.artist_id.map(|v| format!("ar-{v}",)),
artist: artist.name.clone(),
child_type: "music".to_string(), child_type: "music".to_string(),
is_video: false, is_video: false,
} }

View file

@ -1,6 +1,11 @@
use entities::{prelude::User, user}; use audiotags::{AudioTagEdit, FlacTag, Id3v2Tag};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use entities::{
use tracing::error; album, artist,
prelude::{Artist, User},
track, user,
};
use sea_orm::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter};
use tracing::{debug, error};
use crate::{ use crate::{
authentication::Authentication, authentication::Authentication,
@ -47,3 +52,142 @@ pub async fn verify_user(
} }
} }
} }
pub async fn find_track_artist(
track: track::Model,
txn: DbTxn,
) -> Result<(track::Model, artist::Model), Error> {
let artist = track.find_related(Artist).one(&*txn).await;
match artist {
Ok(Some(artist)) => Ok((track, artist)),
Ok(None) => Err(Error::RequestedDataWasNotFound(None)),
Err(e) => {
error!(
error = &e as &dyn std::error::Error,
"Error getting artist: {e}"
);
Err(Error::Generic(None))
}
}
}
pub async fn find_album_artist(
album: album::Model,
txn: DbTxn,
) -> Result<(album::Model, artist::Model), Error> {
let artist = album.find_related(Artist).one(&*txn).await;
match artist {
Ok(Some(artist)) => Ok((album, artist)),
Ok(None) => Err(Error::RequestedDataWasNotFound(None)),
Err(e) => {
error!(
error = &e as &dyn std::error::Error,
"Error getting artist: {e}"
);
Err(Error::Generic(None))
}
}
}
pub fn format_id3_artist_for_album(tag: &Id3v2Tag) -> Option<String> {
let album_artist = tag.album_artist();
let album_artists = tag.album_artists();
if (album_artist, &album_artists) == (None, &None) {
format_artist(tag.artist(), tag.artists(), album_artist, album_artists)
} else {
format_artist(None, None, album_artist, album_artists)
}
}
pub fn format_id3_artist_for_track(tag: &Id3v2Tag) -> Option<String> {
let artist = tag.artist();
let artists = tag.artists();
let album_artist = tag.album_artist();
let album_artists = tag.album_artists();
format_artist(artist, artists, album_artist, album_artists)
}
pub fn format_flac_artist_for_album(tag: &FlacTag) -> Option<String> {
let album_artist = tag.album_artist();
let album_artists = tag.album_artists();
if (album_artist, &album_artists) == (None, &None) {
format_artist(tag.artist(), tag.artists(), album_artist, album_artists)
} else {
format_artist(None, None, album_artist, album_artists)
}
}
pub fn format_flac_artist_for_track(tag: &FlacTag) -> Option<String> {
let artist = tag.artist();
let artists = tag.artists();
let album_artist = tag.album_artist();
let album_artists = tag.album_artists();
format_artist(artist, artists, album_artist, album_artists)
}
fn format_artist(
artist: Option<&str>,
artists: Option<Vec<&str>>,
album_artist: Option<&str>,
album_artists: Option<Vec<&str>>,
) -> Option<String> {
let mut actual_artists = vec![];
if let Some(artist) = artist {
actual_artists.push((1, artist)); // Prioritize track artist over album artist
}
if let Some(artists) = artists {
actual_artists.extend(artists.into_iter().map(|v| (3, v))); // Prioritize track artists over album artists
}
if let Some(album_artist) = album_artist {
actual_artists.push((2, album_artist)); // Prioritize album artist over album artists
}
if let Some(album_artists) = album_artists {
actual_artists.extend(album_artists.into_iter().map(|v| (4, v))); // Prioritize album artists over track artists
}
let mut actual_artists = actual_artists
.into_iter()
.flat_map(|(prio, v)| {
if v.contains(SEPARATORS) {
v.split(SEPARATORS)
.map(|v| (prio, v))
.collect::<Vec<_>>()
.into_iter()
} else {
vec![(prio, v)].into_iter()
}
})
.map(|(prio, v)| (prio, v.trim()))
.filter(|(_, v)| !v.is_empty())
.collect::<Vec<_>>();
actual_artists.sort_unstable_by_key(|v| v.0); // Sort by priority first
actual_artists.sort_by_key(|v| v.1); // Then by name within each priority, hopefully
let mut actual_artists = actual_artists
.into_iter()
.map(|(_, v)| v)
.collect::<Vec<_>>();
actual_artists.dedup();
debug!("Actual artists: {:?}", actual_artists);
if actual_artists.is_empty() {
None
} else {
Some(actual_artists.join(", "))
}
}
const SEPARATORS: &[char] = &[';', '/', '\\', ',', '\0', '&'];