Categories
Uncategorized

Quake 3 Arena

2024, running native on a MacBook Air and the machine doesn’t even get warm to the touch. Awesome.

Head to https://ioquake3.org/ to get started.

Categories
Coffee recommendations

Asobu ceramic lined insulated mug

So years ago I discovered double wall glass mugs.

Nearly perfect but just too fragile, leading to lots of orders:

They are nearly ideal. Zero flavor retention, easy to clean, great for hot coffee and ice cold beer and tea and sparkling water. I get the 18oz version in two packs. Plus they insulate well so no condensation and I can savor.

But they break so damned easily. Which is why I’ve repurchased so many times.

A while ago the Wirecutter recommended a glass lined bottle from Purist and I bought one. It’s as promised but the shape is too deep to hand wash and the lid is impossible to clean internally. so off I went.

And yes I firmly believe that coffee flavor is best from a wide opening shape and glass or ceramic. Reddit agrees… mostly.

The main features I want are insulation, glass or ceramic lining and large at 16oz or so. Two full cups from my French press. I found this Asobu:

It’s… excellent. Super slick coating, insulated well, a breeze to clean, coffee tastes great. Nice and wide so the aromas are good.

The shape is a lot like my Yeti that I still have.

And Yeti does have ceramic lined mugs now, but only 4 and 6 ounce:

The Asobu is very well made:

I’ve had it a few days, rigorously testing with coffee, tea, sparkling water, beer, mint tea and it’s great. Super slick ceramic, nice cork, wide and stable, good value at $30. Worthy of my YouShouldBuy category!

Asobu White Infinite Mug, 16oz.

Categories
Watches

Farer Resolute II 36mm

Sometimes you buy a watch because it’s just right. Proportions, dimensions, luminosity, legibility, price, movement, style. This one preoccupied me for a couple of months and arrived last week.

Really enjoying wearing it.

Downsides so far – the lumed numerals blur in the dark into blobs, so the initial legibility decreases a bit. I miss having a date available. Since it has unidirectional winding, there’s noticeable rotor spin that you can feel and hear.

Overall strong positive. At 36 by 10.8, it’s super comfortable. I love the design and style. Legibility is excellent as is timekeeping. At 1100 with bracelet (always buy the bracelet!) the value is good for a Swiss made watch this well detailed and finished.

There’s a larger 38mm version, but for me, with the all-dial case, 36 is perfectly sized.

Farer page is here. No relationship, just a happy customer.

Categories
climate EVlife

The electrical cost of gasoline is 8.6kWh

A friend of mine did an interesting bit of research and data gathering that I’ve not seen elsewhere and I thought I’d share here.

If you read about energy and markets, you might have read about EROEI: Energy return on energy invested. E.g: It might take 20 gallons of oil to extract a 55g barrel of oil.

So what’s the energy cost to refine a gallon of gasoline?

To get an answer, my friend found the government page showing the energy used by “Petroleum Administrative for Defense District 5. Basically, west-coast refineries.”. It’s here. A snapshot graph:

Next, you need to know how much they refined (oil in, gasoline etc out). That’s here. And the refining capacity is here.

If you do the math (to tip my hat to a scientist I admire), the result is 8.6kWh/gallon. To get that number, you

  • take the annual electricity purchased by the refinery (X)
  • Calculate the proportion of gasoline vs total refined output (Y) (19.45 gallons gas per 44.77 gallons refined output)
  • Divide X/Y

That’s more than I would have guessed. Our 2018 Chevrolet Bolt EV holds about 60kWh and can drive around 180 miles, by way of comparison. So the refining energy could power an average EV sedan 34 miles. Which is higher than the average EPA mileage of a comparable ICE sedan.

Food for thought. As my friend put it, “charging an EV will always require less energy than an equivalent gasoline powered vehicle, and would always be cheaper for the end user if not for subsidies to the petroleum industry.”

Categories
Uncategorized

WordPress and self-hosted sites broken on iOS

If you run your own self-hosted WordPress and would like to, you know, blog now on it, you too may have gotten the maddening error “Unable to read the WordPress site on that URL”

This, though their help page does not tell you, is a filthy lie. Do the following whilst cursing their late-stage-capitalist bastard hearts:

Append “/xmlrpc.php” to the URL. That’s all that it takes.

So example.com becomes example.com/xmlrpc.php

Of course, this is only broken on self-hosted sites. Bastards, like I said.

Categories
Computer science programming

Whisper and WhisperX for podcast transcription

I just realized that I hadn’t posted this. Several months ago, I read about whisper.cpp and started playing with it. To quote from their docs, whisper.cpp is a

