diff options
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 53 |
1 files changed, 16 insertions, 37 deletions
diff --git a/src/config.rs b/src/config.rs index e635f4a..3c11bc8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,7 +6,8 @@ use std::pin::Pin; use std::time::*; use super::cache::AsyncCache; -use super::deserialize::{GetRecentTracks, GetUserInfo, Track, User}; +use super::deserialize::{GetRecentTracks, GetUserInfo, GetTrackInfo, Track, TrackStub, User}; +use super::font::{font_cache, FontCache}; use reqwest::{Client, StatusCode}; use dotenv::var; @@ -18,13 +19,9 @@ type CacheFuture<Output> = Pin<Box<(dyn Future<Output = Result<Output, (StatusCo type CacheGetter<Output> = fn(&String) -> CacheFuture<Output>; type Cache<Output> = Arc<RwLock<AsyncCache<String, Output, CacheGetter<Output>>>>; -type FontFuture = CacheFuture<Arc<str>>; -type FontGetter = CacheGetter<Arc<str>>; -type FontCache = Cache<Arc<str>>; - -type UserFuture = CacheFuture<Arc<(User, Track)>>; -type UserGetter = CacheGetter<Arc<(User, Track)>>; -type UserCache = Cache<Arc<(User, Track)>>; +type UserFuture = CacheFuture<Arc<(User, Track, TrackStub)>>; +type UserGetter = CacheGetter<Arc<(User, Track, TrackStub)>>; +type UserCache = Cache<Arc<(User, Track, TrackStub)>>; static INTERNAL_THEMES: &[(&str, &str)] = &[("plain", include_str!("themes/plain.hbs"))]; @@ -49,40 +46,22 @@ fn user_getter(username: &String) -> UserFuture { if tracksreq.status() == StatusCode::NOT_FOUND { return Err((StatusCode::NOT_FOUND, "User does not exist!")); } if tracksreq.status() == StatusCode::FORBIDDEN { return Err((StatusCode::FORBIDDEN, "You need to unprivate your song history!")); } - let tracksinfo = tracksreq.json::<GetRecentTracks>().await + let trackstub = tracksreq.json::<GetRecentTracks>().await .map_err(|e| {log::error!("Couldn't parse user.getRecentTracks for `{username}`: {e}"); (StatusCode::INTERNAL_SERVER_ERROR, "Couldn't parse user.getRecentTracks!")})? .recenttracks.track.into_iter().next().ok_or((StatusCode::UNPROCESSABLE_ENTITY, "You need to listen to some songs first!"))?; - Ok(Arc::new((userinfo, tracksinfo))) - }) -} - -fn font_getter(fontname: &String) -> FontFuture { - let fontname = urlencoding::encode(fontname.as_ref()).to_string(); - Box::pin(async move { - let Some(google_api_key) = STATE.google_api_key.clone() - else { - unreachable!(); - }; - - let fontreq = STATE.http.get(format!("https://www.googleapis.com/webfonts/v1/webfonts?key={}&family={fontname}", google_api_key)) + let trackreq = STATE.http.get(format!("https://ws.audioscrobbler.com/2.0/?method=track.getInfo&format=json&username={username}&api_key={}&track={}&artist={}", STATE.lastfm_api_key, trackstub.name, trackstub.artist.name)) .send().await - .map_err(|e| {log::error!("Failed to get info for font `{fontname}`: {e}"); (StatusCode::SERVICE_UNAVAILABLE, "Couldn't connect to Google Fonts!")})?; - if fontreq.status() == StatusCode::NOT_FOUND { return Err((StatusCode::NOT_FOUND, "Font does not exist!")); } - if fontreq.status() == StatusCode::FORBIDDEN { - log::error!("Invalid Google API key in config!"); - return Err((StatusCode::SERVICE_UNAVAILABLE, "This instance is not configured to support Google Fonts properly, please use a different font.")); - } + .map_err(|e| {log::error!("Failed to get tracks for user `{username}`: {e}"); (StatusCode::SERVICE_UNAVAILABLE, "Couldn't connect to last.fm!")})?; + if trackreq.status() == StatusCode::NOT_FOUND { return Err((StatusCode::NOT_FOUND, "Track does not exist!")); } - let cssreq = STATE.http.get(format!("https://fonts.googleapis.com/css2?family={fontname}")) - .send().await - .map_err(|e| {log::error!("Failed to get CSS for font `{fontname}`: {e}"); (StatusCode::SERVICE_UNAVAILABLE, "Couldn't download font CSS!")})?; + let trackinfo = trackreq.json::<GetTrackInfo>().await + .map_err(|e| {log::error!("Couldn't parse track.getInfo for `{}` by `{}` on behalf of {username}: {e}", trackstub.name, trackstub.artist.name); (StatusCode::INTERNAL_SERVER_ERROR, "Couldn't parse track.getInfo!")})?.track; - Ok(cssreq.text().await.unwrap().into()) + Ok(Arc::new((userinfo, trackinfo, trackstub))) }) } - #[derive(Debug)] enum Whitelist { Exclusive{cache: UserCache, whitelist: BTreeSet<String>}, @@ -95,11 +74,11 @@ pub struct State { default_theme: Arc<str>, send_refresh_header: bool, - http: Client, + pub(crate) http: Client, handlebars: Handlebars<'static>, - google_api_key: Option<Arc<str>>, + pub(crate) google_api_key: Option<Arc<str>>, google_fonts_cache: FontCache, whitelist: Whitelist, @@ -146,7 +125,7 @@ impl State { }, google_api_key: var("LFME_GOOGLE_API_KEY").map(Into::into).ok(), - google_fonts_cache: Arc::new(RwLock::new(AsyncCache::new(Duration::from_secs(86400), font_getter as FontGetter))), + google_fonts_cache: font_cache(), whitelist: { let load_whitelist = || -> Option<BTreeSet<String>> { @@ -178,7 +157,7 @@ impl State { self.google_fonts_cache.write().await.get_owned(font).await } pub fn has_google_api_key(&self) -> bool { self.google_api_key.is_some() } - pub async fn get_userinfo(&self, user: &String) -> (Result<Arc<(User, Track)>, (StatusCode, &'static str)>, Duration) { + pub async fn get_userinfo(&self, user: &String) -> (Result<Arc<(User, Track, TrackStub)>, (StatusCode, &'static str)>, Duration) { match &self.whitelist { Whitelist::Open{default_cache, whitelist_cache, whitelist} => { if whitelist.contains(user) { |