Merge branch 'main' into drafts

This commit is contained in:
John Bowdre 2024-08-05 09:26:38 -05:00
commit 010517ba3a
28 changed files with 102 additions and 298 deletions

View file

@ -45,7 +45,9 @@ jobs:
echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: Build with Hugo
run: HUGO_REMOTE_FONT_PATH=${{ secrets.REMOTE_FONT_PATH }} hugo --minify
run: |
HUGO_REMOTE_FONT_PATH=${{ secrets.REMOTE_FONT_PATH }} \
hugo --minify
- name: Insert 404 page
run: |
mkdir -p public/bunnycdn_errors

View file

@ -1,25 +0,0 @@
// manipulates the post upvote "kudos" button behavior
window.onload = function() {
// get the button and text elements
const kudosButton = document.querySelector('.kudos-button');
const kudosText = document.querySelector('.kudos-text');
const emojiSpan = kudosButton.querySelector('.emoji');
kudosButton.addEventListener('click', function(event) {
// send the event to Cabin
cabin.event('kudos')
// disable the button
kudosButton.disabled = true;
kudosButton.classList.add('clicked');
// change the displayed text
kudosText.textContent = 'Thanks!';
kudosText.classList.add('thanks');
// spin the emoji
emojiSpan.style.transform = 'rotate(360deg)';
// change the emoji to celebrate
setTimeout(function() {
emojiSpan.textContent = '🎉';
}, 150); // half of the css transition time for a smooth mid-rotation change
});
}

View file

@ -1,195 +0,0 @@
/*
Typo, a more natural web typing thing
https://neatnik.net/typo
https://github.com/neatnik/typo
Copyright (c) 2021 Neatnik LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
function num_between(min, max) {
return Math.floor(Math.random() * (max- min + 1) + min);
}
function chance(val) {
if(num_between(0, 100) < val) return true;
else return false;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
var typos = {
q:['w','a'],
w:['q','r','s'],
e:['w','d','r'],
r:['e','f','t'],
t:['r','g','y'],
y:['t','h','u'],
u:['y','j','i'],
i:['u','k','o'],
o:['i','l','p'],
p:['o',';','['],
a:['q','s','z'],
s:['w','a','x','d'],
d:['e','s','c','f'],
f:['r','d','v','g'],
g:['t','f','b','h'],
h:['y','g','n','j'],
j:['u','h','m','k'],
k:['i','j',',','l'],
l:['o','k','.',';'],
z:['a','x'],
x:['z','s','c'],
c:['x','d','v'],
v:['c','f','b'],
b:['v','g','n'],
n:['b','h','m'],
m:['n','j',','],
}
async function typo(element, text) {
var buffer = '';
var typo_active = false;
var tag_active = false;
var typing_typos = (element.dataset.typoChance) ? element.dataset.typoChance : 10;
var typing_speed = (element.dataset.typingDelay) ? element.dataset.typingDelay : 50;
var typing_jitter = (element.dataset.typingJitter) ? element.dataset.typingJitter : 15;
for (var i = 0; i < text.length; i++) {
// Get the letter that were supposed to type
letter = text.charAt(i);
// TODO: actual support for html or markup or whatever
/*
// Handle elements/markup
if(letter == '<' && (
text.charAt(i+1) == 's' ||
text.charAt(i+1) == 'p' ||
text.charAt(i+1) == 'a' ||
text.charAt(i+1) == '/' ||
text.charAt(i+1) == 'i')
) {
tag_active = true;
}
if(tag_active) {
buffer = buffer + letter;
element.innerHTML = buffer;
if(letter == '>' && (
text.charAt(i-1) == 'n' ||
text.charAt(i-1) == 'a' ||
text.charAt(i-1) == 'p' ||
text.charAt(i+1) == '"' ||
text.charAt(i+1) == '/')
) {
tag_active = false;
await sleep(typing_speed);
}
continue;
}
*/
// Trigger a typo
if(chance(typing_typos) && typo_active === false && i > 1) {
if(typeof typos[letter] !== 'undefined') {
// Swap the letter with a random typo
typo = typos[letter][Math.floor(Math.random() * typos[letter].length)];
// Append the letter to the buffer
buffer = buffer + typo;
// Write the buffer
element.innerHTML = buffer;
typo_active = true;
var seed = num_between(2,5);
realization_delay = seed;
realization_delay_counter = seed;
}
}
// Append the letter to the buffer
buffer = buffer + letter;
// Write the buffer
element.innerHTML = buffer;
// Typical typing speed
var speed_lower = parseFloat(typing_speed) - parseInt(typing_jitter);
var speed_upper = parseFloat(typing_speed) + parseInt(typing_jitter);
delay = num_between(speed_lower,speed_upper);
// Chance of longer delay though
if(chance(5)) delay = num_between(100, 200);
await sleep(delay);
if(typo_active) {
realization_delay_counter--;
if(realization_delay_counter == 0) {
for (var k = 0; k < seed+1; k++) {
// Pause at realization of typo
await sleep(typing_jitter);
// Rewind the buffer!
buffer = buffer.substring(0, buffer.length - 1);
// Write rewound buffer
element.innerHTML = buffer;
// Brief pause before continuing
await sleep(30);
}
typo_active = false;
// Add the letters back
i = i - seed;
await sleep(100);
}
}
}
// Whatever you do here will happen when the typing is finished
//do_something();
return new Promise(resolve => setTimeout(resolve, 1));
}
document.addEventListener('DOMContentLoaded', function() {
var element = document.getElementById('tagline');
var text = element.innerHTML;
typo(element, text);
});

