cover art api

This commit is contained in:
Erica Z 2024-11-07 10:01:28 +01:00
parent e52adda2ed
commit 2b9b6ee6c7
3 changed files with 46 additions and 55 deletions

View file

@ -27,8 +27,6 @@ mod imp {
#[property(get, set)] #[property(get, set)]
track: Cell<i64>, track: Cell<i64>,
#[property(get, set)]
cover_art_url: RefCell<String>,
#[property(get, set)] #[property(get, set)]
stream_url: RefCell<String>, stream_url: RefCell<String>,
@ -83,8 +81,7 @@ impl Song {
.property("album", &song.album) .property("album", &song.album)
.property("genre", &song.genre) .property("genre", &song.genre)
.property("duration", song.duration as i64) .property("duration", song.duration as i64)
//.property("track", song.track) .property("track", song.track.map(i64::from).unwrap_or(-1))
.property("cover-art-url", api.cover_art_url(&song.id, 0).as_str())
.property("stream-url", api.stream_url(&song.id).as_str()) .property("stream-url", api.stream_url(&song.id).as_str())
.build(); .build();
@ -96,7 +93,7 @@ impl Song {
.thumbnail_loading .thumbnail_loading
.replace(Some(glib::spawn_future_local(async move { .replace(Some(glib::spawn_future_local(async move {
let bytes = api let bytes = api
.cover_art(&id, 50) // TODO: constify thumbnail size, maybe take dpi into account etc .cover_art(&id, Some(50)) // TODO: WidgetExt::scale_factor
.await .await
.unwrap(); .unwrap();
let song = match song_weak.upgrade() { let song = match song_weak.upgrade() {

View file

@ -153,10 +153,51 @@ impl Client {
} }
} }
async fn send_bytes(&self, request: reqwest::RequestBuilder) -> Result<Bytes, Error> { fn url(&self, path: &[&str], query: &[(&str, &str)]) -> url::Url {
let mut url = self.base_url.clone();
url.path_segments_mut()
// literally can't fail
.unwrap_or_else(|_| unsafe { std::hint::unreachable_unchecked() })
.extend(path);
url.query_pairs_mut().extend_pairs(query);
url
}
async fn get<T: serde::de::DeserializeOwned + Send + 'static>(
&self,
path: &[&str],
query: &[(&str, &str)],
) -> Result<T, Error> {
self.send(self.client.get(self.url(path, query))).await
}
pub async fn ping(&self) -> Result<(), Error> {
self.get(&["rest", "ping"], &[]).await
}
pub async fn get_random_songs(&self, size: u32) -> Result<Vec<schema::Child>, Error> {
self.get::<schema::RandomSongsOuter>(
&["rest", "getRandomSongs"],
&[("size", &size.to_string())],
)
.await
.map(|response| response.random_songs.song)
}
pub fn cover_art_url(&self, id: &str, size: Option<u32>) -> url::Url {
match size {
None => self.url(&["rest", "getCoverArt"], &[("id", id)]),
Some(size) => self.url(
&["rest", "getCoverArt"],
&[("id", id), ("size", &size.to_string())],
),
}
}
pub async fn cover_art(&self, id: &str, size: Option<u32>) -> Result<Bytes, Error> {
let (sender, receiver) = async_channel::bounded(1); let (sender, receiver) = async_channel::bounded(1);
let future = request.send(); let future = self.client.get(self.cover_art_url(id, size)).send();
runtime().spawn(async move { runtime().spawn(async move {
async fn perform( async fn perform(
response: Result<reqwest::Response, reqwest::Error>, response: Result<reqwest::Response, reqwest::Error>,
@ -197,53 +238,6 @@ impl Client {
.expect("could not receive cover art bytes from tokio") .expect("could not receive cover art bytes from tokio")
} }
fn url(&self, path: &[&str], query: &[(&str, &str)]) -> url::Url {
let mut url = self.base_url.clone();
url.path_segments_mut()
// literally can't fail
.unwrap_or_else(|_| unsafe { std::hint::unreachable_unchecked() })
.extend(path);
url.query_pairs_mut().extend_pairs(query);
url
}
async fn get<T: serde::de::DeserializeOwned + Send + 'static>(
&self,
path: &[&str],
query: &[(&str, &str)],
) -> Result<T, Error> {
self.send(self.client.get(self.url(path, query))).await
}
pub async fn ping(&self) -> Result<(), Error> {
self.get(&["rest", "ping"], &[]).await
}
pub async fn get_random_songs(&self, size: u32) -> Result<Vec<schema::Child>, Error> {
self.get::<schema::RandomSongsOuter>(
&["rest", "getRandomSongs"],
&[("size", &size.to_string())],
)
.await
.map(|response| response.random_songs.song)
}
pub fn cover_art_url(&self, id: &str, size: u32) -> url::Url {
if size == 0 {
self.url(&["rest", "getCoverArt"], &[("id", id)])
} else {
self.url(
&["rest", "getCoverArt"],
&[("id", id), ("size", &size.to_string())],
)
}
}
pub async fn cover_art(&self, id: &str, size: u32) -> Result<Bytes, Error> {
self.send_bytes(self.client.get(self.cover_art_url(id, size)))
.await
}
pub fn stream_url(&self, id: &str) -> url::Url { pub fn stream_url(&self, id: &str) -> url::Url {
self.url(&["rest", "stream"], &[("id", id)]) self.url(&["rest", "stream"], &[("id", id)])
} }

View file

@ -482,7 +482,7 @@ mod imp {
.replace(Some(glib::spawn_future_local(async move { .replace(Some(glib::spawn_future_local(async move {
let api = window.imp().api.borrow().as_ref().unwrap().clone(); let api = window.imp().api.borrow().as_ref().unwrap().clone();
let bytes = api let bytes = api
.cover_art(&song_id, 0) // 0: full size .cover_art(&song_id, None) // full size
.await .await
.expect("could not load cover art for song {song_id}"); .expect("could not load cover art for song {song_id}");