notes by alifeeeprofile picturerss

return to notes / blog / website / weeknotes / linktree

here I may post some short, text-only notes, mostly about programming. source code.

tags: all (58), scripting (23), linux (6), jq (5), android (4), bash (4), geojson (4), obsidian (4), github (3), html (3) ............ see all (+88)

guestbook!

show all /
sign book

opening a remote SQLite file in DBeaver using sshfs#prevsinglenexttop

2025-10-11 • tags: sqlite, dbeaver, sshfs, ssh, linux • 140 'words', 42 secs @ 200wpm

DBeaver is a database management program. SQLite is a database format which uses a single file (e.g., database.sqlite). You can open .sqlite files in DBeaver, but only on your local computer.

I wanted to open an .sqlite file on a remote server, without downloading it every time. I found out about sshfs ("SSH FileSystem") which mounts a remote filesystem on your local filesystem, so you can pretend the remote .mysql file is a file on your computer.

I set up sshfs like so:

sudo apt install sshfs
sudo mkdir -p /media/alifeee/remotefiles
sudo chown alifeee:alifeee /media/alifeee/remotefiles
sshfs server:/usr/alifeee/ /media/alifeee/remotefiles

Now /media/alifeee/remotefiles appears in my file browser just like any other drive I would plug into my computer. Neat. Who needs FTP… ;]

back to top

assembling the PiBow Mini, a small Macro pad#prevsinglenexttop

2025-09-14 • tags: hardware, keyboards, raspberry-pi, scripting • 618 'words', 3.1 mins @ 200wpm

What is it

I picked up a Keybow Mini from Sheffield Hackspace a few weeks ago, which is a small 3-key mechanical keyboard or "macro pad".

It had been donated to the hackspace by Pimoroni; I also picked up a donated Pi Zero and a lying 1024GB SD card I'd picked up a few weeks ago, and assembled it.

Assembly

Unfortunately, this is a text only-blog. I assure you that the pictures of me putting keycaps and circuitboards together are incredibly riveting — but you'll just have to imagine.

end result

After following the assembly guide and the creating macros guide, I had a little 3-key keyboard which could increase, decrease, or mute my volume (via media keys). I wanted to have more options, so I wrote a little layout in Lua in which the left button switches "layout", and the other two buttons do different actions based on which layout is currently enabled. The keys I started with are:

…where the latter two groups are from the 'expanded function key set'.

AutoKey

It works well! I can use the function keys to run macros with AutoKey. For example, here's a script which prints the current date:

output = system.exec_command("date '+%Y-%m-%d'")
keyboard.send_keys(output)

Firmware

Here's the Lua script for what I described. I think it's pretty readable.

require "keybow"

-- do loads of things --
--   left button switches between mode
--   do not use F13 as by default it opens settings
-- red: media controller
-- blue: send F15 and F16
-- green: send F17 and F18

Kbsetup = 0
TotKbSetups = 3

function setup()
    keybow.use_mini()
    keybow.auto_lights(false)
    keybow.clear_lights()
    keybow.set_pixel(0, 255, 0, 0)
    keybow.set_pixel(1, 255, 0, 0)
    keybow.set_pixel(2, 255, 0, 0)
end

-- left key
function handle_minikey_02(pressed)
    if (pressed) then
        Kbsetup = (Kbsetup + 1) % TotKbSetups
    end
    if (Kbsetup == 0) then
        -- print("setup 1")
        keybow.set_pixel(0, 255, 0, 0)
        keybow.set_pixel(1, 255, 0, 0)
        keybow.set_pixel(2, 255, 0, 0)
    elseif (Kbsetup == 1) then
        -- print("setup 2")
        keybow.set_pixel(0, 0, 255, 0)
        keybow.set_pixel(1, 0, 255, 0)
        keybow.set_pixel(2, 0, 255, 0)
    elseif (Kbsetup == 2) then
        -- print("setup 3")
        keybow.set_pixel(0, 0, 0, 255)
        keybow.set_pixel(1, 0, 0, 255)
        keybow.set_pixel(2, 0, 0, 255)
    end
end

-- middle key
function handle_minikey_01(pressed)
    if Kbsetup == 0 then
        keybow.set_media_key(keybow.MEDIA_VOL_DOWN, pressed)
    elseif Kbsetup == 1 then
        keybow.set_key(keybow.F15, pressed)
    elseif Kbsetup == 2 then
        keybow.set_key(keybow.F17, pressed)
    end
end

-- right key
function handle_minikey_00(pressed)
    if Kbsetup == 0 then
        keybow.set_media_key(keybow.MEDIA_VOL_UP, pressed)
    elseif Kbsetup == 1 then
        keybow.set_key(keybow.F16, pressed)
    elseif Kbsetup == 2 then
        keybow.set_key(keybow.F17, pressed)
    end
