use std::path::{Path, PathBuf};
use config::{AppConfig, MusicService};
use reader::{ArtistImageRef, Track};
use utils::CoverUrl;
pub fn from_path(
config: &AppConfig,
cover_path: Option<&Path>,
max_width: u32,
) -> Option<CoverUrl> {
let path = cover_path?;
if path.is_absolute() {
return utils::format_artwork_thumb_url(Some(&path.to_path_buf()), max_width);
}
let (server_url, token) = config
.server
.as_ref()
.map(|s| (s.url.as_str(), s.access_token.as_deref()))
.unwrap_or(("", None));
utils::map_cover_url(utils::jellyfin_image::jellyfin_image_url_from_path(
&path.to_string_lossy(),
server_url,
token,
max_width,
80,
))
}
pub fn artist(
config: &AppConfig,
override_path: Option<&Path>,
photo: Option<&ArtistImageRef>,
fetched_url: Option<&str>,
album_cover_path: Option<&Path>,
use_photo: bool,
max_width: u32,
) -> Option<CoverUrl> {
let override_owned = override_path.map(Path::to_path_buf);
if let Some(cover) = utils::format_artwork_url(override_owned.as_ref()) {
return Some(cover);
}
if use_photo {
let resolved = match photo {
Some(ArtistImageRef::Remote(url)) => Some(utils::cover_url_from_string(url.clone())),
other => fetched_url
.map(|u| utils::cover_url_from_string(u.to_string()))
.or_else(|| match other {
Some(ArtistImageRef::Local(path)) => utils::format_artwork_url(Some(path)),
_ => None,
}),
};
if resolved.is_some() {
return resolved;
}
}
from_path(config, album_cover_path, max_width)
}
pub fn track(config: &AppConfig, track: &Track, max_width: u32) -> Option<CoverUrl> {
let Some(service) = track.id.service() else {
let owned = track.cover.as_deref().map(PathBuf::from);
return utils::format_artwork_thumb_url(owned.as_ref(), max_width);
};
let server = config.server.as_ref()?;
let url = match service {
MusicService::Jellyfin => utils::jellyfin_image::resolve_track_cover(
track.cover.as_deref(),
&track.id.key(),
&track.album_id,
&server.url,
server.access_token.as_deref(),
max_width,
80,
),
MusicService::Subsonic | MusicService::Custom => {
let subsonic_path = match track.cover.as_deref() {
Some(c) => format!("{}:{}", track.id.uid(), c),
None => track.id.uid(),
};
utils::subsonic_image::subsonic_image_url_from_path(
&subsonic_path,
&server.url,
server.access_token.as_deref(),
max_width,
80,
)
}
MusicService::YtMusic => utils::jellyfin_image::resolve_track_cover(
track.cover.as_deref(),
&track.id.key(),
&track.album_id,
"",
None,
max_width,
80,
),
MusicService::SoundCloud => track.cover.clone(),
};
utils::map_cover_url(url)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
fn local_active() -> AppConfig {
AppConfig {
active_source: config::Source::Local,
server: None,
..Default::default()
}
}
#[test]
fn from_path_resolves_a_remote_ref_while_local_is_active() {
let url = "https://example.com/cover.jpg";
let reff = format!("ytmusic:_:{}", utils::jellyfin_image::encode_cover_url(url));
let got = from_path(&local_active(), Some(Path::new(&reff)), 200).expect("resolves");
assert_eq!(
&*got, url,
"self-contained remote ref → its URL, not artwork://"
);
}
}