High-performance inference of OpenAI’s Whisper automatic speech recognition (ASR) model:

  • Plain C/C++ implementation without dependencies
  • Apple Silicon first-class citizen – optimized via ARM NEON, Accelerate framework, Metal and Core ML
https://github.com/ggerganov/whisper.cpp

In other words, a fast and free speech transcription app that runs on your laptop. Damn!

In fact, it’s so efficiently written that you can transcribe on your iOS phone. Or browser. Haven’t tried those yet.

Anyway, that gave me an idea: a couple of friends of mine run a podcast called TGN. They’ve been at it for a few years, and have around 250 episodes of an hour each. Could I use whisper.cpp to produce a complete set of episode transcripts? If I did, would that be useful?

(Insert a few months of side project hacking, nights and weekends.)

It works, pretty well. For podcasts, however, you end up with a wall of text because Whisper doesn’t do what’s called ‘speaker diarization,’ that is, identifying one voice or another. It’s on their roadmap, though.

I was sharing the progress on the TGN slack when an employee of the company OctoML DM’d me. They have a WhisperX image that does diarization, and he offered to help me use it for the project.

(More nights and weekends. Me finding bugs for OctoML. Adding a second podcast. Getting help from a couple of friends, including the a-ha mkdocs idea from David.)

Voila! May I present:

The key useful bits include

  • Full text searching
  • Local mirrored copies of the podcast MP3, raw transcript text and (in progress attempts) to mirror the episode web page.
  • Using mkdocs to build static websites that look OK, and can render Markdown into HTML.

Lots of features yet to build but it’s been a really fun side project. Source code is all on GitHub, right now I’m in the prefect branch, trying out a workflow rewrite using Prefect.

Categories
Aphorisms

For a friend who just got laid off

41. If you do everything for one reason, then all you have done will be become meaningless when the reason does.

James Richardson, Vectors: Aphorisms and Ten-Second Essays

Categories
Aphorisms

Richardson, au courant

26.
The tyrant’s self-esteem is just fine, thank you. It’s you he
doesn’t care much for. And yes, he recognizes that he doesn’t
feel what you feel. Which is a good thing, since your feeling is
so weak that it makes him need to beat you up.

James Richardson, Vectors 3.0: Even More Aphorisms and Ten-Second Essays

Categories
programming

Internet manners – download if newer

If you’re a developer, sooner or later you’ll need to poll a website or URL, looking for information. There are good and bad uses of this, (looking at you, Ticketmaster and scalpers) and I want to be good. (This was inspired by reading Rachel’s post about her rate limiter.)

As part of my podcast speech-to-text project I am downloading a chunk of XML from their RSS feeds. These are commercial and can handle lots of traffic, but just the same why not be smart and polite about it? My goal is to have a cron job polling for new episodes, and I don’t want to cost them excess hosting and traffic fees.

The HTTP spec includes a header called Last-Modified, so your first thought might be:

  • Use the HTTP ‘head’ verb to only get metadata
  • Check the Last-Modified header to see if its newer

This will not work. ‘HEAD’ doesn’t include Last-Modified. Instead, you need the ‘ETag’ header! It’s roughly (see that link for details) a file hash, so if the RSS updates the ETag should as well. Simply save the ETag to disk and compare the version returned in the ‘HEAD’ metadata. Fast, polite, simple. Here’s the Python version from the project:

def podcast_updated(podcast: Podcast) -> bool:
    # Based on our saved last-updated time, are there new episodes? If not, don't
    # hammer their server. Internet manners. Method - call HEAD instead of GET
    # Note that HEAD doesn't include a timestamp, but does include the cache ETag, so
    # we simply snapshot the etag to disk and see if it differs.
    filename = podcast.name + '-timestamp.txt'
    try:
        r = requests.head(podcast.rss_url)
        url_etag = r.headers['ETag']
        file_etag = open(filename, 'r').read()

        if file_etag == url_etag:
            log.info(f'No new episodes found in podcast {podcast.name}')
            return False
    except FileNotFoundError:
        log.warning(f'File {filename} not found, creating.')

    open(filename, 'w').write(url_etag)
    return True

It adds a local file per URL, which is a bit messy and I need to rework the code a bit, but it’s working and runs quite fast.

Another idea would be to try the requests-cache module, which does this plus local caching of content. I’ve read their docs but not tried it yet.

P.S. Yes, I also shared this on StackOverflow. 😉

Categories
Uncategorized

Goddamn WordPress

So I pay for WordPress to host this blog. Money well spent at 48/year. I also run a private blog. The WordPress iOS app as well as their new Jetpack app both refuse to log into the self hosted instance.

Why? I’m guessing fuck you, pay me. The BlogPost app kind of works but I need to work on its image uploading.

Had to rant. Guessing there are lots of others in this predicament.