end

Final notes

The only annoying thing is that to reprogram the PiBow Mini, you've got to unplug it, remove the SD card, plug it into a laptop (in my case as only my laptop has an SD reader), copy the new Lua files over, unplug the SD card, plug it in, test the new code, and repeat if it doesn't work as intended.

That's why I opted to send function keys, which I can turn into hotkeys using AutoKey, then I only have to change a Python script, and not redo a whole device firmware.

But, it's pretty neat!

back to top

Plurality in Top Hat and The Zero Theorem#prevsinglenexttop

2025-09-11 • tags: plurality, films • 210 'words', 63 secs @ 200wpm

Plurality is an interesting state of being. The Plurality Hub describes it as "[…] at it's core, when multiple people inhabit one body."

I've chatted to a few plural people, mainly via Discord. So, I always find it interesting to see portrayals of it in film.

Yesterday I watched The Zero Theorem (2013). It was meh, but the main character Qohen Leth (Christoph Waltz) was plural — it wasn't really talked about apart from being expressed as being weird by other characters. It felt a bit like it was just there to make Qohen seem weird to the audience.

The more interesting film I watched a while ago was Top Hat, a 1935 Ginger Rogers & Fred Astaire film about complications in a hotel — there was a character Bates (Eric Blore) who was plural, and it wasn't really played for laughs. Everyone seemed to accept it without questioning it, and I remember finding it interesting that was the case.

Anyway, let me know if you watch anything else with plural characters. Ideally not where they are only plural because they're "insane" or supposed to be weird.

back to top

how to convince someone to not use AI art for event promotion#prevsinglenexttop

2025-09-01 • tags: ai, ai-art, linkdump • 2053 'words', 10.3 mins @ 200wpm

I was asked the question:

I wanted something a bit more "evidenced" than "AI is for losers" (my usual response), so the below is compiled from that search.

Mastodon

"what will gay bars do if they can't rely on cheap ai images to promote their events"

our parties thrived in the "worst photoshop you've ever seen" era of gay flyers, mama let's just return to tradition

Pup Harke

Blog Posts

It's embarrassing, destructive, and looks like shit: AI-generated art is the perfect aesthetic form for the far right.

Tommy Robinson tweets an image of soldiers walking into the ocean on D-Day. Britain First’s co-leader produces imagery of Muslim men laughing at sad white girls on public transport. An AI-generated song combining…

[...]

– Gareth Watkins, AI: The New Aesthetics of Fascism

Pluralistic

I often find Cory Doctorow has good opinions. A lot of his blog posts are mainly about ethics & copyright rather than "disgust", but are still relevant. I found most of these by searching site:https://pluralistic.net/ ai art on Kagi

Herein lies the problem with AI art. Just like with a law school letter of reference generated from three bullet points, the prompt given to an AI to produce creative writing or an image is the sum total of the communicative intent infused into the work. The prompter has a big, numinous, irreducible feeling and they want to infuse it into a work in order to materialize versions of that feeling in your mind and mine. When they deliver a single line's worth of description into the prompt box, then – by definition – that's the only part that carries any communicative freight. The AI has taken one sentence's worth of actual communication intended to convey the big, numinous, irreducible feeling and diluted it amongst a thousand brushtrokes or 10,000 words. I think this is what we mean when we say AI art is soul-less and sterile.

– Cory Doctorow, Why I don't like AI art (25 Mar 2025)

this one is more like useful context why AI is overhyped and "bad, actually".

The AI sector is utterly dependent on criti-hype. They are burning tens of billions of dollars on engineering salaries, custom chip fabs, human data annotation, data-center rents, racks and racks of GPUs and ASICs, whole gridsworth of electricity and entire aquifers’ worth of fresh water for cooling.

They are hemorrhaging a river of cash, but that river’s source is an ocean-sized reservoir of even more cash.

To keep that reservoir full, the AI industry needs to convince fresh rounds of “investors” to give them hundreds of billions of dollars on the promise of a multi-trillion-dollar payoff.

– Cory Doctorow, How the Writers Guild sunk AI’s ship

…more opinions…

Having lived through that era, I'm prepared to believe that maybe I'll look back on AI "art" and say, "damn, I can't believe I never thought that could be real art."

But I wouldn't give odds on it.

I don't like AI art. I find it anodyne, boring. As Henry Farrell writes, it's uncanny, and not in a good way

– Cory Doctorow, AI "art" and uncanniness (13 May 2024)

…and some about the incredible ethics of AI companies

There is no subject on which AI companies have been more consistently, flagrantly, grotesquely dishonest than training data. When it comes to getting more data, AI companies will lie, cheat and steal in ways that would seem hacky if you wrote them into fiction, like they were pulp-novel dope fiends.

