fix: myriad typos and issues
This commit is contained in:
parent
21a158602a
commit
be92f3bdf0
64 changed files with 107 additions and 104 deletions
|
@ -12,7 +12,7 @@ Here's a quick rundown of extensions and tools, specific to Safari, to make that
|
|||
- [1Blocker](https://1blocker.com): block ads, trackers and myriad other annoyances. My go to adblocker for Safari and it even ships with a handy, dandy local firewall to futz with analytics and trackers embedded in apps.
|
||||
- [Baking Soda](https://apps.apple.com/us/app/baking-soda-tube-cleaner/id1601151613) and [Vinegar](https://apps.apple.com/us/app/vinegar-tube-cleaner/id1591303229): load videos on YouTube and elsewhere in the native video player.
|
||||
- [Banish](https://apps.apple.com/us/app/banish-block-open-in-app/id1632848430): block all those annoying open in app banners.[^2]
|
||||
- [Stop the Madness](https://underpassapp.com/StopTheMadness/): a Swiss Army knife of an extension aimed at curtailing modern annoyances. It'll route around AMP pages, strip tracking parameters, stops clickjacking, stops url shorteners and myriad other fixes for popular user-hostile patterns. *Essential*.atterns. *Essential*.
|
||||
- [Stop the Madness](https://underpassapp.com/StopTheMadness/): a Swiss Army knife of an extension aimed at curtailing modern annoyances. It'll route around AMP pages, strip tracking parameters, stops clickjacking, stops url shorteners and myriad other fixes for popular user-hostile patterns. *Essential*.
|
||||
- [Super Agent](https://www.super-agent.com/): automatically set your cookie preferences to the minimum allowed set.[^3]
|
||||
- [User Scripts](https://github.com/quoid/userscripts): an open source user scripts extension for Safari. I'll leave this one to your imagination (exercise caution and abandon in equal measure since you'll be running community provided scripts and styles on the sites you visit).
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ tags: ['webmentions', 'development', 'JavaScript']
|
|||
|
||||
My blog is currently hosted on weblog.lol which allows for a simple and configurable weblog managed in git with posts formatted in markdown. I wanted to add webmentions to my blog which, as of now, doesn't include a build step. To accomplish this, I've added an intermediary api endpoint to the same Next.js app that powers my [/now](https://coryd.dev/now) page.<!-- excerpt -->
|
||||
|
||||
Robb has [a handy write up on adding webmentions to your website](https://rknight.me/adding-webmentions-to-your-site/), which I followed — first adding the appropriate Mastodon link to my blog template, registering for webmentions.up and Bridgy, then adding the appropriate tags to my template document's `<head>` to record mentions.
|
||||
Robb has [a handy write-up on adding webmentions to your website](https://rknight.me/adding-webmentions-to-your-site/), which I followed — first adding the appropriate Mastodon link to my blog template, registering for webmentions.io and Bridgy, then adding the appropriate tags to my template document's `<head>` to record mentions.
|
||||
|
||||
Next it was simply a question of rendering the output from the webmentions endpoint.
|
||||
|
||||
|
@ -137,4 +137,4 @@ The webmentions HTML shell is as follows:
|
|||
</div>
|
||||
```
|
||||
|
||||
And there you have it — webmentions loaded client side and updated as they occur. There's an example visible on my post [Automating (and probably overengineering) my /now page](https://blog.coryd.dev/2023/02/automatingandprobablyoverengineeringmy-nowpage#webmentions).
|
||||
And there you have it — webmentions loaded client side and updated as they occur. There's an example visible on my post [Automating (and probably over-engineering) my /now page](https://blog.coryd.dev/2023/02/automatingandprobablyoverengineeringmy-nowpage#webmentions).
|
||||
|
|
|
@ -5,7 +5,7 @@ draft: false
|
|||
tags: ['automation', 'Mastodon', 'Eleventy']
|
||||
---
|
||||
|
||||
I've discussed [building a now page using Eleventy](/posts/2023/building-my-now-page-using-eleventy/) but I also syndicate a subset of that content out to Mastodon using [`@11ty/eleventy-activity-feed`](https://www.npmjs.com/package/@11ty/eleventy-activity-feed) and [Make](https://make.com/en/).<!-- excerpt --> The [`@11ty/eleventy-activity-feed`](https://www.npmjs.com/package/@11ty/eleventy-activity-feed) allows you to aggregate various web feeds into a single feed, inserting entries from the feeds sequentially as they're published. My `follow-feed.11ty.js` looks like this:
|
||||
I've discussed [building a now page using Eleventy,](/posts/2023/building-my-now-page-using-eleventy/) but I also syndicate a subset of that content out to Mastodon using [`@11ty/eleventy-activity-feed`](https://www.npmjs.com/package/@11ty/eleventy-activity-feed) and [Make](https://make.com/en/).<!-- excerpt --> The [`@11ty/eleventy-activity-feed`](https://www.npmjs.com/package/@11ty/eleventy-activity-feed) allows you to aggregate various web feeds into a single feed, inserting entries from the feeds sequentially as they're published. My `follow-feed.11ty.js` looks like this:
|
||||
|
||||
```javascript
|
||||
module.exports = class {
|
||||
|
|
|
@ -29,7 +29,7 @@ export default async function handler(req: any, res: any) {
|
|||
}
|
||||
const METHOD = METHODS[req.query.type] || METHODS['default']
|
||||
const data = await fetch(
|
||||
`http://ws.audioscrobbler.com/2.0/?method=${METHOD}&user=cdme_&api_key=${KEY}&limit=${
|
||||
`https://ws.audioscrobbler.com/2.0/?method=${METHOD}&user=cdme_&api_key=${KEY}&limit=${
|
||||
req.query.limit || 20
|
||||
}&format=${req.query.format || 'json'}&period=${req.query.period || 'overall'}`
|
||||
).then((response) => response.json())
|
||||
|
|
|
@ -111,7 +111,7 @@ export default async function syndicate(init?: string) {
|
|||
}
|
||||
```
|
||||
|
||||
We start off with an optional `init` parameter that can be passed into our `syndicate` function to hydrate our syndication cache — the structure of this cache is essentially `SERIVCE_KEY: string[]` where `string[]` contains RSS post IDs. Now, given that Vercel is intended as front end hosting, I needed a reasonably simple and reliable solution for hosting a simple JSON object. I explored and didn't want to involve a full-fledged database or storage solution and wasn't terribly interested in dealing with S3 or B2 for this purpose so I, instead, went with a "secret" GitHub gist[^1] and leveraged the GitHub API for storage. At each step of the [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) process in this script we make a call to the GitHub API using a token for authentication, deal with the returned JSON and go on our merry way.
|
||||
We start off with an optional `init` parameter that can be passed into our `syndicate` function to hydrate our syndication cache — the structure of this cache is essentially `SERIVCE_KEY: string[]` where `string[]` contains RSS post IDs. Now, given that Vercel is intended as front end hosting, I needed a reasonably simple and reliable solution for hosting a simple JSON object. I explored and didn't want to involve a full-fledged database or storage solution and wasn't terribly interested in dealing with S3 or B2 for this purpose, so I, instead, went with a "secret" GitHub gist[^1] and leveraged the GitHub API for storage. At each step of the [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) process in this script we make a call to the GitHub API using a token for authentication, deal with the returned JSON and go on our merry way.
|
||||
|
||||
Once the cache is hydrated the script will check the feeds available in `lib/syndicate/config.ts` and post the most recent item if it does not exist in the cache and then add it to said cache. The configured services are simply:
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ export default async function loadNowData(endpoints?: string) {
|
|||
|
||||
// artists
|
||||
if ((endpoints && selectedEndpoints.includes('artists')) || !endpoints) {
|
||||
const artistsUrl = `http://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=cdme_&api_key=${MUSIC_KEY}&limit=8&format=json&period=7day`
|
||||
const artistsUrl = `https://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=cdme_&api_key=${MUSIC_KEY}&limit=8&format=json&period=7day`
|
||||
artistsJson = await fetch(artistsUrl)
|
||||
.then((response) => response.json())
|
||||
.catch((error) => {
|
||||
|
@ -186,7 +186,7 @@ export default async function loadNowData(endpoints?: string) {
|
|||
|
||||
// albums
|
||||
if ((endpoints && selectedEndpoints.includes('albums')) || !endpoints) {
|
||||
const albumsUrl = `http://ws.audioscrobbler.com/2.0/?method=user.gettopalbums&user=cdme_&api_key=${MUSIC_KEY}&limit=8&format=json&period=7day`
|
||||
const albumsUrl = `https://ws.audioscrobbler.com/2.0/?method=user.gettopalbums&user=cdme_&api_key=${MUSIC_KEY}&limit=8&format=json&period=7day`
|
||||
albumsJson = await fetch(albumsUrl)
|
||||
.then((response) => response.json())
|
||||
.catch((error) => {
|
||||
|
@ -226,7 +226,7 @@ export default async function loadNowData(endpoints?: string) {
|
|||
|
||||
// current track
|
||||
if ((endpoints && selectedEndpoints.includes('currentTrack')) || !endpoints) {
|
||||
const currentTrackUrl = `http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=cdme_&api_key=${MUSIC_KEY}&limit=1&format=json&period=7day`
|
||||
const currentTrackUrl = `https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=cdme_&api_key=${MUSIC_KEY}&limit=1&format=json&period=7day`
|
||||
currentTrackJson = await fetch(currentTrackUrl)
|
||||
.then((response) => response.json())
|
||||
.catch((error) => {
|
||||
|
@ -338,7 +338,7 @@ const Cover = (props: { media: Media; type: 'artist' | 'album' }) => {
|
|||
export default Cover
|
||||
```
|
||||
|
||||
All of the components for this page [can be viewed on GitHub](https://github.com/cdransf/coryd.dev/tree/main/components/media). Each one consumes an object from the `loadNowData` object and renders it to the page. The page is also periodically revalidated via an api route that simply calls this same method:
|
||||
All the components for this page [can be viewed on GitHub](https://github.com/cdransf/coryd.dev/tree/main/components/media). Each one consumes an object from the `loadNowData` object and renders it to the page. The page is also periodically revalidated via an api route that simply calls this same method:
|
||||
|
||||
```ts
|
||||
import loadNowData from '@/lib/now'
|
||||
|
|
|
@ -30,7 +30,7 @@ const EleventyFetch = require('@11ty/eleventy-fetch')
|
|||
|
||||
module.exports = async function () {
|
||||
const MUSIC_KEY = process.env.API_KEY_LASTFM
|
||||
const url = `http://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=cdme_&api_key=${MUSIC_KEY}&limit=8&format=json&period=7day`
|
||||
const url = `https://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=cdme_&api_key=${MUSIC_KEY}&limit=8&format=json&period=7day`
|
||||
const res = EleventyFetch(url, {
|
||||
duration: '1h',
|
||||
type: 'json',
|
||||
|
@ -159,7 +159,7 @@ module.exports = async function () {
|
|||
}
|
||||
```
|
||||
|
||||
Rather than dealing with a an API that returns JSON, I'm transforming the RSS feed that Oku exposes for my currently reading collection, using [@extractis/feed-extractor](https://www.npmjs.com/package/@extractus/feed-extractor) to transform the XML into JSON and leveraging Eleventy's [@11ty/eleventy-fetch](https://www.npmjs.com/package/@11ty/eleventy-fetch) package for caching. Because I'm simply rendering a list of what I'm reading, the liquid templating is a bit simpler:
|
||||
Rather than dealing with an API that returns JSON, I'm transforming the RSS feed that Oku exposes for my currently reading collection, using [@extractis/feed-extractor](https://www.npmjs.com/package/@extractus/feed-extractor) to transform the XML into JSON and leveraging Eleventy's [@11ty/eleventy-fetch](https://www.npmjs.com/package/@11ty/eleventy-fetch) package for caching. Because I'm simply rendering a list of what I'm reading, the liquid templating is a bit simpler:
|
||||
|
||||
{% raw %}
|
||||
|
||||
|
@ -188,7 +188,7 @@ Rather than dealing with a an API that returns JSON, I'm transforming the RSS fe
|
|||
|
||||
For **Watching: movies** and **Watching: tv** we're following a nearly identical pattern (outside of object name semantics that are specific to the media type for each). Both Trakt and Letterboxd expose RSS feeds for watched media activity and both are passed through, fetched and cached using the same dependencies.
|
||||
|
||||
[You can view the tv.js data file here](https://github.com/cdransf/coryd.dev/blob/e886857387661ceeba4f2b368989ec32f0c3f121/src/_data/tv.js) and [movies here](https://github.com/cdransf/coryd.dev/blob/e886857387661ceeba4f2b368989ec32f0c3f121/src/_data/movies.js), while [the full `now.liquid` combines all of the discussed snippets](https://github.com/cdransf/coryd.dev/blob/e886857387661ceeba4f2b368989ec32f0c3f121/src/_includes/now.liquid).
|
||||
[You can view the tv.js data file here](https://github.com/cdransf/coryd.dev/blob/e886857387661ceeba4f2b368989ec32f0c3f121/src/_data/tv.js) and [movies here](https://github.com/cdransf/coryd.dev/blob/e886857387661ceeba4f2b368989ec32f0c3f121/src/_data/movies.js), while [the full `now.liquid` combines all the discussed snippets](https://github.com/cdransf/coryd.dev/blob/e886857387661ceeba4f2b368989ec32f0c3f121/src/_includes/now.liquid).
|
||||
|
||||
Currently, this page is refreshed on an hourly basis using scheduled builds on Vercel triggered by GitHub actions, [which you can read about here](/posts/2023/scheduled-eleventy-builds-cron-github-actions/).
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ These work by checking that the `To/CC/BCC` matches the appropriate alias before
|
|||
|
||||
In the event I've failed to tune a regular expression properly or an actual person triggers a match I have a rule that is executed after the aforementioned alias-specific rules that stops all rule evaluations for _any_ address in my contacts.
|
||||
|
||||
**Update:** I've run every regular expression and glob pattern I apply to my messages through ChatGPT to see if it could simplify, combine and otherwise improve them (namely reducing false positives). This has worked quite well (outside of the time required to coax ChatGPT to the best possible answer). Further, my deliveries rule that forwards to Parcel now also requires both a subject and body match before forwarding.
|
||||
**Update:** I've run every regular expression and glob pattern I apply to my messages through ChatGPT to see if it could simplify, combine and otherwise improve them (namely reducing false positives). This has worked quite well (outside the time required to coax ChatGPT to the best possible answer). Further, my deliveries rule that forwards to Parcel now also requires both a subject and body match before forwarding.
|
||||
|
||||
[I also have a rule containing regular expressions that also skips evaluations for login pin codes, meeting/appointment reminders and common security notices](https://pastes.coryd.dev/mail-regexes-alerts/markup).
|
||||
|
||||
|
@ -92,7 +92,7 @@ In the event I've failed to tune a regular expression properly or an actual pers
|
|||
|
||||
## Mapping categories as folders
|
||||
|
||||
I've tailored these rules to align with folders on a per topic basis. I have a broad `Financial` folder for things like receipts, bank statements and bills. That folder contains a few granular subfolders like `Deliveries`, `Media`, `Medical`, `Promotions` and so forth. All multi-step rules are set to filter messages when `any` of the tabled criteria matches.
|
||||
I've tailored these rules to align with folders on a per-topic basis. I have a broad `Financial` folder for things like receipts, bank statements and bills. That folder contains a few granular subfolders like `Deliveries`, `Media`, `Medical`, `Promotions` and so forth. All multistep rules are set to filter messages when `any` of the tabled criteria matches.
|
||||
|
||||
The top level `Financial` rule [looks like this](https://pastes.coryd.dev/mail-regexes-financial/markup).
|
||||
|
||||
|
@ -138,7 +138,7 @@ The top level `Financial` rule [looks like this](https://pastes.coryd.dev/mail-r
|
|||
|
||||
`Deliveries` follow a similar pattern with rule sets intended to capture messages with package tracking information or other details. I kickstarted this rule by, naturally, referencing [this answer from StackOverflow](https://stackoverflow.com/a/5024011).
|
||||
|
||||
All of the regular expressions contained in this answer are matched against the `Body` of inbound messages before being forwarded to [Parcel Email](https://parcelapp.net/help/parcel-email.html)[^3]. These rules are supplemented by a few edge case rules targeted at the `Subject` field:
|
||||
All the regular expressions contained in this answer are matched against the `Body` of inbound messages before being forwarded to [Parcel Email](https://parcelapp.net/help/parcel-email.html)[^3]. These rules are supplemented by a few edge case rules targeted at the `Subject` field:
|
||||
|
||||
```json
|
||||
"conditions": [
|
||||
|
@ -275,7 +275,7 @@ These are designed to capture confirmations sent by Southwest and are sent off t
|
|||
```
|
||||
|
||||
**Social networking messages**
|
||||
These I've left as a simple list wherein `any` included top level domain is filed away as I don't belong to many social networks and they change fairly infrequently.
|
||||
These I've left as a simple list wherein `any` included top level domain is filed away as I don't belong to many social networks, and they change fairly infrequently.
|
||||
|
||||
**DMARC notifications (depending on how you have your policy record configured)**
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ This leaves me in a place where I've ruled out the popular streaming music provi
|
|||
- **[Astiga:](https://asti.ga)** nicely designed, supports the [Subsonic music API](http://www.subsonic.org/pages/api.jsp) and lets you source music from cloud storage. **Awesome.** Not awesome: I don't particularly like any of the available iOS apps and scrobbling from iOS to Last.fm is inconsistent. Not perfect — absolutely worth keeping an eye on as it develops.
|
||||
- **[Roon:](https://roonlabs.com)** a very promising service, but one geared more towards the audiophile audience and with hardware requirements I'm not interested in investing in at this point.
|
||||
|
||||
Pretty limited, right? My solution and the one I'm really enjoying is [Plexamp](https://plexamp.com/). I knew Plex supported music playback — I didn't realize they had an excellent, bespoke app to support it.[^5] Plex scrobbles to Last.fm from the server, auto-populates artist metadata, does a stellar job matching similar artists and building playlists from *your own collection*. That's it, that's what I wanted. I don't want the collection to drift, I'll add to it when I find music that I want to listen to more than once and *sometimes*, I want to throw on a station or playlist constrained to that set of artists.
|
||||
Pretty limited, right? My solution and the one I'm really enjoying is [Plexamp](https://plexamp.com/). I knew Plex supported music playback — I didn't realize they had an excellent, bespoke app to support it.[^5] Plex scrobbles to Last.fm from the server, autopopulates artist metadata, does a stellar job matching similar artists and building playlists from *your own collection*. That's it, that's what I wanted. I don't want the collection to drift, I'll add to it when I find music that I want to listen to more than once and *sometimes*, I want to throw on a station or playlist constrained to that set of artists.
|
||||
|
||||
So here we are: I have a cloud-based Plex instance, it's used solely for music playback, the artist images match up with Last.fm and [my now page](/now). The metadata is defined the way I've elected to define it and it's available via an [rclone](https://rclone.org) mount to Google Drive. This is all more complicated than listening to music should be, but I can hit play and listen to what I want to (and get decent recommendations too). Apparently that's too much to ask for from most services, or maybe I'm just out of touch.[^6]
|
||||
So here we are: I have a cloud-based Plex instance, it's used solely for music playback, the artist images match up with Last.fm and [my now page](/now). The metadata is defined the way I've elected to define it, and it's available via a [rclone](https://rclone.org) mount to Google Drive. This is all more complicated than listening to music should be, but I can hit play and listen to what I want to (and get decent recommendations too). Apparently that's too much to ask for from most services, or maybe I'm just out of touch.[^6]
|
||||
|
||||
[^1]: When I last leveraged Apple Music's catalogue I kept a smart playlist that highlighted releases that fell out of their streaming catalogue.
|
||||
[^2]: One of those apps that does exactly what it sets out to in a robust and reliable manner — plus it's native to macOS. Go buy it.
|
||||
|
|
|
@ -5,11 +5,11 @@ draft: false
|
|||
tags: ['Eleventy', 'JavaScript', 'development']
|
||||
---
|
||||
|
||||
I've relaunched, rebuilt and rewritten my personal blog more times than I can count and I've had a trail of posts I've never fully migrated at each turn. This weekend, while relaxing and watching movies I ported them into Eleventy and, in doing so, found that the pagination implementation I was using didn't scale well with the number of pages I added.<!-- excerpt -->
|
||||
I've relaunched, rebuilt and rewritten my personal blog more times than I can count, and I've had a trail of posts I've never fully migrated at each turn. This weekend, while relaxing and watching movies I ported them into Eleventy and, in doing so, found that the pagination implementation I was using didn't scale well with the number of pages I added.<!-- excerpt -->
|
||||
|
||||
I quickly explored having the current page act as a floating index of sorts wherein I would cap the number of pages shown at, say, `5` and then show the previous and next two pages on either side. Limiting the rendered count in [liquid.js](https://liquidjs.com/) was as simple as using the `limit` filter, but tracking the floating index and numbers on either side was more difficult than I would have liked.
|
||||
|
||||
Given that I was already iterating through all pages in my posts collection, my next thought (and the choice I ran with) was to fold all of the enumerated values into a `<select>` and use that to give users more control when paging. That select lives in [`paginator.liquid#17-28`](https://github.com/cdransf/coryd.dev/blob/78f6cfa93b6caaf6d82e9085939df9d2a14fc389/src/_includes/paginator.liquid#L17-L28) and looks like this:
|
||||
Given that I was already iterating through all pages in my posts collection, my next thought (and the choice I ran with) was to fold all the enumerated values into a `<select>` and use that to give users more control when paging. That select lives in [`paginator.liquid#17-28`](https://github.com/cdransf/coryd.dev/blob/78f6cfa93b6caaf6d82e9085939df9d2a14fc389/src/_includes/paginator.liquid#L17-L28) and looks like this:
|
||||
|
||||
```html
|
||||
<div class="flex flex-row items-center">
|
||||
|
|
Reference in a new issue