Skip to main content

utils/
subsonic_image.rs

1pub fn parse_subsonic_path(path_str: &str) -> Option<(&str, Option<&str>)> {
2    let parts: Vec<&str> = path_str.split(':').collect();
3    if parts.len() >= 2 {
4        let id = parts[1].trim();
5        if id.is_empty() {
6            return None;
7        }
8        let tag = if parts.len() >= 3 {
9            Some(parts[2])
10        } else {
11            None
12        };
13        Some((id, tag))
14    } else {
15        None
16    }
17}
18
19pub fn subsonic_image_url_from_path(
20    path_str: &str,
21    server_url: &str,
22    access_token: Option<&str>,
23    max_width: u32,
24    quality: u32,
25) -> Option<String> {
26    let (id, tag) = parse_subsonic_path(path_str)?;
27    if tag == Some("none") {
28        return None;
29    }
30
31    if let Some(tag) = tag
32        && let Some(url) = decode_embedded_cover_url(tag)
33    {
34        return Some(url);
35    }
36
37    let mut url = reqwest::Url::parse(&format!(
38        "{}/rest/getCoverArt.view",
39        server_url.trim_end_matches('/')
40    ))
41    .unwrap_or_else(|_| reqwest::Url::parse("http://127.0.0.1/").unwrap());
42
43    {
44        let mut pairs = url.query_pairs_mut();
45        pairs.append_pair("id", id);
46        pairs.append_pair("size", &max_width.to_string());
47        pairs.append_pair("quality", &quality.to_string());
48        if let Some(token) = access_token {
49            pairs.append_pair("access_token", token);
50        }
51    }
52
53    Some(url.to_string())
54}
55
56fn decode_embedded_cover_url(tag: &str) -> Option<String> {
57    let hex = tag.strip_prefix("urlhex_")?;
58    if hex.len() % 2 != 0 {
59        return None;
60    }
61
62    let mut bytes = Vec::with_capacity(hex.len() / 2);
63    let chars: Vec<char> = hex.chars().collect();
64    let mut i = 0;
65    while i < chars.len() {
66        let hi = chars[i].to_digit(16)?;
67        let lo = chars[i + 1].to_digit(16)?;
68        bytes.push(((hi << 4) | lo) as u8);
69        i += 2;
70    }
71
72    String::from_utf8(bytes).ok()
73}