When an AI company tells you it won't use your intimate secrets as training data, they are lying. Of course they're lying! This isn't just any data, it's data that isn't replicated elsewhere on the internet. It's rare – it's unique. It's a competitive advantage. AI companies will 100%, without exception, totally use your private therapy data as training data.

[...]

These companies lie all the time about everything, but the thing they lie most about is how they handle sensitive data. It's wild that anyone has to be reminded of this. Letting AI companies handle your sensitive data is like turning arsonists loose in your library with a can of gasoline, a book of matches, and a pinky-promise that this time, they won't set anything on fire.

– Cory Doctorow, from Anyone who trusts an AI therapist needs their head examined (01 Apr 2025)

Linked

The following are linked from Cory's blogs above

LLMs are eerie, then, in a specific and technical sense of that term. The late Mark Fisher wrote an influential book, where he distinguished between the “weird” and the “eerie.” He had an easier time pinning down the weird, because it has a longer tradition and current debate around it. The weird is “that which does not belong,” encompassing both Lovecraftian horrors and natural phenomena like black holes.

The eerie is harder to pin down.

A sense of the eerie seldom clings to enclosed and inhabited domestic spaces; we find the eerie more readily in landscapes partially emptied of the human. What happened to produce these ruins, this disappearance? What kind of entity was involved? What kind of thing was it that emitted such an eerie cry? As we can see from these examples, the eerie is fundamentally tied up with questions of agency. What kind of agent is acting here? Is there an agent at all?

This captures the specific uncanniness of LLMs and LLM art. LLM art is so disturbing because it is culture that has been drained of all direct intentionality. Just like the movements of the planchette, it is a by-product of collective agency, without itself being an agent. A void has been created, and something disturbing appears to have crept in.

The sensation of the eerie occurs either when there is something present where there should be nothing, or is there is nothing present when there should be something.

– Henry Farrell, Large Language Models are Uncanny

this one is more about copyright

Most importantly, the tool itself is just data; SD 1.0 was about 4.2GiB of floating-point numbers, I believe. I’m currently using (literally, right now!) another open model, Whisper, which is 3GiB, and allows me to convert most spoken audio into text, and even translate it. I use it to, securely and privately, transcribe what I’m saying to myself through the day.

– Oblomovka, On Stable Diffusion

mainly from searching using ai art for local indie event posters on Kagi.

reddit

There are lots of opinions (albeit Reddit opinions) on

Some include:

This is very NOT DIY or anti-consumerism

boooo!!!!

I would boycott that place.

It’s not punk to fuck around with AI

Yea it’s sucky and I’m tired of it. I noticed it’s the older bands who do it

What the absolute fuck?!? If they keep this bullshit up, I sincerely hope they go out of business.

Boycott. Dont show up to those shows and encourage others to do the same

Cause nothing says support local artists/bands than asking billionaire owned ai to make art for you, I would rather go to a venue that has shitty looking art for flyers than one that has ai “art”

I hate AI, it’s making people so lazy and it’ll be the death of creativity

I 100% call out places that do this. Absolutely chases away anyone with taste.

Ah dont worry about it, if they are at the point of using AI, they are probably going broke

basschat

Comments from Gig posters using AI on the Basschat forum.

Thinking about using AI to generate photos that can be used in band posters. Does anyone have any experience, advice, warnings, threats?

Do you not have an artistic friend you could slip a few quid to to knock one up? This sort of thing has a "thin end of the wedge" vibe about it.

NPR

Comments from *Opinion: Art fair flyers should showcase human creativity*.

"Shame on you," an Instagram user commented. "You exist because of artists and yet you insist on stealing from and subjugating them…"

Pablo Picasso, by the way, made paintings and lithographs to promote art fairs. Maybe the folks at Oakland's First Fridays could have taken one of those and just made a few "significant adjustments."

mainly found via searching ai art on https://marginalia-search.com/.

IA.net

This article is actually trying to explain to copywriters (etc.) how they should use AI images, by showing them how they shouldn't

AI images might look technically appealing at first sight, but they fall apart on closer inspection: AI doesn’t know what it does. If you don’t curate your prompts like Shakespeare wrote his sonnets, you’ll end up with images that don’t say anything but: “I used AI to add color.”

– Unknown, AI Art is The New Stock Image: Critique of the pure AI image

mainly found via searching public perception of ai art on Kagi

Corrall Design

AI will also amplify any inherent bias in its training dataset. For example, if a model is trained on a police database and told to suggest jail sentences in a courtroom - something which is already happening in the US - it will have inherited any racial bias that was present in the records of arrests, and be more likely for example, to suggest harsher sentences for black defendants. Famously too, if one prompts Dall-E with the word ‘CEO,’ it will only produce images of white men.

[...]