View file

@ -8,33 +8,8 @@ numberOfRelatedPosts = 5
indexTitle = ".-. ..- -. - .. -- . - . .-. .-. --- .-."
bad_robots = [
"AdsBot-Google",
"Amazonbot",
"anthropic-ai",
"Applebot-Extended",
"AwarioRssBot",
"AwarioSmartBot",
"Bytespider",
"CCBot",
"ChatGPT",
"ChatGPT-User",
"Claude-Web",
"ClaudeBot",
"cohere-ai",
"DataForSeoBot",
"Diffbot",
"FacebookBot",
"Google-Extended",
"GPTBot",
"ImagesiftBot",
"magpie-crawler",
"omgili",
"Omgilibot",
"peer39_crawler",
"PerplexityBot",
"YouBot"
]
omgUser = "jbowdre"
musicThreadId = "2aVjZUocjk96LELFbV5JvJjm14v"
# Comments
analytics = true
@ -167,7 +142,7 @@ url = "https://jbowdre.lol"
[[socialLinks]]
icon = "fa-solid fa-pen-to-square"
title = "Weblog"
url = "https://blog.jbowdre.lol"
url = "https://srsbsns.lol"
[[socialLinks]]
icon = "fa-solid fa-satellite"

View file

@ -1 +1,2 @@
baseURL = "http://localhost:1313/"
baseURL = "http://localhost:1313/"
enableRobotsTXT = false

View file

@ -1 +1,2 @@
baseURL = "https://preview.runtimeterror.dev/"
baseURL = "https://preview.runtimeterror.dev/"
enableRobotsTXT = false

View file

