Today I Learned (TIL)
TIL stands for today I learned. This is a collection of small, interesting things I’ve learnt, which I thought were worth remembering and sharing with other people.
If you want to follow along, these posts have their own RSS feed.
The caret anchor (
^) matches differently in Python and RubyCollapsing whitespace in a Liquid template
Output an empty string with stripped whitespace, that is
{{- "" -}}.Python has a builtin tool to do rot13 (among other things)
Look in the codecs module.
The “MCP” in Archivematica stands for “Master Control Program”
It’s nothing to do with generative AI.
Get a list of values in a JSON object with jq
The equivalent to Python’s
dict.values()isjq '[.[]]'.The person who runs the Cambridge NTP servers has an excellent email address
The @ symbol was added to Morse code in 2004
It was added in May 2004, it’s the first new symbol since the Second World War, and the French have a cute name for it. The rest of Morse code has some surprising omissions.
My preferred options for SmartyPants in Python
smartypants.smartypants(…, Attr.default | Attr.u)Get the avatar URL for a Bluesky user
Make a request to the
app.bsky.actor.getProfileendpoint, passing their handle as theactorparameter.Looking up posts in the Bluesky API
Install the
atprotopackage, construct a client with your username/password, then call theget_post_threadmethod with yourat://URI.Using zipstream to stream new zip files to object storage with boto3
You can construct a
zipstream.ZipFile, add files, then wrap it in a file-like object to upload it withS3.upload_fileobj.Using Linode object storage and boto3
If you’re calling
put_object, you need the config optionrequest_checksum_calculation = "when_required".Disable HTTP Basic Auth for certain pages in Caddy
Define a matcher that negates the routes you want to be public, then use that with your
basic_authdirective.Group nodes in a Mermaid flowchart by putting them in a subgraph
Show a list of checkboxes in a WTForms form
Subclass
SelectMultipleFieldand override thewidgetandoption_widgetfields.Combine arrows in Mermaid by using an invisible node
Redacting sensitive information from gunicorn access logs
Create a subclass of
gunicorn.glogging.Logger, and redact information in theatoms()method.Listen for the
popstateevent to see when the user clicks the “back” buttonMore generally, it fires whenever the user is navigating the session history.
Python’s f-strings support
=for self-documenting expressionsThe f-string
f"{x=}"expands tof"x={x}".The error “No aggregated item, sequence was empty” comes from Jinja2
You get this error message if you try to use Jinja2’s filters to get the min/max of an empty sequence.
Go’s compiler is smart enough to spot division by zero errors
Print a comma-separated number in Python with
{num:,}You can use
{num:,}to insert a comma every three digits,{num:_}to insert an underscore every three digits, and{num:n}to insert a locale-aware digit separator.How do I find photos of a person on Flickr?
https://www.flickr.com/people/{path_identifier}/photosofHow does Flickr’s getLicenseHistory handle photos with no license changes?
When fixing mojibake, use
ftfy.fix_and_explain()to understand how it’s fixing a piece of textWhy isn’t
delete_where()deleting rows in sqlite-utils?The
delete_where()function doesn’t auto-commit, so you need to wrap itwith db.connor something else to trigger the commit.console.log()holds a reference to an object, not a copy of itWhen you view an array/object with
console.log(), you see the contents at the time you expand it, not as it existed when you calledconsole.log().How to get a macOS file/folder icon in Swift
Use
NSWorkspace.shared.iconto get the icon as anNSImage, then you can save it to disk or do something else with it.Create an animated placeholder box with CSS
What does Flickr return in the
flickr.photo.getSizesAPI for videos?The video’s owner will get the URL to the original video file as “Video Original”, otherwise you should look for the largest video size.
Getting and setting the cover image from an EPUB file
How to find the
content.opfin an EPUB fileRestricting routes to pre-approved IP addresses in Caddy
How to find the biggest files backed up by Backblaze
Look at the file
/Library./Backblaze.bzpkg /bzdata /bzfilelists /bigfilelist.dat Editing a filename in Finder will convert it to NFD
Even if the filename looks the same, it may be invisibly converted to a different sequence of bytes.
Creating a reverse proxy to a multi-site server with Caddy
You need to add Host headers and HTTPS configuration to your
reverse_proxyblock.How to get the target of an HTTP redirect with curl
What is the
author_namein the list of tags on a Flickr photo?When you call the
flickr.photos.getInfoAPI, each tag is attributed to an author. Theauthor_nameis their username, not their realname.How to get a user’s email address with the Flickr API
The
flickr.profile.getProfileAPI returns somebody’s email address, but only if you’re allowed to see it.HTML strings may not be equivalent if you minify them
There’s a lot of whitespace in HTML which looks irrelevant at first glance, but may be significant and cause the document to render differently.
How do the
ispublic,isfriendandisfamilyflags work in the Flickr API?How to get the expiry date of an HTTPS certificate with Python
Connect to the domain using the
socketmodule, then use thegetpeercert()method on the connection to get information about the HTTPS certificate.Create solid-colour image placeholders to show before an image loads
Get an image from a video with ffmpeg
Get the embedded artwork from an MP3 file
Use the command
eyeD3 [MP3_FILE] --write-images [FOLDER].Convert an animated GIF to an MP4 with ffmpeg
Using the Wikimedia Commons API to tell if a file has been deleted
How to get the selected item in Finder using AppleScript
Removing letterboxing from a video screenshot with ImageMagick
Using
-trimwill remove the black portions and leave you the unletterboxed image.How to highlight Python console sessions in Jekyll
Adding a couple of options to the
consolelexer (console?lang=python&prompt=>>>) gets you syntax highlighting for a Python console session.Get a Palette colour as a command-line argument with Clap
Wrapping a
Palette:Srgbin a struct and implementingFromStrfor the struct allows you to take hexadecimal colours as command-line inputs.How to get the filename/size without downloading a file in curl
You can do some fun stuff with the
--write-outflag and variables.How to count how many Discord messages were sent on a given day
Using the
Duringfilter gives me a count of how many messages were being sent.How to see the HTTP requests being made by pywikibot
To see exactly what HTTP requests were being made, I modified the library so that betamax would record requests.
How to embed an inline SVG in a CSS rule
Modern browsers allow you to embed the SVG almost as-is, with just a couple of characters that need escaping – no base64 required!
How to shuffle an array in a Jekyll template
If you want an array in random order, you can use the
samplefilter to get a random sample of the same size as the original array.Checking if a URL has changed when you fetch it over HTTP
When you make an HTTP request, you can use the
If-Modified-Sinceheader to get a 304 Not Modified if nothing has changed since your last request.Why is Pillow rotating my image when I save it?
Images can have orientation specified in their EXIF metadata, which isn’t preserved when you open and save an image with Pillow.
How to change the name of an internal link in an Obsidian table
Escaping the pipe like
[[filename\|display text]]allows you to customise the of a link in a table.Getting a boto3 Session for an IAM role using Python
Why I use Sessions in boto3, and the Python function I use to create them.
How much will Mastodon instances try to re-send messages?
Get my Netlify bandwidth usage from the API
How to restrict a page to specific IP addresses
How to parse URLs in JXA
How to check when an HTTPS certificate expires
What happens when you replace a photo on Flickr?
Use the
{% raw %}tag to describe Liquid in LiquidIf you’re trying to write about using Liquid tags in a Liquid-based site, wrapping your tags in the
{% raw %}tag will prevent them being rendered.What characters are allowed in titles on Wikimedia Commons?
How to do offline geo-lookups of IP addresses
MaxMind offer databases you can do to look up IP addresses without sending the address off to a remote service.
How to move files when you need sudo on the remote server
Use the
{% capture %}tag to assign complex strings to variablesIf you want to get a string that’s semi-complicated to construct, you can put a “mini-template” in the
{% capture %}tag to build it over multiple lines.WordPress URLs that get hammered by spammers
Manage MP3 metadata from iTunes with eyed3
How to create flag emojis for countries in Python
Use the IMAGE function to insert an image into a spreadsheet
Pausing the animation of <svg> elements can affect child <svg> elements differently in different browsers
Running the Netlify CLI in GitHub Actions
Get and manipulate the contents of a page in Safari with
"do JavaScript"SVGs are only rendered on GitHub if you use an
<img>that points to another fileAnimate an attribute of an element with <animate>
How to delete albums
Live Text is aware of how hyphenation works (kinda)
Go between M-IDs and filenames on Wikimedia Commons
Why I prefer XML to JSON in the Wikimedia Commons APIs
The XML-to-JSON conversion leads to some inconsistent behaviour, especially in corner cases of the API.
How to do resumable downloads with curl
Find files that use a particular SDC field
Why the term “snak” keeps appearing in the Wikidata API
The acronym “woe” in the Flickr API stands for “Where On Earth”
Use Unicode property escapes to detect emoji in JavaScript
Finding the original page for a post on Mastodon
Following the logged-out 302 Redirect takes you to the original post.
How to use hex colours with the palette crate
You can use
Srgb::from_str()to parse a hexadecimal string as a colour in the palette crate.Calley-ope (calliope) Syndrome is pronouncing a word wrong because you’ve only ever read it on the page
How do Dreamwidth posts IDs work?
They were deliberately non-sequential as an anti-spam technique. It’s no longer required, but it’s in the codebase now and hasn’t been changed since it was written.
DynamoDB: Conditional updates on nested fields
Using TransportAPI and geopy to get the distance between stations
The Content-Disposition header can be used to name a downloaded file
How to set the clock on a Horstmann Electronic 7 water heater
Why does Hypothesis try the same example three times before failing?
How to set the clock on a Tricity Bendix SIE454 electric cooker
How to set the clock on a Worcester 28CDi boiler
Get an RSS feed of external audio posts on Tumblr
If you add
/podcastto a Tumblr site, you get a podcast-like RSS feed for all the external audio posts on that site.