Emacs Functions, Agate Upgrade (publ. 2024-08-21)

Preparing photos with Emacs; a.k.a, Emacs helps me do more in less time.

I've written around 100 elisp function in the last two years or so. Most of them are not functions that would be useful in a published code library or package, but just functions that save me time or otherwise provide some automation useful in my particular life circumstances. E.g., I've written code to automatically send out e-mail reminders to people each week; code to speed up my process for making gemlog posts; code that launches a gemipedia search; code that restarts system daemons; and various other little things perhaps not interesting enough to list out.

I suppose, as an ideal, it would be nice if all our coding produced mostly code that could easily be reused by others. But it is very easy and quick to write code in elisp if you are able to make a bunch of assumptions specific only to your life and needs, such as what file endings are involved, where you want files to go, and so forth. I'm interested in the idea of composing lots of small functions, with super-powerful combinators, but in practice the problem is usually easily reduced to 5 or 10 steps that can be represented as stateful function calls combined with LET assignments to variables.

My Nikon camera produces all its files in one format (JPEG) with one file extension (.JPG, uppercase) and one particular image geometry ratio. I found, nearly all of the time, that what I wanted to do with each photo was rename the files to one incrementing scheme of file names. Then I would make copies of the files at lower resolutions for the gemlog, one at 1920 width, to serve as the main image, and another at 128 width, to serve as a thumbnail. I was doing this fairly fast with Wdired and some on-the-fly macro driven editing, but it still took about 5 or 10 minutes and involved a lot of mental energy to get all the keystrokes correct. So recently I wrote this function to rename the files:

(defun rename-photos-for-post (title)
  (interactive "Mprefix: ")
  "The *.JPG files in current working directory are renamed to TITLE + \
\"_\" + an incremented counter number + \".jpg\""
  (interactive)
  (let ((counter 1))
    (dolist (file (directory-files "." nil "JPG$"))
      (rename-file
       file
       (concat title "_" (number-to-string counter) ".jpg"))
      (setq counter (1+ counter)))))

Usually the "title" I pick — actually "prefix" would have been a better name for that parameter — is something like the date (in YYYYMMDD format) and then the name of the place where the photos were taken, e.g., "tanana" or "yard".

And then this one to resize them:

(defun resize-photos-for-post ()
  "Uses \"convert\" utility on the *.jpg files in the current working \
directory to produce 1920x and 128x resolution copies. The originals \
are placed in a directory called \"originals\"."
  (interactive)
  (ignore-errors (mkdir "originals"))
  (message "resizing photos...")
  (dolist (file (directory-files "." nil "jpg$"))
    (let ((base (file-name-sans-extension file)))
      (call-process
       "convert" nil nil nil
       file "-resize" "1920" (concat base "_1920.jpg"))
      (call-process
       "convert" nil nil nil
       file "-resize" "128" (concat base "_128.jpg")))
    (rename-file file "originals/"))
  (message "done resizing photos"))

You can see how that could be generalize with more parameters and such like. But it reduced my workload down to two command calls which usually take about 10 seconds total to run, which was a big improvement.

Agate Upgrade

I was using the Agate gemini server when the Guix service broke about a year or so ago. The software package got upgraded in Guix but the associated service didn't, so the parameters weren't correct and the service couldn't run. That was pretty much the only thing that system was doing, though, so I just rolled back and kept the system frozen at that commit for a year. I suppose I could have reverted just those service and package definitions, with a local guix repo, but I didn't bother with that.

Recently some patches were submitted for that to debbugs (bug#72577). Since the patch included a base change-id, and Emacs has debbugs/gnus patching functionality built it, it was easy to apply those patches to a local guix repo. I tested out the patches first in a guix qemu VM and submitted some test reports via e-mail. Then I created a local guix repo on the server, applied the v3 version of the patches to that repo, and then rebuilt the system. It is working great, and I am back to serving gemini pages again, but with an up-to-date version of Agate. The old TLS keys didn't seem to be recognized so I generated new ones using the instructions given in the guix service documentation, and therefore you might have noticed my cert fingerprint changed recently.

Presumably those patches will get include in guix proper soon. But if not, then I'll just merge in the master branch occasionally, to keep the rest of the system up-to-date.

Copyright

This work © 2024 by Christopher Howard is licensed under Attribution-ShareAlike 4.0 International.

CC BY-SA 4.0 Deed