@ -27,7 +27,7 @@ And in the free time I have left, I game on my Steam Deck.
### See what I've been up to on:
- [GitHub](https://github.com/jbowdre)
- [Weblog](https://blog.jbowdre.lol)
- [Weblog](https://srsbsns.lol)
- [Gemlog](https://capsule.jbowdre.lol/gemlog/)
- [status.lol](https://status.jbowdre.lol)
- [social.lol](https://social.lol/@jbowdre)

View file

@ -1,14 +1,24 @@
---
title: "/changelog"
date: "2024-05-26T21:19:08Z"
lastmod: "2024-07-04T02:32:27Z"
lastmod: "2024-08-04T22:30:43Z"
description: "Maybe I should keep a log of all my site-related tinkering?"
featured: false
toc: false
timeless: true
categories: slashes
---
*High-level list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).*
*Running list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).*
**2024-08-04:**
- Dynamically build `robots.txt` based on [ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt)
**2024-08-02:**
- Display "pinned" recent track in sidebar using [MusicThread](https://musicthread.app) instead of latest scrobble
- Tweak Typo behavior to avoid uncorrected mistakes near the end of the string
**2024-07-29:**
- Build `robots.txt` dynamically with [Dark Visitors API](https://darkvisitors.com/) and code from [Luke Harris](https://www.lkhrs.com/blog/2024/darkvisitors-hugo/)
**2024-07-03:**
- Remove `target="_blank"` from external links for improved security and accessibility
@ -16,7 +26,7 @@ categories: slashes
**2024-06-28:**
- Add [recentfm.js](https://recentfm.rknight.me/) recently-played widget to sidebar
- Use [Hugo render-hook](https://gohugo.io/render-hooks/links/#examples) to add ↗ marker to external links
- Redirect /uses and /saves to pages on the [personal blog](https://blog.jbowdre.lol)
- Redirect /uses and /saves to pages on the [personal blog](https://srsbsns.lol)
**2024-06-24:**
- Select the [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1) license

View file

@ -1,7 +1,7 @@
---
title: "/colophon"
date: "2024-05-26T22:30:58Z"
lastmod: "2024-06-29T03:29:46Z"
lastmod: "2024-08-02T21:16:41Z"
description: "There's a lot that goes into this site. Let me tell you how it works."
featured: false
toc: true
@ -15,9 +15,12 @@ categories: slashes
- uses the font face [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/) ([details](/using-custom-font-hugo/)), and icons from [Font Awesome](https://fontawesome.com/) and [Fork Awesome](https://forkaweso.me/).
- performs syntax highlighting with [Torchlight](https://torchlight.dev) ([details](/spotlight-on-torchlight/)).
- provides site search with [lunr](https://lunrjs.com/) based on an implementation detailed by [Victoria Drake](https://victoria.dev/blog/add-search-to-hugo-static-sites-with-lunr/).
- fetches [ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt) to dynamically generate a [robots.txt](/robots.txt) discouraging AI scrapers with Hugo's [`resources.GetRemote` capability](https://gohugo.io/functions/resources/getremote/).
- leverages [Cabin](https://withcabin.com) for [privacy-friendly](https://withcabin.com/privacy/runtimeterror.dev) analytics.
- fetches recently-played music from [MusicThread](https://musicthread.app/).
- displays my latest status from [omg.lol](https://home.omg.lol/referred-by/jbowdre).
- resolves via [Bunny DNS](https://bunny.net/dns/).
- is published to / hosted on [Bunny Storage](https://bunny.net/storage/) and [Bunny CDN](https://bunny.net/cdn/) with a [GitHub Actions workflow](//further-down-the-bunny-hole/)
- is published to / hosted on [Bunny Storage](https://bunny.net/storage/) and [Bunny CDN](https://bunny.net/cdn/) with a [GitHub Actions workflow](//further-down-the-bunny-hole/).
- has a [Gemini](https://geminiprotocol.net) mirror at `gemini://gmi.runtimeterror.dev`. This is generated from a [Hugo gemtext post layout](https://github.com/jbowdre/runtimeterror/blob/main/layouts/_default/single.gmi), deployed to a [Vultr](https://www.vultr.com/) VPS through that same GitHub Actions workflow, and served with [Agate](https://github.com/mbrubeck/agate).
The post content is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/); the site code is under the [MIT License](https://github.com/jbowdre/runtimeterror/blob/main/LICENSE).

View file

@ -79,6 +79,6 @@ I like to know what's flying overhead, and I'm also feeding flight data to [flig
- [Kineto](https://github.com/beelux/kineto) Gemini-to-HTTP proxy ([post](/gemini-capsule-gempost-github-actions/))
- [Linkding](https://github.com/sissbruecker/linkding) bookmark manager serving [links.bowdre.net](https://links.bowdre.net/bookmarks/shared)
- [ntfy](https://ntfy.sh/) notification service ([post](/easy-push-notifications-with-ntfy/))
- [SearXNG](https://docs.searxng.org/) self-hosted metasearch engine serving [grep.vpota.to](https://grep.vpota.to) ([post](https://blog.jbowdre.lol/post/self-hosting-a-search-engine-iyjdlk6y))
- [SearXNG](https://docs.searxng.org/) self-hosted metasearch engine serving [grep.vpota.to](https://grep.vpota.to) ([post](https://srsbsns.lol/post/self-hosting-a-search-engine-iyjdlk6y))
- [Uptime Kuma](https://github.com/louislam/uptime-kuma) for monitoring internal services (via Tailscale)
- [vault-unseal](https://github.com/lrstanley/vault-unseal) to auto-unseal my on-prem Vault instance

View file

@ -14,7 +14,7 @@ tags:
- meta
- serverless
---
As I covered briefly [in a recent Scribble](https://blog.jbowdre.lol/post/near-realtime-weather-on-profile-lol-ku4yq-zr), I was inspired by the way [Kris's omg.lol page](https://kris.omg.lol/) displays realtime data from his [Weatherflow Tempest weather station](https://shop.weatherflow.com/products/tempest). I thought that was really neat and wanted to do the same on [my omg.lol page](https://jbowdre.lol) with data from my own Tempest, but I wanted to find a way to do it without needing to include an authenticated API call in the client-side JavaScript.
As I covered briefly [in a recent Scribble](https://srsbsns.lol/post/near-realtime-weather-on-profile-lol-ku4yq-zr), I was inspired by the way [Kris's omg.lol page](https://kris.omg.lol/) displays realtime data from his [Weatherflow Tempest weather station](https://shop.weatherflow.com/products/tempest). I thought that was really neat and wanted to do the same on [my omg.lol page](https://jbowdre.lol) with data from my own Tempest, but I wanted to find a way to do it without needing to include an authenticated API call in the client-side JavaScript.
I realized I could use a GitHub Actions workflow to retrieve the data from the authenticated Tempest API, post it somewhere publicly accessible, and then have the client-side code fetch the data from there without needing any authentication. After a few days of tinkering, I came up with a presentation I'm happy with.

View file

@ -14,11 +14,11 @@ tags:
- meta
- selfhosting
---
It wasn't too long ago (January, in fact) that I started [hosting this site with Neocities](/deploy-hugo-neocities-github-actions/). I was pretty pleased with that setup, but a few weeks ago my [monitoring setup](https://blog.jbowdre.lol/post/upptime-serverless-server-monitoring-c88fbaz7) started reporting that the site was down. And sure enough, trying to access the site would return a generic error message stating that the site was unknown. I eventually discovered that this was due to Neocities "forgetting" that the site was linked to the `runtimeterror.dev` domain. It was easy enough to just re-enter that domain in the configuration, and that immediately fixed things... until a few days later when the same thing happened again.
It wasn't too long ago (January, in fact) that I started [hosting this site with Neocities](/deploy-hugo-neocities-github-actions/). I was pretty pleased with that setup, but a few weeks ago my [monitoring setup](https://srsbsns.lol/post/upptime-serverless-server-monitoring-c88fbaz7) started reporting that the site was down. And sure enough, trying to access the site would return a generic error message stating that the site was unknown. I eventually discovered that this was due to Neocities "forgetting" that the site was linked to the `runtimeterror.dev` domain. It was easy enough to just re-enter that domain in the configuration, and that immediately fixed things... until a few days later when the same thing happened again.
The same problem has now occurred five or six times, and my messages to the Neocities support contact have gone unanswered. I didn't see anyone else online reporting this exact issue, but I found several posts on Reddit about sites getting randomly broken (or even deleted!) and support taking a week (or more) to reply. I don't have that kind of patience, so I started to consider moving my content away from Neocities and cancelling my $5/month Supporter subscription.
I [recently](https://blog.jbowdre.lol/post/i-just-hopped-to-bunny-net) started using [bunny.net](https://bunny.net) for the site's DNS, and had also [leveraged Bunny's CDN for hosting font files](/using-custom-font-hugo/). This setup has been working great for me, and I realized that I could also use Bunny's CDN for hosting the entirety of my static site as well. After all, serving static files on the web is exactly what a CDN is great at. After an hour or two of tinkering, I successfully switched hosting setups with just a few seconds of downtime.
I [recently](https://srsbsns.lol/post/i-just-hopped-to-bunny-net) started using [bunny.net](https://bunny.net) for the site's DNS, and had also [leveraged Bunny's CDN for hosting font files](/using-custom-font-hugo/). This setup has been working great for me, and I realized that I could also use Bunny's CDN for hosting the entirety of my static site as well. After all, serving static files on the web is exactly what a CDN is great at. After an hour or two of tinkering, I successfully switched hosting setups with just a few seconds of downtime.
Here's how I did it.

View file

@ -18,7 +18,7 @@ I'm not one to really worry about page view metrics, but I do like to see which
In my quest for such knowledge, last week I switched my various web properties back to using [Cabin](https://withcabin.com/) for "privacy-first, carbon conscious web analytics". I really like how lightweight and deliberately minimal Cabin is, and the portal does a great job of presenting the information that I care about. With this change, though, I gave up the cute little upvote widgets provided by the previous analytics platform.
I recently shared [on my Bear weblog](https://blog.jbowdre.lol/tracking-bear-upvotes-from-my-cabin/) about how I was hijacking Bear's built-in upvote button to send a "kudos" [event](https://docs.withcabin.com/events.html) to Cabin and tally those actions there.
I recently shared [on my Bear weblog](https://srsbsns.lol/tracking-bear-upvotes-from-my-cabin/) about how I was hijacking Bear's built-in upvote button to send a "kudos" [event](https://docs.withcabin.com/events.html) to Cabin and tally those actions there.
Well today I implemented a similar thing on *this* blog. Without an existing widget to hijack, I needed to create this one from scratch using a combination of HTML in my page template, CSS to style it, and JavaScript to fire the event.

View file

@ -180,7 +180,7 @@ That's getting there:
![A darker styled RSS page](getting-there-feed.png)
Including those CSS styles means that the rendered page now uses my color palette and the [font I worked so hard to integrate](/using-custom-font-hugo/). I'm just going to make a few more tweaks to change some of the formatting, put the `New to feeds?` bit on its own line, and point to [Mojeek](https://mojeek.com) instead of DDG ([why?](https://blog.jbowdre.lol/post/a-comprehensive-evaluation-of-various-search-engines-i-ve-used)).
Including those CSS styles means that the rendered page now uses my color palette and the [font I worked so hard to integrate](/using-custom-font-hugo/). I'm just going to make a few more tweaks to change some of the formatting, put the `New to feeds?` bit on its own line, and point to [Mojeek](https://mojeek.com) instead of DDG ([why?](https://srsbsns.lol/post/a-comprehensive-evaluation-of-various-search-engines-i-ve-used)).
Here's my final (for now) `static/xml/feed.xsl` file:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

View file

@ -1,7 +1,7 @@
---
title: "Taking Taildrive for a Testdrive"
date: "2024-07-29T23:48:29Z"
# lastmod: 2024-07-28
lastmod: "2024-07-30T13:59:50Z"
description: "A quick exploration of Taildrive, Tailscale's new(ish) feature to easily share directories with other machines on your tailnet without having to juggle authentication or network connectivity."
featured: false
toc: true
@ -140,15 +140,19 @@ sudo apt update # [tl! .cmd:1]
sudo apt install davfs2
```
During the install of `davfs2`, I got prompted for whether or not I want to allow unprivileged users to mount WebDAV resources. I was in a hurry and just selected the default `<No>` response... before I realized that was probably a mistake (at least for this particular use case).
I need to be able mount the share as my standard user account (*without* elevation) to ensure that the ownership and permissions are correctly inherited. The `davfs2` installer offered to enable the SUID bit to support this, but that change on its own doesn't seem to have been sufficient in my testing. In addition (or perhaps instead?), I had to add my account to the `davfs2` group:
So I ran `sudo dpkg-reconfigure davfs2` to try again and this time made sure to select `<Yes>`:
```shell
sudo usermod -aG davfs2 $USER # [tl! .cmd]
```
![Should unprivileged users be allowed to mount WebDAV resources?](davfs-suid.png)
And then use the `newgrp` command to load the new membership without having to log out and back in again:
That should ensure that the share gets mounted with appropriate privileges (otherwise, all the files would be owned by `root` and that could pose some additional challenges).
```shell
newgrp davfs2 # [tl! .cmd]
```
I also created a folder inside my home directory to use as a mountpoint:
Next I created a folder inside my home directory to use as a mountpoint:
```shell
mkdir ~/taildrive # [tl! .cmd]

View file

@ -13,7 +13,7 @@ tags:
- meta
- tailscale
---
Last week, I came across and immediately fell in love with a delightfully-retro monospace font called [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/). I promptly purchased a "personal developer" license and set to work [applying the font in my IDE and terminal](https://blog.jbowdre.lol/post/trying-tabby-terminal). I didn't want to stop there, though; the license also permits me to use the font on my personal site, and Berkeley Mono will fit in beautifully with the whole runtimeterror aesthetic.
Last week, I came across and immediately fell in love with a delightfully-retro monospace font called [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/). I promptly purchased a "personal developer" license and set to work [applying the font in my IDE and terminal](https://srsbsns.lol/post/trying-tabby-terminal). I didn't want to stop there, though; the license also permits me to use the font on my personal site, and Berkeley Mono will fit in beautifully with the whole runtimeterror aesthetic.
Well, you're looking at the slick new font here, and I'm about to tell you how I added the font both to the site itself and to the [dynamically-generated OpenGraph share images](/dynamic-opengraph-images-with-hugo/) setup. It wasn't terribly hard to implement, but the Hugo documentation is a bit light on how to do it (and I'm kind of inept at this whole web development thing).
@ -81,7 +81,7 @@ And that would work just fine... but it *would* require storing those web font f
So instead, I opted to try using a [Content Delivery Network (CDN)](https://en.wikipedia.org/wiki/Content_delivery_network) to host the font files. This would allow for some degree of access control, help me learn more about a web technology I hadn't played with much, and make use of a cool `cdn.*` subdomain in the process.
{{% notice note "Double the CDN, double the fun" %}}
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://blog.jbowdre.lol/post/i-just-hopped-to-bunny-net). Rather than scrap the content I'd already written, I'll go ahead and describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://srsbsns.lol/post/i-just-hopped-to-bunny-net). Rather than scrap the content I'd already written, I'll go ahead and describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
{{% /notice %}}
#### Cloudflare R2

View file

@ -1,4 +1,4 @@
---
type: redirect
target: https://blog.jbowdre.lol/save
target: https://srsbsns.lol/save
---

View file

@ -1,4 +1,4 @@
---
type: redirect
target: https://blog.jbowdre.lol/uses
target: https://srsbsns.lol/uses
---

View file

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1719254875,
"narHash": "sha256-ECni+IkwXjusHsm9Sexdtq8weAq/yUyt1TWIemXt3Ko=",
"lastModified": 1722185531,
"narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "2893f56de08021cffd9b6b6dfc70fd9ccd51eb60",
"rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
"type": "github"
},
"original": {

View file

@ -47,8 +47,7 @@
</button>
<span class="kudos-text">Enjoyed this?</span>
</div>
{{ $kudos := resources.Get "js/kudos.js" | minify }}
<script src="{{ $kudos.RelPermalink }}"></script>
<script src="https://res.runtimeterror.dev/js/kudos.js" async></script>
<span class="post_email_reply"><a href="mailto:wheel.east.brief@clkdmail.com?Subject=Re: {{ .Title }}">📧 Reply by email</a></span>
{{- end }}
<footer class="content__footer"></footer>

View file

@ -51,10 +51,14 @@
{{- end }}
</ul>
{{- end }}
{{ with .Site.Params.omgUser }}
<hr>
<h3>status.lol</h3>
<script src="https://status.lol/jbowdre.js?time&link&fluent&pretty"></script>
<script src="https://status.lol/{{ . }}.js?time&link&fluent&pretty" defer></script>
{{ end }}
{{ with .Site.Params.musicThreadId }}
<hr>
<h3>latest track</h3>
<script src="https://recentfm.rknight.me/now.js?u=pushpianotire&e=🎶"></script>
<h3>current theme song</h3>
<script src="https://res.runtimeterror.dev/js/theme-song.js?id={{ . }}" defer></script>
{{ end }}

View file

@ -0,0 +1,15 @@
{{- $url := "https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/robots.json" -}}
{{- with resources.GetRemote $url -}}
{{- with .Err -}}
{{- errorf "%s" . -}}
{{- else -}}
{{- $robots := unmarshal .Content -}}
{{- range $botname, $props := $robots }}
{{- printf "User-agent: %s\n" $botname }}
{{- end }}
{{- printf "Disallow: /\n" }}
{{- printf "\n# (bad bots bundled by https://github.com/ai-robots-txt/ai.robots.txt)" }}
{{- end -}}
{{- else -}}
{{- errorf "Unable to get remote resource %q" $url -}}
{{- end -}}

View file

@ -13,5 +13,5 @@
<!-- Code Copy button via https://digitaldrummerj.me/hugo-add-copy-code-snippet-button/ -->
{{ if (findRE "<pre" .Content 1) }}
{{ $jsCopy := resources.Get "js/code-copy-button.js" | minify }}
<script src="{{ $jsCopy.RelPermalink }}"></script>
<script src="{{ $jsCopy.RelPermalink }}" async></script>
{{ end }}

View file

@ -37,7 +37,7 @@
{{ if eq .Site.Params.analytics true }}
<!-- cabin analytics -->
<script async defer src="https://cabin.runtimeterror.dev/hello.js"></script>
<script async src="https://cabin.runtimeterror.dev/hello.js"></script>
{{ end }}
<!-- syntax highlighting -->
@ -49,5 +49,4 @@
{{ end }}
<!-- typo text animation -->
{{ $jsTypo := resources.Get "js/typo.js" | minify }}
<script src="{{ $jsTypo.RelPermalink }}"></script>
<script src="https://res.runtimeterror.dev/js/typo.js" defer></script>

View file

@ -12,6 +12,6 @@
}
</script>
{{ $jsLunr := resources.Get "js/lunr.js" | minify }}
<script src="{{ $jsLunr.RelPermalink }}"></script>
<script src="{{ $jsLunr.RelPermalink }}" async></script>
{{ $jsSearch := resources.Get "js/search.js" | minify }}
<script src="{{ $jsSearch.RelPermalink }}"></script>
<script src="{{ $jsSearch.RelPermalink }}" async></script>

View file

@ -7,7 +7,5 @@ User-agent: *
Disallow:
# except for these bots which are not friends:
{{ range .Site.Params.bad_robots }}
User-agent: {{ . }}
{{- end }}
Disallow: /
{{ partial "bad-robots.html" . }}

View file

@ -238,16 +238,28 @@ small[style^="opacity: .5"] {
opacity: 1 !important;
}
/* recentfm styling */
.recent-played {
/* theme song styling */
.theme-song {
background: var(--off-bg) !important;
flex-direction:column;
border-radius: 0.5em;
padding: 0.5em;
display: flex;
flex-direction: column;
border-radius: 0.5rem;
padding: 0.7rem;
font-size: 0.9rem;
line-height: 0.9rem;
}
.recent-played-track {
margin: 0.5em 0;
.theme-song img {
width: 14rem;
height: auto;
object-fit: cover;
}
@media (min-width: 45rem) {
.theme-song img {
max-width: 100%;
margin: 0 auto;
}
}
/* code overrides */
@ -432,6 +444,7 @@ p:has(+ ul) {
.kudos-button:disabled {
cursor: default;
color: var(--fg);
}
.kudos-button .emoji {