From 9edafd94b00a73662d51824dbcba0a018e2140cf Mon Sep 17 00:00:00 2001 From: alyx Date: Thu, 10 Aug 2023 20:45:01 -0400 Subject: Create plain theme, do some escaping, fix some busted envvars, document themes. --- README.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 152 insertions(+), 9 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index d1cbc57..af69629 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,45 @@ A simple webserver for rendering a last.fm embed. More specifically, this displays a simple webpage with info about your current or most recent last.fm scrobble. -Its intended use is to be put on a personal site or whatever. +Its intended use is to be put in an iframe on a personal site or whatever. +While it is self-hostable, there is an official public instance at `https://lfm.aleteoryx.me`. # Usage + +`lfm_embed` serves one thing: +Requests to `/user/` will generate a page displaying your current or last last.fm scrobble. +The look and feel of this is down to the configured theme for your request. + +As the user, you may select a theme supported by the server by passing `?theme=` query string. +Check with your host for a list of supported themes. + +Individual themes may also support parameters, via additional query parameters. + +## Builtin Themes + +### `plain` + +A minimal theme, displaying just the username, album art, and track info. +It is the default fallback for an unset or unknown theme. + +![A screenshot of the plain theme, displaying album art, and the text "@vvinrg is scrobbling Sweet Tooth from Sleepyhead by Cavetown".](screenshots/plain-light.png) + +#### Parameters + +- `dark`: toggle the theme's dark mode. + +# Self-Hosting `lfm_embed` is, as it stands, designed to use a reverse proxy. A future release may include HTTPS support, but currently, it will only listen on `localhost`, prohibiting it from public access. Once configured, a request of the form `http://localhost:9999/` will render out an embed with the default theme. As it stands, there are no plans to support displaying users with private listen history. -*** - # Configuration Configuration should be done via the environment. `lfm_embed` also supports reading from a standard `.env` file. The following are the environment variables which `lfm_embed` understands. -*** - ## Core Config ### `LMFE_API_KEY` (Required) @@ -29,7 +50,7 @@ Your last.fm API key. You'll need to create one [here](https://www.last.fm/api/a The port to serve on locally. ### `LFME_NO_REFRESH` (Default: `0`) -If set to `1`, disable outputting of the HTML `meta http-eqiv="refresh"` tag, used for live status updates. +If set to `1`, disable outputting of the HTTP `Refresh: ` header, used to provide live status updates. ## Logging @@ -74,6 +95,8 @@ If set, must be a valid path to a directory containing [Handlebars](https://hand They will be registered as themes on top of the builtin ones, with each theme's name being their filename minus the extension. Same-named themes will override builtin ones. +See [Theming](#theming) for details on writing custom themes. + Theme names are the same as their path, minus the extension. Given an extension of .hbs, a directory like: ``` themes/ @@ -94,9 +117,11 @@ alices-themes/mysuperawesometheme By default, these are loaded and compiled once, at startup. -### `LFME_THEME_EXT` (Default: `hbs`) +### `LFME_THEME_EXT` (Default: `.hbs`) The file extension for themes in `LFME_THEME_DIR`. +Note: This behaves more like a suffix than a file extension. You must include the leading dot for a file extension. + ### `LFME_THEME_DEV` (Default: `0`) If set to `1`, existing themes will be reloaded on edit. @@ -116,7 +141,125 @@ LFME_WHITELIST_REFRESH=30s LFME_WHITELIST_MODE=exclusive LFME_WHITELIST=a_precious_basket_case, realRiversCuomo, Pixiesfan12345 ``` -*** -# Theming +# Theming {#theming} + +Custom themes are, as stated above, [Handlebars](https://handlebarsjs.com/guide/#language-features) files. +They are expected to produce a complete HTML doc, which should contain info about a user's scrobbles. + +See `src/themes` for examples of implementation. + +## Writing a Theme + +Themes should have, roughly, the structure below: + +```html + + + + + + + + {{#if error}}

{{error}}

{{else}} + + {{/if}} + + +``` + +You will be passed one of 2 context objects, depending on if there was an error processing the request. +If there was an error, the object will just be `{ error: String }`, otherwise it will be the following: + +```js +{ + // The user the request was made on the behalf of. + user: { + // Their username. + name: String, + // Their "Display Name". + realname: String, + // Link to user's profile picture. + image_url: String, + // Link to user's profile. + url: String, + + // Total scrobbles. + scrobble_count: Number, + // Number of artists in library. + artist_count: Number, + // Number of tracks in library. + track_count: Number, + // Number of albums in library. + album_count: Number, + + // True if user subscribes to last.fm pro. + pro_subscriber: Boolean + }, + + // The user's most current, or most scrobble. + scrobble: { + // The name of the track. + name: String, + // The name of its album. + album: String, + // The artist who made it. + artist: { + // Their name. + name: String, + // Link to their profile image. + image_url: String, + // Link to the artist's last.fm page. + url: String + }, + // A link to the track image. + image_url: String, + // A link to the track's last.fm page. + url: String, + + // True if the user has loved the track. + loved: Boolean + // True if the user is currently scrobbling it, false if it's just + // the most recently played track. + now_playing: Boolean, + }, + + // A set of extraneous query parameters. + // + // This should be considered UNTRUSTED, as the requester has full + // control over it. Use the provided `html_escape`, + // `html_attr_escape`, and `uri_encode` helpers when inlining + // any contained text. + query: Object +} +``` + +In addition, the following [helpers](https://handlebarsjs.com/guide/expressions.html#helpers) are provided, on top of the handlebars [builtins](https://handlebarsjs.com/guide/builtin-helpers.html): + +- `(eq Object Object) => Boolean`: Check equality between its args. + +- `(ne Object Object) => Boolean`: Check inequality between its args. + +- `(gt Number|String Number|String) => Boolean`: Check if the first arg is greater than the second. + +- `(gte Number|String Number|String) => Boolean`: Check if the first arg is greater than or equal to the second. + +- `(lt Number|String Number|String) => Boolean`: Check if the first arg is less than the second. + +- `(lte Number|String Number|String) => Boolean`: Check if the first arg is less than or equal to the second. + +- `(and Boolean Boolean) => Boolean`: Boolean AND gate. + +- `(or Boolean Boolean) => Boolean`: Boolean OR gate. + +- `(not Boolean) => Boolean`: Boolean NOT gate. + +- `(html_escape String) => String`: Escape HTML special characters from the input string, replacing them with HTML entities in the output. For use in standard markdown. + +- `(html_attr_escape String) => String`: Escape HTML special characters, as well as quotation marks, in the input, replacing them with HTML entities and escaped quotes in the output. For use in HTML tag attributes. + +- `(uri_encode String) => String`: URI-encode input text, making the output suitable to be included as part of a link or other URL. + +# Contributing +[E-Mail me](mailto:alyx@aleteoryx.me) if you'd like to help out, submit a custom theme, or request a feature. -- cgit v1.2.3-54-g00ecf