Sunday, April 06, 2025

Black and white film photo of a bunch of film rolls

I honestly don't know whether the past few days of tinkering with Emacs evil-mode, Doom, etc. was fun or a complete, confusing waste of time. Right now I'm thinking the latter.


I don't care what you think

I don’t mean to be rude, but I don’t care much what you think. OK, that’s not exactly true, I care deeply what you think. Maybe it’s more accurate to say that I don’t worry about what you think. Are you mad that I keep switching platforms? Sorry, not sorry. Are you annoyed that I use words like “just” and “maybe” and “really” too often? Yeah, me too. We’ll get over it. Does it bother you that I don’t do enough throat-clearing before mentioning something that has become problematic? You’ll be fine. Would you prefer that I only write about Emacs? Not happening.

There, I feel a little better now, because when I got up this morning I wanted to apologize for being alive and just (see, there’s that word again) shut everything down. I don’t think I’ll do that, though, because regardless of what you think…I think…and it needs to come out somehow.

Permalink #

Saturday, April 05, 2025

black and white film photo of my grandson looking out the window.

I should apologize for my mood this morning...Sorry about my mood this morning.


Yesterday, I decided to bring back my Doom Emacs config. I've been missing evil-mode and using Space as leader key. Sometimes hitting Control-this Control-that constantly becomes tedious, ya know? After a couple of hours, I bailed on the idea. Doom offers a ton of quality-of-life features, but it also contains a lot of magic. As much as I appreciate the magic, I too often feel like it's working against me. Back to my own config, which works against me too, but at least it's my fault this way.


Friday, April 04, 2025

Black and white photo of my dog on the couch

I need to find a way for my brain to relax. I spend entire days with a dozen apps open, each with a dozen tabs open. I click rapidly between them looking for something to focus on. I never find anything.


Part of my problem might be that I've surrounded myself with too much infrastructure. There are dependencies everywhere. daily.baty.net for example. The idea is that I have a separate blog that works well for short, daily writing. Except that now I have two blogs. And I'm (for the moment) using Kirby for that one. This means an entirely different workflow and setup. This is great for when I'm feeling bored with Hugo. It keeps me from moving this blog back and forth. However, it's also more stuff in my brain. Do I need more stuff in my brain? Right now, I don't think so. Hence, I'm writing today's journal post here.


I was feeling nostalgic for Evil mode today, so, instead of doing the smart thing and installing and configuring Evil-mode, I brought back my Doom Emacs config and got it up to date. Doom is pretty great. It usually takes a couple weeks before I get twitchy about Emacs not feeling like "it's mine" but we'll see.


Handling robots.txt with Caddy and Kirby CMS

Kirby CMS uses plain .txt files for content. Since the bare .txt files should not be accessible with a browser, one normally uses a path matcher in Caddy and then denies requests based on a path, like so...