“Generative A.I. art is vampirical - feasting on past generations of artwork even as it sucks the lifeblood from living artists. Over time, this will impoverish our visual culture.”

– Matt Corrall, The harm & hypocrisy of AI art

National Library of Medicine (NIH)

Quotes from a research article: Eyes can tell: Assessment of implicit attitudes toward AI art by Yizhen Zhou, Hideaki Kawabata:

[The] results suggest that a negative bias may exist toward [AI-generated artworks]

[...] although it was difficult for individuals to identify AI-generated artwork, they exhibited an implicit prejudice against AI art

Computers in Human Behaviour

Quotes from Defending humankind: Anthropocentric bias in the appreciation of AI art by Kobe Millet, Florian Buehler, Guanzhong Du, Michail D. Kokkoris:

Four experiments [...] consistently reveal a pervasive bias against AI-made artworks

The same artwork is preferred less when labeled as AI-made [...] and subsequently induces less awe

These effects are more pronounced among people [...] who believe that creativity is a uniquely human characteristic

Conclusions

I summarise a lot of the above to the opinions:

…or, put more succinctly:

back to top

parsing ical files using awk#prevsinglenexttop

2025-08-24 • tags: ics, awk, jq, scripting • 450 'words', 135 secs @ 200wpm

I've been interested in "doing something" with the ical format for a while, as it's quite a simple format, but can be shared easily to create events in other people's calendars.

Here is an example of an ical event, from the wikipedia page

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTAMP:19970701T100000Z
DTSTART:19970714T170000Z
DTEND:19970715T040000Z
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR

As you can see, it's fairly human-readable. You can see a description of the event as SUMMARY, and a start/end date-time as DTSTART/DTEND. You can imagine writing a file like this manually (though probably don't start doing that).

As for parsing them, you can use awk pretty well. Create a file called parse_ics.awk a bit like this:

# run with:
#   awk -F':' -f parse_ics.awk
{sub("\r$", "")} # remove terrible line endings
$1=="UID"{UID=$2}
$1=="DTSTART"{DTSTART=$2}
$1=="DTEND"{DTEND=$2}
$1=="SUMMARY"{SUMMARY=$2}
$1=="GEO"{GEO=$2}
$1=="END" && $2=="VEVENT"{
  # parsing date format to timestamp
  datespec_fmt = "\\1 \\2 \\3 \\4 \\5 \\6"
  start_ts = mktime(gensub(/(....)(..)(..)T(..)(..)(..)Z/, datespec_fmt, 1, DTSTART))
  end_ts = mktime(gensub(/(....)(..)(..)T(..)(..)(..)Z/, datespec_fmt, 1, DTEND))
  # output
  printf "%s\n", SUMMARY
  printf "  %s – %s\n", strftime("%a %b %d %Y @ %H:%M", start_ts), strftime("%a %b %d %Y @ %H:%M", end_ts)
}

Save the example event above as event.ics and you can parse it with:

$ cat event.ics | awk -F':' -f parse_ics.awk
Bastille Day Party
  Mon Jul 14 1997 @ 17:00 – Tue Jul 15 1997 @ 04:00

If you want to do something more… machiney… you could change the output to be more machine-readable (i.e., JSON) by changing the printing section in awk, e.g., to…

printf "{"
printf "\"SUMMARY\": \"%s\",", SUMMARY
printf "\"START_TS\": %i,", start_ts
printf "\"END_TS\": %s", end_ts
printf "}"

…which you can then use in jq or elsewhere that uses json:

$ cat event.ics | awk -F':' -f parse_ics.awk | jq
{
  "SUMMARY": "Bastille Day Party",
  "START_TS": 868896000,
  "END_TS": 868935600
}

So… if someone publishes their event as an .ics file… you can do some nice scripting with it!

For example, I created a script which parses the Sheffield United football fixtures and sends a message on Discord whenver there is one coming up later in the day (as Sheffield Hackspace is near the football ground so it affects parking for car-brains).

back to top

jailbreaking your kindle and installing KOReader#prevsinglenexttop

2025-08-20 • tags: kindle, koreader, jailbreaking • 957 'words', 4.8 mins @ 200wpm

Here's how I jailbreak kindles and install custom e-reader software (KOReader).

Why?

Once done, your e-books become files (detached from the demon of DRM) that you can share between your devices, download from anywhere, and from which your access can't be revoked by a higher corporate power until you start paying for the new subscription that you didn't used to need to pay for.

Also, more simply: don't sell me hardware and then tell me I can't install my own software.

My favourite Kindle to jailbreak

The kindle that I've jailbroken most often is the Kindle 4 from 2011 (the grey one, with buttons, without a touchscreen, without a backlight). I like this one because I don't want a fancy device. I want to read e-books with few distractions. I don't like the idea of a touchscreen (to be fair, I've not tried one), neither do I want a backlight, or I'd just read on my phone, laptop, or PC — the e-ink is the whole appeal to me!

