From 41a5fa81b5c12feb8aab0ad82d42c135e93065f7 Mon Sep 17 00:00:00 2001 From: alyx Date: Wed, 22 Nov 2023 19:49:27 -0500 Subject: Add custom font support. --- README.md | 20 ++++++++++++++++++-- src/config.rs | 2 +- src/ctx.rs | 21 +++++++++++++++++---- src/font.rs | 10 ++++++++++ src/lib.rs | 1 + src/main.rs | 6 +++++- src/themes/plain.hbs | 11 +++++++++-- 7 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 src/font.rs diff --git a/README.md b/README.md index 739b94a..4d5ae8f 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,15 @@ Themes should have, roughly, the structure below: - + {{#if error}}

{{error}}

{{else}} @@ -225,7 +233,15 @@ If there was an error, the object will just be `{ error: String }`, otherwise it // the most recently played track. now_playing: Boolean, }, - + + // Custom font info. + font: { + // Set if the theme should replace the custom font with something. + name: String? + // Will contain CSS which includes a custom font as 'included_font'. + css: String? + } + // A set of extraneous query parameters. // // This should be considered UNTRUSTED, as the requester has full diff --git a/src/config.rs b/src/config.rs index 3b36ad2..4c5d4b7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -62,7 +62,7 @@ pub struct State { http: Client, default_refresh: Duration, - whitelist_refresh: Duration + whitelist_refresh: Duration, } impl State { diff --git a/src/ctx.rs b/src/ctx.rs index 63b54ff..904667d 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -2,6 +2,7 @@ use reqwest::StatusCode; use super::deserialize as de; use std::sync::Arc; use std::collections::BTreeMap; +use super::font::FontQuery; pub mod model { use std::sync::Arc; @@ -66,6 +67,13 @@ pub mod model { pub loved: bool } + #[derive(serde::Serialize, Debug)] + #[serde(untagged)] + pub enum Font { + Url { css: Arc }, + Name { name: Arc }, + } + /// The context passed in to all themes. /// /// Serialized as untagged, so themes should check if `error` is set and decide whether to show an error state or try rendering user info. @@ -75,15 +83,15 @@ pub mod model { /// Contains text explaining a potential error. Error { error: &'static str }, /// Contains data about a user and what they're listening to. - Data { user: User, scrobble: Scrobble, query: BTreeMap } + Data { user: User, scrobble: Scrobble, font: Option, query: BTreeMap, } } } #[derive(Debug)] pub struct ResponseCtx(pub model::Data, pub StatusCode); -impl From<(Result, (StatusCode, &'static str)>, BTreeMap)> for ResponseCtx { - fn from(v: (Result, (StatusCode, &'static str)>, BTreeMap)) -> ResponseCtx { - let (v, q) = v; +impl From<(Result, (StatusCode, &'static str)>, Option, BTreeMap)> for ResponseCtx { + fn from(v: (Result, (StatusCode, &'static str)>, Option, BTreeMap)) -> ResponseCtx { + let (v, f, q) = v; match v { Ok(a) => { let (user, track) = a.as_ref(); @@ -115,6 +123,11 @@ impl From<(Result, (StatusCode, &'static str)>, BTree url: track.url.clone(), loved: track.loved.unwrap_or(false) }, + font: match f { + Some(FontQuery { font: Some(s), include_font: None }) => Some(model::Font::Name { name: s }), + Some(FontQuery { include_font: Some(s), .. }) => Some(model::Font::Url { css: format!("@font-face {{ font-family: 'included_font'; src: url('{}'); }}", s.replace("\\", "\\\\").replace("'", "\\'")).into() }), + _ => None, + }, query: q }, StatusCode::OK) }, diff --git a/src/font.rs b/src/font.rs new file mode 100644 index 0000000..f9f4f4d --- /dev/null +++ b/src/font.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +#[derive(serde::Deserialize, Debug, Default)] +#[serde(default)] +#[serde(rename = "kebab-case")] +pub struct FontQuery { + pub font: Option>, + pub include_font: Option>, +// pub small_font: Option<()> +} diff --git a/src/lib.rs b/src/lib.rs index 0d1d299..8226852 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ pub mod deserialize; pub mod cache; pub mod config; pub mod ctx; +pub mod font; pub use config::STATE; pub use ctx::ResponseCtx; diff --git a/src/main.rs b/src/main.rs index b787049..f8b0e7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::fs::File; use std::sync::Arc; use lfm_embed::{STATE, ResponseCtx}; +use lfm_embed::font::FontQuery; use warp::Filter; #[derive(serde::Deserialize, Debug)] @@ -13,6 +14,9 @@ struct UserQuery { #[serde(default)] theme: Option>, #[serde(flatten)] + #[serde(default)] + font: Option, + #[serde(flatten)] rest: BTreeMap } @@ -40,7 +44,7 @@ async fn main() { .then(|s, q: UserQuery| async move { log::debug!(target: "lfm::server::user", "Handling request for user `{s}` with {q:?}"); let (ctx, dur) = STATE.get_userinfo(&s).await; - let ResponseCtx(mut data, status) = (ctx, q.rest).into(); + let ResponseCtx(mut data, status) = (ctx, q.font, q.rest).into(); let theme = q.theme.filter(|a| STATE.handlebars().has_template(&a)).unwrap_or_else(|| STATE.default_theme()); log::debug!(target: "lfm::server::user", "Using theme {theme}"); diff --git a/src/themes/plain.hbs b/src/themes/plain.hbs index fe33d28..bbd0589 100644 --- a/src/themes/plain.hbs +++ b/src/themes/plain.hbs @@ -1,5 +1,5 @@ - + {{#if error}}Error!{{else}}@{{user.name}}'s Last.fm Stats{{/if}} @@ -11,6 +11,13 @@ a:visited { color: pink } a { color: cyan; } {{/if}} + * { font-size: {{#if font}}17px{{else}}20px{{/if}}; } + {{#if font.css}} + {{{font.css}}} + {{/if}} + {{#if (or font.name font.css)}} + * { font-family: '{{#if font.name}}{{font.name}}{{/if}}{{#if font.url}}included_font{{/if}}' } + {{/if}} p { margin: 0px; padding: 0px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } @@ -18,7 +25,7 @@ {{#if error}}

{{error}}

{{else}} - +

@{{user.name}}{{#if scrobble.now_playing}} is scrobbling{{else}}'s last scrobble was {{/if}} -- cgit v1.2.3-70-g09d2