awk '/in_reply_to_screen_name/ { print $3 }' tweets.json | sed 's/[","]//g' | sort | uniq -c | sort | grep -v BryantD | tail -20
56 graphxgrrl
57 patrickoduffy
58 jessnevins
59 othergretchen
60 GlobeChadFinn
61 ryantomorrow
65 smakofsky
66 seclectech
69 multiplexer
73 gentlyepigrams
75 rmd1023
76 mgrasso
79 JimHenleyMusic
79 Wolf_six
89 carlrigney
102 _r_o_n_e_
107 rone_____1
129 emilytheslayer
306 rdonoghue
341 ce_murphy
Category: Technology
I made a thing! I have been on a minor roll with python recently and this seemed like a fun project so I started working on it. Towards the end I reached out to the awesome person who inspired me, since she didn’t seem to have been keeping her tracker up to date, and she said I should go ahead and launch mine. So here we are.
I used this as an excuse to try out new technology and libraries. Click and Cloup made the list; the first because I wanted to try out new argument parsers and the second because I needed option groups. This forced me to learn to use setuptools better, which was a win. I am gonna keep using this tech going forward.
I also wound up sticking Rich in there for better CLI output and it’s kinda great, so that’ll stay in my toolbox too.
Dataset turned out to be too limited, because it’s really just for columnar data in a single table and it turns out itch.io jams have one little thing which break that paradigm; namely, multiple owners per jam. So now I’m using sqlite with JSON support and honestly it’s a bit grungy. Maybe next time I’ll learn SQLAlchemy for real.
My python has gotten significantly better over the last year with this kind of small but enjoyable work, and I am gonna keep doing it.
Before the pandemic, I’d been thinking about writing a little aggregator to pull movie times at my favorite local indie theaters into a calendar. I’m bad at remembering to see that cool showing a month from now but if I had a calendar that would theoretically help.
Obviously I didn’t need it for the last couple of years but the silver lining is that I got better at Python. I spent some time coding over the last week of my sabbatical and voila: the Seattle Arthouse Movie Calendar.
The code is here. I was sort of fiddling around with making it a real library but decided not to chew off too much at once. It was enough fun learning how to use classes to make it super-easy to add a new theater.
Lots of potential improvements. I am probably going to generate separate calendars for each theater next, for convenience. I’d also like to render maybe three days worth of calendar on the Web page. I feel like doing more than that risks pulling traffic away from the official theater sites, which I’d prefer to avoid, but three days seems reasonable.
I’m going to write up some notes on using the code for other cities too. If you’re decent with Python you could probably figure it out from reading what’s there but documentation is a good practice anyhow.
Got a wild hair, updated my ten-years-fallow technical operations blog with a reading list I wrote up for my last job. This inexorably led to changing themes and doing some maintenance. This sort of industriousness will never last.
Finished up the work discussed previously; I’m now planning on running an update weekly on Monday, which will aggregate the previous week’s reviews. There are working spoiler blocks. An example post: Movie Reviews: 6/27/2022 to 7/3/2022.
The code for all this is now public at https://github.com/BryantD/letterboxd-feed-wp.
This week I needed to do some analysis of JIRA tickets that goes beyond the reporting JIRA provides — not entirely an uncommon task. My usual quickie toolkit for that purpose involves Jupyter notebooks, which I prefer over downloading CSVs and playing with spreadsheets because I can automate the notebooks given a JIRA API key.
In this case, though, I really want one of my PMs to be able to run these reports, and I don’t want to get into the whole “OK then type this at the command line” thing. The post title kind of gives this away, but after some thought I realized, hey, just check the notebook into the company’s GitHub and there we go.
But how about that API key? Obviously I don’t want to embed mine in the notebook. Is there some way to use GitHub secrets for this? Answer: yes, there is, and it’s really simple, but I don’t see it documented step by step anywhere else so I’m gonna do that here.
If you want the quick answer: GitHub makes secrets available as environment variables, and if you’re working in the GitHub Jupyter environment, you don’t need to do anything special with workflows to make that happen. Therefore, you can just use Python’s os.environ
mapping object to get at secrets.
FoundryVTT is a high quality virtual online tabletop platform. Unlike Roll20, however, there’s not a central server — once you buy a license, you have to run it someplace. There are a few services that will do this for you at a reasonable price, but I’m a geek, so if I start using FoundryVTT I want to host it myself.
Fly.io is a very cool new application hosting cloud. I experimented with it a month ago for hosting an NJPWWorld RSS feed generator and it was awesomely simple. They support persistent disk, so I couldn’t see any reason why it wouldn’t work for FoundryVTT. And it did! Details after the cut.
My old boss Steve Makosfky was singing the praises of Scriptable the other day — it’s an iOS app that allows you to run Javascript in a number of ways, including as a widget. It’s also free (but tip the developer if you like and use it). So I modified an existing script that displays random photos from Flickr to replace my clunky Unsplash photo widget.
It’s way better than my previous solution. It doesn’t clog up my photo library, plus it’s mildly configurable. (Could be more so, but I’ll leave that as an exercise to the reader.) I’ve set mine up such that it only pulls down nature photos, which means I’m no longer seeing people I don’t know on my iOS home screen.
I stuck my code in a gist in case anyone finds this useful.
So far this month I’ve received a couple hundred email messages from Instagram notifying me that their Terms of Use have been updated. They’re legitimate emails; it looks like someone signed up hundreds of Instagram accounts using randomized innocence.com email addresses. Since I moved my mail to Fastmail, I’m now seeing them all. I poked around a couple of the accounts (hi, kurt.clemons78446!) and the ones I spot checked have all been deleted.
I imagine someone used innocence.com as a domain for non-existent email addresses, and these either date back to before Instagram added a confirmation step (and were later removed for spamming) or they just never confirmed the accounts. You’d think that deleted accounts would be removed from whatever list of email addresses Facebook is using to generate these emails. Unconfirmed accounts… I guess those should still see the Terms of Use changes.
Good times. Finally added a filtering rule for the emails, anyhow.
I don’t like wearing headphones all day and since I’m lucky enough to have a spare room for an office, I can play music through my Bluetooth speaker. However, I’m lazy, and I don’t want to fiddle around with my music player just cause I’m starting a Zoom meeting. Thus, automation.
Zoom provides callbacks when meetings start, but that’s aimed at people writing plugin modules. OK, we can go a bit lower level. I can’t just watch for a process, cause Zoom is always running on my laptop. But I can watch for open UDP sockets!
$ lsof -i 4UDP | grep zoom
zoom.us 88028 bryantd 83u IPv4 0xa90f1ce03eca5d5 0t0 UDP xx.xx.xx.xx:57275
zoom.us 88028 bryantd 84u IPv4 0xa90f1ce03eca2ed 0t0 UDP xx.xx.xx.xx:52612
zoom.us 88028 bryantd 90u IPv4 0xa90f1ce09340175 0t0 UDP *:65048
zoom.us 88028 bryantd 91u IPv4 0xa90f1ce0939ce8d 0t0 UDP *:60088
zoom.us 88028 bryantd 95u IPv4 0xa90f1ce0939c8bd 0t0 UDP *:50594
That’ll do, pig. That’ll do.
#!/bin/bash
trap ctrl_c INT
function ctrl_c() {
stop_music
exit
}
function stop_music() {
/usr/bin/osascript -e 'tell application "Music" to pause'
}
while true; do
zoom_status=$( /usr/sbin/lsof -i UDP | /usr/bin/grep zoom | wc -l )
if (( $zoom_status > 0 )); then
stop_music
fi
sleep 30
done
I’m catching interrupts because I want a quick keyboard method to stop the music just in case. Right now I don’t think I want it to restart music when I leave a Zoom call, but easy enough to add that if I do.