I also like it because you can find loads of them on eBay for £15–20.

Required Downloads

(This section will probably become out of date)

Several pages exist where I download software to put on the Kindle. These are on:

A. Amazon updates page: https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=GKMQC26VQQMM8XSW
B. Tools Snapshots on the MobileRead Forum: https://www.mobileread.com/forums/showthread.php?t=225030
C. Updated Keystore on the MobileRead Forum: https://www.mobileread.com/forums/showpost.php?p=4506164&postcount=1295
D. RenameOTABin on the MobileRead Forum: https://www.mobileread.com/forums/showpost.php?p=4076733&postcount=25
E. KOReader Installation Guide: https://github.com/koreader/koreader/wiki/Installation-on-Kindle-devices

Installation Instructions

The installation is fairly easy if you use the right files, as the Kindle appears as a USB storage device when you plug it into your computer — so the general way I found to install things was to: read the readme.txt; copy over the files (usually listed in the readme.txt) to the Kindle; unplug the Kindle; go into settings and press Update Your Kindle. Most of the "installations" below are done either this way, or just by placing file(s) on the Kindle from the computer.

There are also (better, up-to-date) instructions on https://kindlemodding.org/ or https://wiki.mobileread.com/wiki/Kindle4NTHacking, but my instructions are:

these are specific to the Kindle 4, my setup, and might be out of date

  1. Update the Kindle to the latest firmware (download link A)
    (I have had problems with developer keys being untrusted without doing this)
  2. Turn on Aeroplane mode and restart Kindle
    (again, I've had problems without this step)
  3. Jailbreak Kindle (download link B) by placing files in Kindle and following README instructions to enable "diagnostic reboot"
    (I like this step because people have made some cute "your kindle is jailbroken" graphics that show)
  4. Install Kindle MKK (download link B) by placing the install file on the kindle and starting a software update
  5. Install the new Kindle MKK 2025 hotfix (download link C) in the same way
  6. Install KUAL (download link B) by placing KUAL-KDK-1.0.azw2 in the documents folder (then check you can open it)
  7. Install RenameOTABin (download link D) by placing folder in the extensions folder and then activating it via the KUAL menu
    this is to disable "over-the-air" updates. in case Amazon pushes an update which breaks things – we disable the downloading of it
  8. Install KOReader (download link E) and open it with KUAL.
  9. Done!

Using the Krindle

KOReader has a lot more features than the default Kindle reader, and is a lot more user-customisable. But the important question is how to put books on it.

The two ways I've found are to either:

Acquiring Books

Now that you're not locked in to Amazon's ecosystem, you don't have to buy all your e-books from the Amazon store (great!).

There are plenty of options of where to get e-books on the internet, including:

Conclusion

I like reading books (I also like tracking what I read – which you can follow with Mastodon!).

I think physical books are great, but with my purchasing rules (generally sticking to charity shops & local shops), it's hard to get specific books without ordering them online.

The Krindle fills that niche and lets me read (mostly) any book I find out about.

Pretty nice, if you ask me.

back to top

jumping to column N in Libreoffice Calc with AutoKey#prevsinglenexttop

2025-08-19 • tags: libreoffice, calc, shortcuts, hotkeys, scripting • 281 'words', 84 secs @ 200wpm

I am a director of Sheffield Hackspace and part of my role is to keep track of the membership.

It's currently via a spreadsheet where the membership payments come via bank transactions, and I match them up to the sheet. This involves a lot of finding names with "CTRL+F", and then changing a specific column.

I'd like to be able to "jump to column N", but I couldn't find an appropriate shortcut (I would love something like "Alt" then press "N", but alas).

After some web-searching, I found AutoKey, a Linux program that sounds like a colder version of AutoHotKey. I installed it, and it worked great. I'd tried to use xdotool to send key commands before, but it didn't work when set as a keyboard shortcut.

What I wanted to do using the keyboard was:

After reading the the documentation, I figured a script to do this:

import time
keyboard.send_keys("<ctrl>+<shift>+T")
time.sleep(0.25)
keyboard.send_keys("<left>")
keyboard.send_keys("<shift>+N")
keyboard.send_key("<delete>")
keyboard.send_key("<enter>")

(the 0.25 second wait is to let LibreOffice Calc recognise the shortcut and move the cursor to the Name Box)

…and used the GUI to set the script to run whenever I typed "Ctrl+F8".

It worked great :]

I see myself using this program more into the future.

back to top

using a single curl request to get headers and content at the same time#prevsinglenexttop

2025-07-15 • tags: scripting, curl • 283 'words', 85 secs @ 200wpm