path *.txt /content/* /site/* /kirby/* /.*

But what if I want a /robots.txt file? Turned out to be a simple answer, but it took me a while to find it. I'm writing it down here in case anyone else might need it. Here's the whole block from my site's Caddyfile:

(kirby) {
    php_fastcgi unix//run/php/php8.3-fpm.sock
    @blocked {
        path *.txt *.md /content/* /site/* /kirby/* /.*
        not path /robots.txt   # <----- Here's the important part
    }
    respond @blocked "Not Found" 404 {
        close
    }
}

With that one extra line, when you add an import kirby line to a server block, /robots.txt will remain accessible.

Permalink #

Journelly - Org mode-backed journaling for iOS

I saw the Irreal post about Journelly, but mostly ignored it because I wasn't looking for a new iOS journaling app. He did mention that Journelly is by Álvaro Ramírez, author of Plain Org, lmno.lol, and others, so that made things more interesting.

What intrigued me most, though, was learning that Journelly is backed by plain-text Org Mode files. Bonus! Now it had my attention.

Álvaro was kind enough to let me into the TestFlight, and I'm putting it through its paces this morning.

Here's what mine looks like so far...

Simple and easy to use, so that's good. As Álvaro desribed Journelly, it's like a personal, private Twitter/Instagram/Mastodon account.

Speaking of simple, the entire journal is kept as a single journelly.org file. I chose to sync mine via iCloud, which meant that I could view and edit it locally on my Mac. The problem with iCloud Drive's default storage locations is that they're in a stupid place, e.g. /Users/jbaty/Library/Mobile Documents/iCloud~com~xenodium~Journelly/Documents/Journelly.org. Don't make me create symlinks, iCloud! 😄

Digging into the settings, I noticed that in addition to the default iCloud Drive folder, I could configure Journelly to use any folder in iCloud, including my ever-popular ~/Documents/Notes folder. Much better.

Since I use Emacs for most everything, including my journals, I've never done much journaling on my Phone. Journelly could change this equation.

It would be cool if I could use Journelly from my Mac as well. To that end, I created an Org Mode capture template to make it easy to add entries while in Emacs on my Mac.

("j" "Journelly Entry" entry
           (file "~/Documents/Notes/Journelly/Journelly.org")
           "* %U @ -\n%?" :prepend t)

I can now hit C-c c j and I'm in a capture buffer for the Journelly file. The Journelly app can include weather and location to new entries. Currently, my capture template isn't smart enough to do that, but it could be, with just a bit of work.

It's only been a couple of hours with Journelly, so this isn't meant to be a review, but first impressions are that it's handy, simple, and could work well as an adjunct to my existing Org mode based note-taking setup.

For a recent review of Journelly, see Monday App Finder: Journelly, a Twitter-Like Journal for iOS - The Mac Observer.

Permalink #

Daily.baty.net is running Kirby now

I've migrated daily.baty.net to Kirby CMS. It has been a static site managed by Tinderbox for a long time. I love Tinderbox, but now that baty.net is back on Hugo, I wanted a playground for learning more about Kirby, without moving the main blog back and forth between Hugo and Kirby. So, here we are.

Your RSS feed is probably complaining right now. Sorry about that.

Permalink #

Mu4e transient menu

I ran across something neat while reading the Mu4e release notes

A (experimental) “transient” menu has been added for mu4e. You can use it e.g., with something like:

(require 'mu4e-transient)
(global-set-key (kbd "C-c m") #'mu4e-transient-menu)

It's very handy!

Permalink #

Saturday, March 29, 2025

One of the things I'm finding useful about LLMs is having them summarize my own writing. For example, I threw this month's Org journal at ChatGPT and asked for a summary:

Jack Baty's journal entries from early March 2025 reflect his daily life, thoughts on photography, and personal observations. He struggles with sleep due to being woken early, enjoys organizing his journals and photos, and contemplates selling his cameras, particularly the Leica SL2 or Nikon Zf. He describes his experiences shopping with friends and family, expresses concerns about aging, and shares his mixed feelings about current events, especially regarding political figures. His reflections reveal a sense of nostalgia, motivation issues, and a desire for connection, particularly with his partner, Gail. He also documents mundane tasks, like grocery shopping and website building, while dealing with the ups and downs of daily life, including caring for his dog, Alice.

It's as if my journaling is raw material for a new set of documents summarizing my life. It's readable, accurate[1], and like seeing it this way.


🎶 "Absolute Elsewhere" by Blood Incantation.

When are we going to get past this period of Metal sounding like call-and-respond between Backstreet Boys and Cookie Monster with the flu? It's been self-parody for a decade.



  1. Well OK, my feelings about current events and "political figures" are not at all "mixed". ↩︎

Annotating an image with weather

I thought it would be neat to include the date and weather on the images I use for my journal entry covers here on the blog.

It turned out to be neat, but not fun. I spent nearly 3 hours on all sorts of failed approaches. I figured it might be useful to write down where I ended up.

I leveraged two of my existing bash scripts that deal with the weather, and wrote a new one that uses ImageMagick to put things together.

Basically, I pass an image name to the script and it overlays the date at the bottom left and the weather at the bottom right. Like so...

~/bin/annotate-image.sh MyImage.jpg

Here is the result:

The results are still janky, but they work.
#!/bin/bash

# Check if an image name is provided
if [ "$#" -ne 1 ]; then
    echo "Usage: $0 <image_file>"
    exit 1
fi

IMAGE_FILE="$1"
OUTPUT_FILE="cover_$(basename "$IMAGE_FILE")"
WEATHER_URL="wttr.in/Grand+Rapids_0tqp0.png"
WEATHER_ICON=$(~/bin/getwcond)
WEATHER_ICON="/Users/jbaty/Sync/graphics/weather/64x64/day/$WEATHER_ICON"
CONDITIONS=$(~/bin/getweather | cut -f2 -d"|")


# Get current date in format "Friday, March 28, 2025"
CURRENT_DATE=$(date "+%A, %B %d, %Y")

# Add the weather info to the bottom right and the date to the bottom left
/opt/homebrew/bin/magick \
    "$IMAGE_FILE" \
    -fill white \
    -undercolor '#6F737880' \
    -font "Helvetica" \
    -pointsize 40 \
    -gravity SouthWest \
    -annotate +20+20 "$CURRENT_DATE" \
    -gravity SouthEast \
    -pointsize 30 \
    -annotate +20+20 "$CONDITIONS" \
    "$OUTPUT_FILE"

# Now overlay the weather from wttr onto the output from the previous command
/opt/homebrew/bin/magick composite \
    -gravity SouthEast \
    -geometry +20+60 \
    "$WEATHER_ICON" \
    "$OUTPUT_FILE" \
    "$OUTPUT_FILE"

echo "Weather added to image: $OUTPUT_FILE"

That script uses two other scripts that I wrote years ago for grabbing weather conditions getweather

#!/bin/sh
# Grab and parse weather info using WeatherAPI.com

jq=/opt/homebrew/bin/jq
weatherfile=`mktemp`
curl -s "https://api.weatherapi.com/v1/forecast.json?key=MYAPIKEY&q=MYZIP&days=1&aqi=no&alerts=no" > $weatherfile

now=`${jq} -r .current.condition.text ${weatherfile}`
temp=`${jq} -r .current.temp_f ${weatherfile}`
condition=`${jq} -r .forecast.forecastday[0].day.condition.text ${weatherfile}`
high=`${jq} -r .forecast.forecastday[0].day.maxtemp_f ${weatherfile}`
low=`${jq} -r .forecast.forecastday[0].day.mintemp_f ${weatherfile}`

echo "${now} ${temp} | Low ${low}, High ${high}"

Returns something like "Light rain 50.4 | Low 27.9, High 69.1". I use cut to grab just the high/low temperature part.

Then there's getwcond which is mostly a copy/paste job from the previous script. It returns the name of an image file for the current conditions (e.g. 234.png). I use this as the icon to overlay onto the image.

#!/bin/sh
# Jack Baty, 2023 (https://baty.net)
# Grab and parse weather info using WeatherAPI.com

jq=/opt/homebrew/bin/jq
weatherfile=`mktemp`
conditionfile=/Users/jbaty/Sync/graphics/weather/conditions.json
curl -s "https://api.weatherapi.com/v1/forecast.json?key=MYAPIKEY&q=MYZIP&days=1&aqi=no&alerts=no" > $weatherfile

code=`${jq} -r .forecast.forecastday[0].day.condition.code ${weatherfile}`
iconcond=`${jq} -r .current.condition.icon ${weatherfile}`
icon=$(${jq} '.[] | select(.code=='${code}').icon' ${conditionfile})

iconfile=$(basename $iconcond)
echo $iconfile

This all took me way too long. I could've pulled out the LLM crutch, but I really wanted to figure it out on my own. Next time I should just take the extra 2 minutes and use Photoshop instead :).

Permalink #

Friday, March 28, 2025

Black and white photo of old car behind bushes

I spent hours this morning trying to find a good way of adding some metadata to the cover images on the blog. I wanted the temparature, at least. I tried shoehorning it into my Retrobatch script, but that was a dead end. Whenever I'm lost in image manipulation, I turn to ImageMagick. Boy did that take me down a rabbit hole. Long story short, I figured it out. But now I don't like it. ¯_(ツ)_/¯.


So, the so-called DOGE is planning to rewrite the SSA codebase in months. This sounds to me like a way to stop paying people, but being able to blame it on software.


Emacs lisp function to update exif data in film scans

I maintain a list of shell commands for updating Make/Model/Lens information in film scans. I've always run this via babel in a code block in an Org mode file. Something like this:

#+begin_src sh
  cd ~/Pictures/_Scans
  exiftool '-m' '-Make=Leica' '-Model=Leica MP' -overwrite_original .
  exiftool '-m' '-LensModel=Summilux-M 1:1.4/50 ASPH' '-FocalLength=50mm' -overwrite_original .
#+End_src

Easy enough, I just copy and paste from a list of commands, depending on the lens and camera. However, it occurred to me that I'd prefer to simply have Emacs prompt me for the information, and then take care of the shell commands for me. Also, instead of hard-coding the path, I wanted to use marked files in a Dired buffer.

I had no idea how to approach this, so I tucked my tail between my legs and asked ChatGPT.

Write an emacs lisp function that, when run in a dired buffer, prompts me for a camera model (from a predefined list of models) and then uses exiftool to set the Make and Model fields of the marked files using my selection.

It worked, first try, but I'd forgotten about the lens options, so I followed up with:

Can you modify it so that I also select a lens and so that the lens information includes focal length?

In 20 seconds, with only a couple of small tweaks, I had a working solution. The only thing for me to do was put my options into camera-list and lens-list.

(defun my/dired-set-exif-camera-lens ()
  "Set the Make, Model, Lens, and Focal Length of marked files in Dired using exiftool."
  "Written (mostly) by ChatGPT"
  (interactive)
(let* ((camera-list '(("Leica MP" . "Leica")
                      ("Leica M3" . "Leica")
                      ("Nikon FM2n" . "Nikon")
                      ("Hasselblad 500C/M" . "Hasselblad")
                      ("Olympus OM2n" . "Olympus")))
       (lens-list '(("Summilux-M 1:1.4/50 ASPH" . "50mm")
                      ("Summilux-M 1:1.4/35 ASPH FLE" . "35mm")
                      ("Zeiss Planar f/2.8 80mm" . "80mm")
                      ("Nikkor f/2.5 105mm" . "105mm)))
         (camera-choice (completing-read "Select Camera Model: " (mapcar #'car camera-list)))
         (lens-choice (completing-read "Select Lens: " (mapcar #'car lens-list)))
         (make (cdr (assoc camera-choice camera-list)))
         (focal-length (cdr (assoc lens-choice lens-list)))
         (files (dired-get-marked-files)))
    (dolist (file files)
      (shell-command (format "exiftool -Make=\"%s\" -Model=\"%s\" -LensModel=\"%s\" -FocalLength=\"%s\" \"%s\" -overwrite_original"
                             make camera-choice lens-choice focal-length file)))
    (revert-buffer))) ;; Refresh Dired buffer to reflect changes

I'm as skeptical as the next person about LLM use, but it's hard to argue with its efficacy for small tasks like this. I'm sure an expert in lisp could do better, but I'm not, and I didn't have to be one. This is a vast improvement over the way I used to do it and getting here saved me hours of fumbling around.

Permalink #

Wednesday, March 26, 2025

Black and white photo of burlap wrapped around trees

I knew it would happen, didn't you? I really don't want to talk about changing blog platforms, though. It's embarrassing. I'll just say that, while I don't love Hugo, it's the thing I'm least uncomfortable with overall. Let's move on, shall we?


Going slowly, making lots of little mistakes, and figuring out how things work is how you learn to solve tons of problems. AI platforms are creating a world where the solution to any problem is “more AI” and prompting.

Paul Ford, "Bad Vibes Coding"


Using the Obsidian Web Clipper with Denote

I was feeling envious of the Obsidian Web Clipper, which is quite fancy, so I thought I'd try leveraging it for use with Denote.

My first run at this involves a couple of steps:

  • Tweak the web clipper to save files using Denote's format and front matter
  • Save the file without adding it to an Obsidian vault
  • Move the saved file into my Denote folder

Here's the Web Clipper template configuration I ended up with:

It was important to set the "Tags" property type to "Text" rather than the default "Multitext" so that Denote does the right thing with it when renaming the file later.

In the Web Clipper's advanced settings, I set the behavior to "Save file..." rather than "Add to Obsidian".

OK, so now after using the Web Clipper, I get a Markdown file[1]with a (mostly) Denote-compatible file name and front matter in my ~/Downloads folder. Here's what clipping this post looks like:

To get the file into my denote-directory, I use a rule in Hazel. Hazel watches my Downloads folder for any new file whose name contains the string "__clipping", and automatically moves it into a "clippings" folder in my Denote folder.

The only manual step remaining is to finish renaming the files using Denote. I don't yet know how to have the Web Clipper "slugify" the file name, so I have Denote do it. This can be done in batch using Dired, so it's not a huge burden.

If there's a simpler way to get a nicely-formatted Org mode file from a web page directly to my Denote folder, I'm all ears, but for now...

Take that, Obsidian! 😄


  1. Denote handles Markdown files natively, so this is fine. ↩︎

Permalink #

Upgrading php to 8.3 on the (Ubuntu) server

I upgraded PHP to v8.3 (from 8.2) today on the server running baty.net. I don't pretend to be an Ubuntu sysadmin, so I'm writing it down, just in case.

    sudo apt update
    sudo apt install php8.3 php8.3-cli php8.3-{bz2,curl,mbstring,intl,gd,xml}
    sudo apt install php8.3-fpm
    sudo a2enconf php8.3-fpm        # enable it
    sudo vi /etc/caddy/Caddyfile    # replace socket path with 8.3
    sudo systemctl reload caddy
    sudo sudo a2disconf php8.2-fpm  # disable 8.2
    sudo apt purge php8.2*          # in fact, just delete 8.2

The site runs on Caddy, so I needed to change the path to the fpm socket. Here's the Kirby section of the Caddyfile...

    (kirby) {
        php_fastcgi unix//run/php/php8.3-fpm.sock
        @blocked {
            path *.txt *.md /content/* /site/* /kirby/* /.*
        }
        redir @blocked /
    }
Permalink #

Roll 204 (Hasselblad 500C/M)

I've not been shooting much film recently. Yesterday, I was bored and in a mood, so I grabbed the Hasselblad and fired off a roll using Alice as my model. Only one frame was good enough to share. I really like it, so it was worth sacrificing the other 11.

Alice
Permalink #

A change to my everything.rss feed

For a while, I tried maintaining a combined RSS feed that included posts from all my sundry blogs. I kept it at /everything.rss. It was managed as part of my WordPress blog, and since I've stopped using WordPress, I've been redirecting /everything.rss to the feed for baty.net, which is either /feed or /index.xml, depending on my blog platform of the day.

I think that instead of that, I'll piggyback off my @batybot account on Mastodon.social. I crosspost most stuff from my sites to @batybot via EchoFeed already, and Mastodon offers an rss feed for each account. Mine is https://mastodon.social/@batybot.rss.

Soon, I'll redirect requests from baty.net/everything.rss to https://mastodon.social/@batybot.rss. This doesn't offer full posts, but rather it's more like a firehose of links to everything I post. If you'd like to avoid that kind of noise, delete your subscription to /everything.rss. If you are a glutton for punishment, feel free to subscribe.

Permalink #

Five weeks with the Nikon Z f

Closeup of Nikon Z f camera dials
See that cool ISO dial? I never use it.

I bought the Nikon Z f thinking it would replace my Leica SL2, since the Nikon is lighter, newer, cheaper, and faster. While it is all of those things, it's still not better.

Here's what I like about the Z f:

  • The design is just the right amount of retro.
  • Autofocus is fast and accurate. Even in low light.
  • High ISOs are very usable.
  • The dials feel good.
  • The RAW files look good out of Capture One without much work.
  • It's nice having a flippy screen, even though it's the wrong style of flippy screen.
  • It's lighter than the SL2.

Here's what I don't love about it:

  • While smaller than the SL2, it's not a small camera.
  • The menus are too complex. I still can't find anything. Use a modern Leica for 10 minutes and you'll see what I mean.
  • The Auto ISO features confound me at every turn. So much so that I've set them once, and I never touch the nice, big, well-made dial for setting ISO.
  • There's no aperture dial on the made-for-the-Zf lenses. A huge miss. I find myself just keeping the mode set to "P" (for "Professional" right?).
  • Auto focus is fast and accurate, but the settings to make them fast and accurate require study. Too much study.
  • The battery/SD door is flimsy and horrible, and with the (almost mandatory) grip attached, I struggle to pull the card out.
  • I wish the dials worked like the Fuji system's dials. Yes, I know, these are more flexible, but if they don't make sense to me, I'm not using them.

If I sell the camera now, I'll lose my ass. But if I don't learn to like it more, the money might be better spent elsewhere, even at a loss.

Also, I haven't sold the SL2, yet.

Permalink #

Fixing the terrible scrolling behavior with Logitech MX Master on macOS

Scrolling with the Logitech MX Master in Safari sucks out of the box. The following from this Reddit thread helped, even though it required installing 2 additional packages.

Here’s the useful part of that thread:

Install Logitech Options+ (sigh) and set:

Logi Options+ (Plus): Customization App for Logitech Devices

What a gross bit of software, but it’s necessary here. I’ve read that once this process is done, I can delete the app completely, but I haven’t tried that yet.

  • Scrolling speed: 0% (as the OP says, this is the most important option to set).
  • Scroll direction: Standard (I would set it on Mos, but you have to pick one here anyway).
  • Smooth scrolling: Off (also good to turn off, Mos will take care of it instead).
  • SmartShift: On (If you want it).
  • Sensitivity value: 95% (we’ll see, maybe I’ll take it down to 90%).

Install Mos:

Mos | Smooth your mouse

brew install mos

(Note that launching Mos required xattr -d com.apple.quarantine Mos.app)

  • General > Smooth scrolling: On.
  • Advanced > Step: 75.00 (at least in my resolution, anything lower than this is just not enough of a scroll per ratchet movement).
  • Advanced > Speed: 3.50 (didn’t try too many others, but it seems to work in conjunction with the rest).
  • Advanced > Duration: 3.90 (default value, haven’t played around with it yet).
  • Now the ratchet action works as expected from a normal mouse, but when I give it a little nudge it goes into a free-spin and scrolls fast. I don’t know how much accuracy I’m getting with the free-spin yet, but to get to the bottom of a document, it’s great. I’ll update if I keep playing with these settings.

Once I’d done this, scrolling in the MX Master has been like butter.

Permalink #