I often make curl requests. I often want to see the HTTP headers and also the content.

Most of the time, you can just add -i or --include to include the headers in the printout

curl -i https://alifeee.co.uk/

In writing this (and looking at man curl), you can also use -v or --verbose to view the headers.

But, if you want to download both the headers and the content in one request (e.g., for a particularly large file or a server you don't want to hammer), you can use a script like this:

# customisation
url="https://alifeee.co.uk/"
file="alifeee.html"
filenom="${file%.*}"
fileext="${file#*.}"

# request
curl -i -o "${filepath}" "${url}"

# get index of first blank line
blank=$(cat "${filepath}" | awk '/^\r?$/ {print NR; exit}')
# cut file up to first blank line
head -n "$(($blank - 1))" "${filepath}" > "${filenom}_HEADERS.txt"
# cut file after first blank line
tail -n "+$(($blank + 1))" "${filepath}" > "${filenom}_RESPONSE.${fileext}"

…and view the results like this…

$ ll
total 108K
-rw-rw-r--  1 alifeee alifeee  620 Jul 15 16:27 alifeee_HEADERS.txt
-rw-rw-r--  1 alifeee alifeee  27K Jul 15 16:27 alifeee.html
-rw-rw-r--  1 alifeee alifeee  26K Jul 15 16:27 alifeee_RESPONSE.html

$ cat "${filenom}_HEADERS.txt"
HTTP/2 200
server: GitHub.com
content-type: text/html; charset=utf-8
last-modified: Wed, 25 Jun 2025 11:17:22 GMT
access-control-allow-origin: *
etag: "685bdac2-66b0"
expires: Tue, 15 Jul 2025 13:26:55 GMT
cache-control: max-age=600
age: 96
date: Tue, 15 Jul 2025 15:27:43 GMT

$ file "${filenom}_RESPONSE.${fileext}"
alifeee_RESPONSE.html: HTML document, Unicode text, UTF-8 text
back to top

automating the turning on and off of my Minecraft server#prevsinglenexttop

2025-06-10 • tags: minecraft, scripting, tmux, cron, nginx • 1112 'words', 5.6 mins @ 200wpm

I run a Minecraft server weekly on Tuesdays. Sometimes, I even play on it.

This describes automating the process for turning it on and off. Won't somebody at https://ggservers.com/ please hire me /jk.

The process

Turning it on

My process every Tuesday to turn on the server has been:

Turning it off

Then, on Wednesday mornings (if I remember), I:

The problems

Each of these steps can take a few seconds to run, so I am often multitasking, and I often forget things (like forgetting the backup, forgetting to actually run shutdown after all is done).

So, I've tried to automate it.

Doing it automatically

I found out that Kamatera (the server host) has an API that you can use to remotely turn on/off servers, which is the only thing that I was really missing.

cron tasks - web server

Here are the cron tasks on my web server:

# turn Minecraft server server on/off
45 16 * * 2 /home/alifeee/minecraft/togglepower.sh on >> /home/alifeee/minecraft/cron.log 2>&1
5 4 * * 3 /home/alifeee/minecraft/rsync_backup.sh on >> /home/alifeee/minecraft/cron.log 2>&1
15 4 * * 3 /home/alifeee/minecraft/togglepower.sh off >> /home/alifeee/minecraft/cron.log 2>&1

cron tasks - minecraft box

…and the cron tasks on the minecraft box:

55 16 * * 2 /home/alifeee/minecraft/tmux_make.sh >> /home/alifeee/minecraft/cron.log 2>&1
0 4 * * 2 /home/alifeee/minecraft/tmux_kill.sh >> /home/alifeee/minecraft/cron.log 2>&1

human description of cron jobs

Hopefully you can see the similarities to the process I described above, i.e.,

The scripts

These scripts are pretty simple, they are:

togglepower.sh - turn on/off the minecraft box

$ cat togglepower.sh
#!/bin/bash
# power on server
date
onoroff="${1}"
echo "got instruction: turn server <${onoroff}>"
if [[ ! "${onoroff}" == "on" ]] && [[ ! "${onoroff}" == "off" ]]; then
  echo "usage: ./togglepower.sh [on|off]"
  exit 1
fi
serverid="${serverid}"
auth=$(curl -s --request POST 'https://console.kamatera.com/service/authenticate' \
--header 'Content-Type: application/json' \
--data '{
    "clientId": "${clientId}",
    "secret": "${secret}"
}')
authentication=$(echo "${auth}" | jq -r '.authentication')
status=$(curl -s --request \
  GET "https://console.kamatera.com/service/server/${serverid}" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer ${authentication}"
)
power=$(echo "${status}" | jq -r '.power')
echo "current power: ${power}"
if [[ "${power}" == "${onoroff}" ]]; then
  echo "power is already ${onoroff}… quitting…"
  exit 1
fi
result=$(curl -s --request PUT \
  "https://console.kamatera.com/service/server/${serverid}/power" \
  --header 'Content-Type: application/json' \
  -H "Authorization: Bearer ${authentication}" \
  --data '{"power": "'"${onoroff}"'"}'
)
echo "complete! got ${result} from API call"

run - run the Minecraft server

$ cat ./run 
#!/bin/bash
java \
  -Xmx1G \
  -jar fabric-server-mc.1.21.4-loader.0.16.10-launcher.1.0.1.jar \
  nogui

tmux_make.sh - make a tmux session and run the Minecraft server in it

$ cat tmux_make.sh 
#!/bin/bash
date
session="minecraft"
echo "making tmux session ${session}"
tmux new-session -d -s "${session}" -c "/home/alifeee/minecraft"
echo "sending run"
tmux send-keys -t "${session}" './run' 'C-m'
echo "created !"

tmux_kill.sh - stop the Minecraft server and stop the tmux session

$ cat tmux_kill.sh 
#!/bin/bash
date
session="minecraft"
echo "sending CTRL+C to ${session}"
tmux send-keys -t "${session}" 'C-c'
echo "sent CTRL+C… sleeping 30s…"
sleep 30
echo "killing session ${session}"
tmux kill-session -t "${session}"
echo "killed session"

rsync_backup.sh - get backups using rsync

$ cat rsync_backup.sh 
#!/bin/bash
date
echo "saving cron log"
rsync minecraft:/usr/alifeee/minecraft/cron.log cron_minecraft.log
date
echo "saving world"
rsync -r minecraft:/usr/alifeee/minecraft/world/ world/
date
echo "saving dynmap"
rsync -r minecraft:/usr/alifeee/minecraft/dynmap/web/ dynmap/web/
date
echo "done!"

What about the map?

Well, I figured this was too annoying to automate, so I just wrote a front page to pick whether you wanted the "dead map" or the "live map" (on https://map.mc.alifeee.net/ – link probably dead).

The HTML for this simple picker makes quite a nice page:

see HTML
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<head>
<style>
html, body {
  background: black;
  color: white;
  height: 100%;
  font-family: sans-serif;
}
body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
img {
  margin-bottom: 1rem;
}
.options {
  display: flex;
}
.option {
  background: orange;
  padding: 1rem;
  border-radius: 0.5rem;
  margin: 0.5rem;
  color: black;
  text-decoration: none;
  max-width: 10rem;
  text-align: center;
}
.option.two {
  background: purple;
  color: white;
}
.option span {
  opacity: 0.75;
}
</style>
</head>

<body>

<h1>minecraft dynmap</h1>

<img src="/map/tiles/world/flat/0_0/zz_16_4.webp" />

<section class="options">
  <a class="option one" href="/map/">
    <h2>dead map</h2>
    <span>viewable all week, updates on server shutdown</span>
  </a>
  <a class="option two" href="https://livemap.mc.alifeee.net/">
    <h2>live map</h2>
    <span>viewable only when the server is live, shows players</span>
  </a>
</section>
</body>
</html>

This is served with a special nginx configuration which just serves a static file, and otherwise serves content via alias (not root):

server {
    server_name map.mc.alifeee.net;
location / {
        root /var/www/dynmap/;
        try_files /whichmap.html =404;
    }
    location /map/ {
        alias /var/www/dynmap/;
        try_files $uri $uri/ =404;
    }
}

Does it work

I think it works. I'll see if I have to make any edits tomorrow or next week.

I love scripting !

back to top

creating a desktop overlay to view players on a Minecraft server with conky#prevsinglenexttop

2025-06-03 • tags: conky, minecraft, scripting, overlay • 1049 'words', 5.2 mins @ 200wpm

Currently, I'm hosting a Minecraft server weekly on Tuesdays. Sometimes I even play.

It's Vanilla with a proximity voice chat mod (walk near people to hear them). Proximity voice chat is endlessly fun (see Barotrauma, Factorio, et cetera…)

Today, I wanted to have an overlay (think Discord voice chat overlay, or when you pop-out a video in Firefox, or when you use chat heads on mobile) which showed me who was online on the server.

Querying the Minecraft server status

After seeing an "enable status" option in the server's server.properties file, and searching up what it meant (it allows services to "query the status of the server), I'd used https://mcsrvstat.us/ before to check the status of the server, which shows you the player list in a browser.

But a local overlay would need a local way to query the server status. So I did some web searching, found a Python script which wasn't great (and written for Python 2), then a self-hostable server status API, which led me to mcstatus, a Python API (with command line tool) for fetching server status.

I installed and tested it with

$ cd ~/temp/minecraft/
$ python3 -m venv env
$ ./env/bin/python -m mcstatus $SERVER_IP json
{"online": true, "kind": "Java", "status": {"players": {"online": 7, "max": 69, "sample": [{"name": "Boldwolf5491", "id": "289qfhj8-a8f2-298g-19ga-897ahwf8uwa8"}, {"name": "……………

Neat!

How to make an overlay on Linux

Next, a way of having an overlay. Searching for "linux x simple text overlay" led me to xmessage, which can show simple windows, but they're more like confirmation windows, not like long-lasting status windows (i.e., it's hard to update the text).

I was also led to discover conky, which – if nothing else – has a great name. It's designed to be a "system monitor", i.e., a thing wot shows you your CPU temperature, uptime, RAM usage, et cetera. The configuration is also written in Lua, which is super neat! I still want to get more into Lua.

Using conky

By modifying the default configuration (in /etc/conky/conky.conf) like so:

diff --git a/etc/conky/conky.conf b/.config/conky/conky.conf
index 44053d5..cc319e1 100644
--- a/etc/conky/conky.conf
+++ b/.config/conky/conky.conf
@@ -37,8 +37,9 @@ conky.config = {
     out_to_stderr = false,
     out_to_x = true,
     own_window = true,
+    own_window_title = 'Minecraft',
     own_window_class = 'Conky',
-    own_window_type = 'desktop',
+    own_window_type = 'normal', -- or desktop
     show_graph_range = false,
     show_graph_scale = false,
     stippled_borders = 0,
@@ -48,25 +49,9 @@ conky.config = {
     use_xft = true,
 }
 
 conky.text = [[
-${color grey}Info:$color ${scroll 32 Conky $conky_version - $sysname $nodename $kernel $machine}
-$hr
-${color grey}Uptime:$color $uptime
-${color grey}Frequency (in MHz):$color $freq
-${color grey}Frequency (in GHz):$color $freq_g
-${color grey}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}
-${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}
-${color grey}CPU Usage:$color $cpu% ${cpubar 4}
-${color grey}Processes:$color $processes  ${color grey}Running:$color $running_processes
-$hr
-${color grey}File systems:
- / $color${fs_used /}/${fs_size /} ${fs_bar 6 /}
-${color grey}Networking:
-Up:$color ${upspeed} ${color grey} - Down:$color ${downspeed}
-$hr
-${color grey}Name              PID     CPU%   MEM%
-${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}
-${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}
-${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}
-${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}
+${execpi 5 ~/temp/minecraft/check.sh}
 ]]

…when we run conky it opens a small window which contains the output of the script ~/temp/minecraft/check.sh (the 5 after execpi means it runs every 5 seconds). If this script was just echo "hi!" then that conky window looks a bit like:

 ———————+x
 |       |
 |  hi!  |
 |_______|

I use Pop!_OS, which uses Gnome/X for all the windows. With that (by default), I can right click the top bar of a window and click "Always on Top", which effectively makes the little window into an overlay, as it always displays on top of other windows, with the added bonus that I can easily drag it around.

Writing a script for conky to use

Now, I can change the script to use the above Minecraft server status JSON information to output something which conky can use as an input, like:

#!/bin/bash
#~/temp/minecraft/check.sh
json=$(~/temp/minecraft/env/bin/python -m mcstatus $SERVER_IP json)
online=$(echo "${json}" | jq -r '.status.players.online')
players=$(echo "${json}" | jq -r '.status.players.sample[] | .name')

echo '${color aaaa99}'"${online} players online"'${color}'
echo "---"
echo "${players}" \
  | sort \
  | awk '
  BEGIN{
    for(n=0;n<256;n++)ord[sprintf("%c",n)]=n
  }{
    r=0; g=0; b=0;
    split($0, arr, "")
    for (i in arr) {c=arr[i]; n=ord[c]; r+=n*11; g+=n*15; b+=n*21}
    printf "${color %X%X%X}%s\n",
      r%128+128, g%128+128, b%128+128, $0
  }
'

The fancy awk is just to make each player be a different colour, and to randomly generate the colours from the ASCII values of the player's username.

The final output

The final output looks like:

 ——————————————————+x
 | 8 players online |
 | ---              |
 | Kick_Flip_Barry  |
 | Blue_Outburst    |
 | Kboy8082         |
 | lele2102         |
 | Compostmelon101  |
 | Nobody808        |
 | Kaithefrog       |
 | BrinnanTheThird  |
 |__________________|

…which I can drag anywhere on my screen. When people join or leave the server, I can see a flash of change out of the corner of my eye.

Conclusions

Is this useful? Should I – instead – just have been playing the game? Do I use too many en-dashes? The world only knows.

Maybe I'll use conky for something else in future… I like to wonder what it could do…

back to top see more (+48)