scrobble 0.2.1 notes

scrobble is a small Python library and command line tool I wrote for:

  1. Last.fm users
  2. who still collect and play CDs
  3. and who know their way around a command line

So, yeah, it’s niche, but I use it every day!

I just added a couple of small features worth mentioning for posterity.

Barcode scanning

The first version of scrobble required you to enter the CD barcode yourself. This was fine. I mean, I lived with it. But obviously it’s a pain in the ass to type out that long number, especially on a smartphone screen.1 I tried to hack my way around that by using the iOS Shortcuts OCR action to process an image and detect the numbers, but I always had to fix the result before submitting. Obviously the tool needed a proper barcode scanner.

This turned out to be very easy to do, I just had to use the barcode.BarcodeDetector class from opencv-python.

So now you can take a photo of the back of your CD case and pass the path to that image. e.g.:

scrobble cd --verbose ~/IMG_1234.jpg

If you’re thinking it seems like a pain to take a photo, save that somewhere, and pass the path to that to a command, consider that iOS Shortcuts is still the primary way at least I use this tool.

Choosing which tracks to scrobble

I didn’t expect this to be something I would need, but I realized it was when I listened to my copy of MF DOOM’s MM..FOOD.2

My copy of the album is a double disc release with one audio disc holding all the tracks and the other an extras DVD-Video. The MusicBrainz release represents the DVD with a single 1:04:19 track called “MM..FOOD Drive Tour”. Well, that’s nice, but I don’t want an hour long track I never listened to being scrobbled.

So scrobble has a new --track-choice flag that lets you choose which tracks from the release to scrobble. Right now the feature requires charmbracelet/gum to be installed, and the experience of using it is very cool.

This feature is also useful when you can’t listen to an entire album in one sitting. I try not to let that happen, but it happens, and when it does it feels “wrong” to have the whole album scrobbled at once without gaps.

Up Next

scrobble is pretty simple and it’s built on the shoulders of people who did real work, like the authors of musicbrainzngs , pyLast, and the other dependencies the tool has.

Here’s another problem to solve. Believe it or not, some CDs don’t have barcodes. Sorry to tear the fabric of your reality like that, but it’s true. What do you do if you own a copy of the US release of Vol. 9 & 10 by The Desert Sessions and you look at the back and find no barcode?

It would be nice to be able to pass a url to a Discogs or a MusicBrainz page and scrobble the tracks from there. Maybe Last.fm album pages too? We’ll see.

  1. ~90% of my use of scrobble is via an iOS Shortcut. A topic for another post. ↩︎

  2. Just remember all caps when you spell the man name. ↩︎

2023: A personal review

2023 in a photo

Emphasis on personal.

This was a year of good and bad extremes.

Sabbatical

This still deserves a separate retrospective. I tried to write one, but life intervened.

The summary is: although duration was not pre-determined, my break from having a full time job ended up being a few days shy of an even year. I don’t regret taking the break, although I did it assuming the world would stay more or less the same until I came back, and it kinda didn’t. Don’t you hate it when that happens!

Gratitude

One must start here.

I am one of the luckiest people on the planet. I really am. Chances are you are too, maybe a bit more lucky or a bit less, but we’d be haggling over third and fourth places in a race of hundreds.

I live in the United States. I am a permanent resident in this country, and a citizen of another safe country. I have undergraduate and graduate degrees. I have a job right now. I have health insurance. I’ve worked in tech for a number of years and I’ve done well financially. Last year I took a break from full time work and spent a good number of months doing not-work. I’ve been able to afford the time and money to engage in most or all of my hobbies. Any chronic physical or mental health issues I might have at the moment are either minor or manageable. I have shelter. I’m not worried about food or water. I do not live in a war zone. I have not lost my home to a fire, a flood, a tornado, or other natural disaster. I have not lost a loved one to an illness or an untimely or violent death.

“Gratitude” is having a moment right now, and so there’s a way this could come across as canned, but it’s not. It’s real. I feel it in my bones.

And I think something that heightened that feeling was another feeling, one of impending doom I felt in a way I hadn’t before. Like this is a moment of twilight. There’s nothing like fear of loss or a looming threat to make you appreciate what you have.

Early 2023

The first three months of the year are lost to me. They were not just the worst of the year but maybe of the last decade of my life. Things got truly existential and I still feel the effects of that to this day. Believe me I don’t like being cryptic about it, but it’s not something I’m ready to talk about in full detail just yet.

Rest of 2023

I ended my sabbatical in June of 2023. Things have been significantly better since. I started a new job at a place I’m proud to work at, re-engaged negotiations with chronic imposter syndrome, got a new bike, got hit by a car riding said bike and broke my elbow, attended a family wedding, said goodbye to a beloved pet, and handled it all pretty well I think.

Extracurriculars

I haven’t flown for about a year now. It’s not a surprise, many private pilots lapse and get rusty as soon as they pass their checkride. You need a reason to fly, otherwise it’ll be difficult to get over the resistance of booking a plane, planning a flight and checking weather, driving to the airport and preflighting, not to mention the cost, etc. I’m okay with it. I’m still a pilot, and I’ll get back to it at some point.

In an effort to expand my social circle and build an auxiliary sense of purpose, I started volunteering in a community owned bike shop near where I live and that’s been great. I like the people I’m meeting at the shop, I like working with my hands, and I like helping people fix their bikes. I signed up for a lot of responsibility pretty fast and I hope I can manage to not disappoint myself and everyone else around me.

More music and fewer podcasts. I spent a lot of time listening to new music and buying and (re)listening to CDs and old favorite albums. I like being bugged by low-stakes questions like “should I alphabetize my CDs globally or by genre”.

Podcasts are now considered harmful and my goal is to have as few of them in my life as possible. It’s a vice, really. More on this another day.

I’ve read a good number of books. Another good transfer of time away of podcasts.

I’m also glad to see that despite the year it’s been, I still managed to post a few things throughout, although I’m still struggling to write well. My prose is stiff and stilted. I attribute it to lack of practice and a very unfavorable consumption:creation ratio.

In November we visited Vienna, Carvoeiro, and Lisbon. Vienna may be my favorite city ever, and my heart still aches every time I return to try using US public transit after a visit to Europe.

Returning to Vienna got me back into Duolingo. It’s not perfect (see below) but it’s probably the most wholesomely gamified addictive app out there.

Seattle

I still live here, and I still feel like I don’t belong.

LLMs (reluctantly)

Clearly this is the headline for the tech world, a world I decreasingly and reluctantly inhabit. I really don’t want to talk about this, but I can’t leave it out of a review of my year.

So what of it? There’s a million takes, many of which are more thought-through than mine while still disagreeing with each other about what is happening, what will happen, and whether it’s good or bad.

I made many attempts at writing something coherent about this topic and failed quite completely. I suppose it’s important to admit it’s related to the crisis I went through earlier in the year.

My feelings are stronger than my thoughts on this, though both are strong and both are pretty negative. I think the effect in the short and medium terms will easily be net bad, and the effect in the long term is a big wide question. I struggle to see how it goes well without a fundamental change in human nature and organized society, and how we individually and collectively respond to incentives. Meanwhile Amazon is shoving ads in every crevice it can find to wring out every last incremental cent it can get, and last week loud ads shouted at me from the pump while I filled up the tank at a Shell gas station. I’m not optimistic.
Maybe a shock is what we need, but it would have to be a bigger shock than COVID-19, and I really don’t want to live through that.

Nothing has dislocated me more from my generation, (some of) my hobbies, or my career than the breathless sprint towards using generative models for anything they can be shoe-horned into. I can’t interpret it as anything other than total willingness and eagerness to commoditize and automate everything, collateral damage be damned. That’s someone else’s problem to solve. Illustration, art, writing, reading, modes of creation and connection, the very god damn atoms of our humanity. I should’ve known better, but I’m still stunned by how many think of art as just pretty pictures, and writing as something to summarize into the shortest fastest snort of words possible. How few see the inherent value in paying an artist or a photographer well for their work. I understood we lived in capitalism, but I thought we knew where to draw lines to demarcate the commercial from the human, work from craft, financial vs psychological value. I thought we cared to know that another person drew this picture or took this photo, or that someone with feelings sang this song. But so many just want passable pixels for their blog and a bop to listen to.

I miss crypto. At least I knew it was all horseshit that was never going to work, and it soaked up all the hype-hungry fast-money hucksters into one drain and kept the rest of us somewhat isolated.

And sure, some people want to use the new tech to cure cancer or dementia, and I’m really glad I work at a place where I can try to be one of those people (and I will). But let’s be honest, all the sweatiness isn’t about that.

I can find some solace in knowing that I’m not alone in how I feel about it all, but will there be enough of us?

I can’t do the topic justice here and it’s not the point of the post. In the meantime I’ll leave a small collection of random links to stimulate the discerning reader.1

I would love to come back to this post years later and wince at making a big deal out of something that didn’t change much for the worse in the end.

Next year

Oops. This is all coming off pretty bleak and angsty I think. Sorry about that. I’ve also been having a lot of fun, I promise! I’m trying to live in the present as much as possible, and just hope that today is not yet the best day I’ll ever have.

I tried coming up with themes for next year and struck out. “Year of less”, “Year of less resistance”, “Year of attention”, “Year of presence”, “Year of focus”. None of it fits well. Like many others my attention and time-management are shot, and I want to repair that. I want to do fewer things and do them better.

  1. If you view source on the homepage, you’ll find a <meta name="Description" content="Perseverance overcomes almost everything, even nature." />↩︎

Art Class

Forewarning: blunt re-telling of personal history, discussions of politics, indoctrination and propaganda, anti-Semitism, all relevant to current events. If you’ve read other posts on this site, this one is very much not like the rest.

I was born in Egypt in the very early 90s. When I was about two or three my parents moved to one of the oil-rich Gulf countries to work. That is where I went to school.

Explaining education in Gulf countries is way out of scope for what I want to exorcise today. What I can tell you is that until I was almost done with high school, we didn’t know whether we’d have to go back to Egypt, so from grades 1 to 9 I went to a school that taught the Egyptian curriculum. The country was not Egypt, but the students were Egyptian, the teachers were Egyptian, the books came from Egypt, and the exams came from Egypt.

This is not a day to mince words, so I will also tell you that the education I received was abysmal on every level: factually, practically, morally. It would be a joke if it wasn’t so despicably ruinous of childhood as well as an education. In the midst of it there is one particular black mark I often think of, and that’s art class.

The Egyptian school curriculum for middle school grades included art. You had to take art.1 Of course like with every other subject, this requirement was purely nominal and for show. What it meant was children’s asses needed to be in seats, and a teacher tasked with being the “art” teacher had to check a box that says art happened. No one taught any artistic technique, theory, history, media. I do remember being taught one thing in art class though, and that’s hating Israel and hating Jews.


The Egyptian school curriculum and culture are awash with propaganda. Any subject that could be warped to extol the virtues of the nation and demean its enemies was thusly warped. Geography books taught lies about what the country produced, chapters on civics told fantasies about the form of government we had, and history books taught outrageous fables about victories that were in fact defeats and betrayals that never happened.2

One of the most important national holidays in Egypt has nothing to do with independence or the founding of a nation. It’s October 6th, the day Egypt “defeated” Israel in the Yom Kippur War of 1973. Egypt, a nation that gained independence in 1922 and sits on top of one of the world’s oldest civilizations marks the peak of its national pride on a war it lies about to its own people. A war that Egyptians are taught was a rout when in fact by the end Damascus itself was being shelled and Israeli forces were 100km from Cairo.

And each year in art class, for weeks that run up to October 6th, we did one thing and one thing only: paint the Egyptian victory, and more importantly, paint the Israeli defeat.

I have memories of countless paintings I had to do of generic battlefields with Egyptian flags flapping in the wind while Israeli flags burn, of proud Egyptian soldiers cresting one sand dune after another, machine guns in hand spewing bullets at hapless Israeli soldiers collapsing every which way while Egyptian fighter jets shoot Israeli planes out of the sky.

Blood, fire, barbed wire, bodies, and burnt tanks. Those are the only things I remember from art class.


It’s embarrassing to think of the things I was taught and mortifying to think of the things I believed, I cannot even repeat them.

As a child in that system I was taught anti-Semitism and anti-Zionism in their purest forms. Stories of sadistic Israeli domination and crushed Arab innocence, stories much like blood-libel or excerpts from The Protocols of the Elders of Zion were exchanged between average kids in average school yards all the time. All lies.

The indoctrination happens in homes, it happens on television, it happens in recess, it happens from friends’ parents, and it happens in art class. It happens from complete strangers, like the man who stopped me while I was walking with a can of Pepsi in hand to tell me that Pepsi was short for “Pay Every Penny Save Israel”, and he was dead serious.3

I am sorry to bring this fact to your consciousness, but it’s what happened. And it is what still happens.


I’m telling you this because I know that for those who never lived in a world like that, it is impossible to imagine what it’s really like. Even as I tell you now, you still don’t know. How could it be real. How could children be taught to hate before they learn to add and subtract, to imagine killing the enemy and shedding their blood, to imagine the glory of blowing themselves up to strike fear and terror in their hearts, to delight in their suffering.

That was my world, that was the world for millions of children who are now adults, and that is the world for millions of children today. That is what happens there. They teach children to hate Jews. I’m not here to tell you to do something about it, I don’t know what is to be done about it. But you have to know, and I had to tell you.

  1. We “took” art. Not learned it, or practiced it. We took it like medicine. ↩︎

  2. Since the revolution and coup d’état of 2011 and 2013, I’m sure all those books have changed although I doubt they are any more truthful. Instead of lies about Mubarak’s Egypt and Nasser’s revolution, there will be lies about Sisi’s Egypt and the 2011 revolution. ↩︎

  3. To be clear, my parents did not believe any of this, but we all had to be careful about what we said. As expatriates belonging to a religious minority, we were second class citizens in that country and always lived in fear that the wrong word spoken to the wrong person would send us packing. ↩︎

scrobble 0.1

My beloved Cambridge Audio CD transport

Picture this.1

It’s been a long day. A long week even? You’ve earned your government salary and then some. It’s you time.

You head to your favorite chair and you think “ah what I would love right now is to pick a CD from this shelf here, slip that baby out of its jewel case2, pop it into this player, put my feet up and listen to the album from start to finish.”

Suddenly, though, an irk. A perturbance in the vibe. Something isn’t right. Then you see it. Your CD player won’t scrobble your album to Last.fm. There will exist no record of this experience, no entry in a NoSQL key-value database maintained by a hardly-changing music tracker owned by a massive media conglomerate to be used to train machine learning models that in the end won’t work all that well.3

Is this you? Because this is me. This was me. And to de-irk myself, I did what any person who is large and in charge would do. I created a Python library.


OK we’ve had our fun. Let’s get serious for a second.

This is for a niche audience, there’s no denying it. The problem I wanted to solve is I’m one of those people who are very attached to their Last.fm profiles, one of those “scrobbled or it didn’t happen” crowd, but I also like to collect CDs and listen to them. Yes you can rip the CD and play the files in a player that will scrobble to Last.fm, and that’s what I do a lot of the time. But I love the ritual of taking a CD out of its case and putting it into a dedicated player, and flipping through the booklet/liner notes while I listen to it from start to finish.

The problem is CD players are dumb machines (meant in the most flattering way possible) that do not have network interfaces or fancy firmwares (again, that’s a good thing). They won’t scrobble. They won’t even know what album or tracks they’re playing unless the CD has CD-Text (rare).

I’m not the first person to try and solve this problem. Daniel Puscher built CodeScrobble (GitHub link), a clever web app that uses the camera to scan the barcode on your CD or vinyl case, matches that to an album, and scrobbles the tracks (with correctly backdated timestamps) to your Last.fm account. There also exists OpenScrobbler created by Enrico Lamperti, which lets you search for and scrobble releases manually.

Unfortunately neither worked well enough for me. With CodeScrobble I had too many instances where the camera would freeze, frames would lag, or it would just not read the barcode. OpenScrobbler worked a little better, but searching manually was tedious, and sometimes search results are messy or miss the specific release I’m looking for.


pip install scrobble

So for fun, I built scrobble, a small Python library that takes a barcode text, looks up the release on MusicBrainz, and scrobbles your tracks to your Last.fm account. Since barcodes can match more than one release with different tracklists, scrobble will ask you to choose a release if that happens (unless you tell it not to). You can also back (or future) date your scrobbles if you are logging an album that you listened to earlier in the day, or just started listening to now.

~  scrobble --help                                                           

 Usage: scrobble [OPTIONS] BARCODE [PLAYBACKEND]

╭─ Arguments ────────────────────────────────────────────────────────────────────────╮
│ *    barcode          TEXT           Barcode of the CD you want to scrobble.       │
│                                      Double album releases are supported.          │
│                                      [default: None]                               │
│                                      [required]                                    │
│      playbackend      [PLAYBACKEND]  When did you finish listening? e.g., 'now' or │
│                                      '1 hour ago'.                                 │
│                                      [default: now]                                │
╰────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────╮
│ --dryrun                --no-dryrun       --dryrun will print a list of tracks     │
│                                           without scrobbling to Last.fm            │
│                                           [default: no-dryrun]                     │
│ --verbose               --no-verbose      --verbose will print a bunch of stuff to │
│                                           your terminal.                           │
│                                           [default: no-verbose]                    │
│ --notify                --no-notify       --notify will send a push notification   │
│                                           via Pushover with CD information.        │
│                                           [default: no-notify]                     │
│ --choice                --no-choice       --choice will give you a list of options │
│                                           of more than one CD is matched.          │
│                                           Otherwise, the app will go with the      │
│                                           first match.                             │
│                                           [default: choice]                        │
│ --install-completion                      Install completion for the current       │
│                                           shell.                                   │
│ --show-completion                         Show completion for the current shell,   │
│                                           to copy it or customize the              │
│                                           installation.                            │
│ --help                                    Show this message and exit.              │
╰────────────────────────────────────────────────────────────────────────────────────╯
~ scrobble --no-choice --verbose 093624966524
  
💿 The Dead Weather - Sea of Cowards (2010)
🎵 1 Blue Blood Blues
🎵 2 Hustle and Cuss
🎵 3 The Difference Between Us
🎵 4 I’m Mad
🎵 5 Die by the Drop
🎵 6 I Can’t Hear You
🎵 7 Gasoline
🎵 8 No Horse
🎵 9 Looking at the Invisible Man
🎵 10 Jawbreaker
🎵 11 Old Mary

See the GitHub README for more information. Contributions welcome (I want to support other sources besides MusicBrainz, like Discogs, Bandcamp, etc.) Drop me a line if you have thoughts.

A note on usability

Now look here. I am happier in a terminal than a pig in a nice yard.4 But even I don’t want to have to fire up a shell as I sit in a chair listening to music. So, the way I actually use this tool is using an iOS shortcut that will either try to OCR an image of the barcode or prompt me to enter it manually and then ssh into a host and run scrobble with the barcode as an argument. It… works?

What’s missing is a proper barcode scanner. The OCR piece helps but it always requires manual correction. Problem is I can’t find a barcode scanner with a Shortcuts component on the App Store that doesn’t sketch the hell out of me. Do you know of one? You know what to do.

🖤

  1. If you read that and started hearing the lyrics to “Nobody Speak” by DJ Shadow, I see you. ↩︎

  2. Or slip case if that’s the kind of day you’re having. ↩︎

  3. Until we call them AI and they kill us all. A STORY FOR ANOTHER TIME PERHAPS. ↩︎

  4. Because pigs are very clean animals. ↩︎

The Kindle Should be Better

This is a draft that I wrote years ago and never published (for reasons). I thought the moment passed, but you know what, new information has come to light. So I will publish the original draft with no or minor modifications, and then add some followup thoughts at the bottom.

Summary: In the year 2023 there is no good reason to buy a Kindle. Buy something else. If the reason you feel stuck with Kindles is the collection of books you bought from Amazon for years, a) that sucks, and b) you can do something about it.


Original draft

Years ago, I wrote

Anything could be better, but some things should be better.

The Kindle has been mediocre for a long time. At some point, we crossed the line from “fine” to “please fix this, it shouldn’t be this way”.

I own a second-generation Kindle Oasis. It’s not the newest one, but it’s an otherwise top of the line Kindle. This fortifies me in my arguments below since if I have the following complaints about the top model, imagine the experience with the middle and bottom ones.

The best Kindle is overpriced

Present-day me interjection: The iPad Mini isn’t that affordable anymore. I still think the Kindle is overpriced.

This complaint is exclusive to the Kindle Oasis, which is $269.99.1 For $60 more, you can buy an iPad that has four times more storage (32 GB to the Oasis’ 8), a larger screen that’s amazing, a whole OS that lets you do close to whatever you want including read books, and everything else that makes the iPad effectively 100% of the tablet market.

The Kindle and iPad are devices that serve different needs, I get that. The iPad is significantly heavier than the Oasis, and the iPad’s screen doesn’t provide one of the primary reasons to use an e-reader: E ink screens that are easier on the eyes. But is that a reasonable price difference? Has the Kindle Oasis earned that price tag? My argument here is that it hasn’t, because the Kindle has hardly changed or improved for years.

It’s too slow

I don’t read as much as I want to. I know I’m not a power user of the Kindle and I don’t think I push it to its limits in terms of storage or usage nearly as much as other readers do. Why does it take 2.5 to 3 seconds to go from power button push to text on screen?

Present-day me interjection: this was one of the complaints I felt funny having because who was I to know that I _could be faster? Well, now I know._

The Kindle’s UI is sluggish. This was understandable years ago, E ink was a new technology that not many customers had prior experience with, and since it wasn’t a tablet you were willing to sacrifice some performance to get good battery life. I could be wrong, but I don’t think we have to make that tradeoff anymore. Pages should turn faster. Settings pages should refresh faster.

The ergonomics are terrible

For a light device, the naked Oasis is impossible to hold with something less than a kung-fu grip without it slipping. For a while I used the Kindle in a case until I realized that I didn’t use the case to protect it – it did not… – I used it because it made holding it easier.

At some point I ditched the case and covered the contact points with gaffer tape which improved the experience at the cost of aesthetics.

I don’t think I have abnormal hands. Is this a failure of testing during development? Did they not notice this? Did they notice and not care?

Library, highlights, and notes management is archaic

The library view on a Kindle is one big bag of all the books you’ve added or read sorted in descending order of date.2 You can create collections and add books to those collections, but that painful process is made even more painful by the sluggish UI I mentioned before. In addition to being one of the largest vendors of books in the world, Amazon also owns Goodreads, which is like saying “I fear my ocean of data is not enough, pray pour another ocean of data on top of it lest I expire from thirst.” None of this has trickled down to a better library management experience for the Kindle.

For many years, the Kindle saved every highlight and note to a plain text file on the device called “My clippings.txt”. I’ve always thought that was a great thing, and even played around with building my own highlight review system on top of the plain text file. But it’s 2023 and the markup is still plain text. Any text formatting in the form of bold, italics, or hyperlinking is lost. Could they consider migrating to a Markdown format? Or a side rich text file?

Typing notes on the Kindle Oasis is brutal. As far as I can tell there is no predictive intelligence to the keyboard at all. The lag and friction are way too much. I end up writing stinted comments that lack nuance, and that’s not good.

Reading anything other than an ebook is a bad experience

I want a fast, clean, Instapaper-like experience of reading online articles on the Kindle. Send to Kindle feels like a service its owners forgot was still live. You need to use Chrome or Firefox to install their plugin.3 Or you can install Mac or PC applications, and if you’re going to require desktop operating systems in the decade we’re in, take inventory of the situation.

Instapaper has a “Send to Kindle” bookmarklet they generously make available, but 1) you have to use Instapaper, and last I checked 2) you have to disable “Prevent cross-site tracking” in Safari for it to work.

I’ll give them a bit of a pass when it comes to PDFs, but the zoom and scrolling experience is a non-starter.


People don’t complain about things like this unless they care, and I care. I like the Kindle and I want it, desperately, to be the device it ought to be.

When something is not the way you want it to be, there will be reasons and it behooves you to think about them. Why isn’t the Kindle better?

I’m afraid it’s for the same reasons Goodreads has been sad and stuck for years. The Kindle doesn’t exist for the beauty of reading, it exists to sell books. If you’re the only game in town, are you going to sell more books if you keep pushing the hardware’s performance and user experience envelope, if you push its performance to make it instantaneous, if you remember that the Kindle has an OS and oh maybe we should, like, make it better and add some features and stuff?

I think the people who run Kindle think the answer is No, but I believe it’s short-sighted. No experiment or A/B test will tell you how many more Kindles you might sell if you revolutionize it just like no user survey could have told Apple how much the money machine would go brrrrr for the iPhone if they made it.

Having written all of this, I’ve convinced myself that the Kindle is Blackberry of ereaders. It’s still the default device to get, but not even its customers realize what they would do to have the iPhone of E ink reading.

I just learned that Kobo works with Libby, and Readwise has Kobo highlight sync integration in beta. Given that, the probability that I will buy another Kindle is practically zero.


Back to the present day

My thoughts haven’t changed much. The reason I decided to publish this draft is that I just got a Kobo Libra 2, and I am a big fan. Turns our I was correct, you can make an E ink based reader more responsive.

Even today, the Oasis costs $60 more than a Libra 2. Why? There is not a single reason about the device itself that justifies this. The only reason I can think of is that Amazon knows people are locked into the library and the ebooks they’ve already bought, and because the books have DRM, you need a Kindle to read them.

All I’ll say here is if you’re somewhat tech-savvy, I highly recommend you research how to download and strip your Amazon ebooks of their DRM and never look back.

It gets better

If you want to get even fancier, look into KOReader. It’s a little hacky to set up, but it gives you a lot more control over your reading view, device settings and functions, and even lets you send books to your device wirelessly straight from Calibre.

Even more proof that E ink devices that suck can’t blame the hardware. They suck because no one’s making them not suck.

See also

  1. (This is still the price) That’s the “Without Ads” version. The “Ad-supported” isn’t proper for comparison and is just… can we stop putting ads in every fucking thing? ↩︎

  2. I wrote this draft in December of 2021. I thought I might have to chuck it but I realized that everything here still stands with one addition: at some point the Kindle OS was updated to show a more organized library view than a simple list of books. It looks better than before, but also half the page above the fold is dedicated to Amazon pushing other books to you. ↩︎

  3. I do not use those browsers and therefore haven’t confirmed if this works. ↩︎

Under new management

Blue Angels, Seattle, WA

It’s hard to avoid going stale. A person, a business, a store, a band, a job, a friendship, a relationship. They can all go stale. They want to go stale. They naturally tend towards staleness if you don’t keep steering and pushing and lifting and refreshing.

stale

stale - adjective
1: tasteless or unpalatable from age
stale bread
2: tedious from familiarity
a stale routine
3: impaired in legal force or effect by reason of being allowed to rest without timely use, action, or demand
a stale affidavit
a stale debt
4: impaired in vigor or effectiveness

Can you believe “stalely” is a word?

Staleness is one of those spiraling states that promote their own entrenchment. Once a thing starts going stale, it’s that less attractive to you, you’re less likely to touch it, eat it, deepen it, grow it, have fun with it. The less you do any of that, the more stale it goes. And so it goes.

Also known as being in a rut.


Fresh starts are so tempting. Drastic action feels so much easier doesn’t it? When you’re stale for so long you feel numb, and drastic action feels like something. Gradual repair is such a drag in comparison. Can you even tell anything is happening? It feels like nothing.

Fresh starts help you save face, kinda. I think they’re often about you saying to the world, to yourself, “hey, I’m aware of what has been happening. I take it seriously. Don’t you worry about whether I’m aware, I am. Here I’ll prove it to you.”


There’s no new redesign, no grand breaks with the past or promises about the future here. Frankly it’s just that I’ve thought of the expression “under new management” on an almost daily basis for weeks and I wanted to write something about it.

And since we’re here, I’ll tell you that I’m aware that ever since I put on my big boy pants and started my first full time job at $COMPANY in early 2017, my creative output has gone to shit. Writing, personal projects, photography, all those links on the chain are rusty as heck, sabbatical having come and gone. As you can see. But there are no new year’s resolutions or grand declarations here. Any action taken will be gradual, and in fact may not feel like much of anything.


One last something. Think of anything you’ve liked for a long time. Maybe it’s a shop that’s been a little bla, maybe what used to never miss the mark at the restaurant has been hit or miss lately. One day you show up and you see a sign: under new management. How do you feel? I’ll tell you how I felt when the exact same thing happened to my favorite restaurant in Seattle that had been slipping for a while: I did not feel good. I don’t think I’ve ever felt excited about new management.

You almost never want new management, you usually just want the old management to regroup and tighten shit up. I think if you’re excited about new management, you want a different thing altogether.

Shortcut: Dispatch Bulletin

Dispatch Bulletin notification

I’m late to the Shortcuts game.1 I’ve seen others build impressive shortcuts for years but for some reason it took me until late last year to start building some of my own. And really it was my loss, because Shortcuts have long stopped being just a gimmick. They are not a serious tool to mix point-and-click with code to build some serious workflows.

This post is about an iOS Shortcut that I use to publish short posts and photos to my Micro.blog site Bulletin. I call it ‘Dispatch Bulletin’.

Context

Bulletin is built using Jekyll, meaning it’s a static website that needs to be generated each time I make a change, and the generated pages need to be hosted somewhere. Bulletin’s source code lives in a privare GitHub repo, and the site is hosted on Netlify.2

You tell Netlify to watch your site’s repo, and it will automatically build and serve your site whenever it sees a new commit in the branch of choice. It’s really cool.

Dependencies

The Shortcut relies on two third-party apps:

  • Scriptable. To run a script that identifies the local timezone and returns its TZ database name.3
  • Working Copy. Critical since that’s how the shortcut can add posts and photos to the site’s git repo.

Summary

Brief overview of how it all works. The shortcut…

  1. Receives text input.
  2. Detects the local timezone to use later in the post frontmatter.
  3. Prompts the user for file suffix. i.e., what to add after the date in the post filename.
  4. Pulls the latest updates to the repo in Working Copy.
  5. Asks the user if they want to attach a photo.
  6. If Yes, prompts the user to select the photo from Files.app and generated the body of a photo post. If No, generates a text only post.
  7. Writes the post and optional image to the repo in Working Copy.
  8. Commits changes and pushes to remote.
  9. Displays a notification that the bulletin was published.

Details

Let’s get into it.

step explanation
Step 1: Receive text input Accept text input, save value in Bulletin variable. We’ll use that later.
Step 2: Format current date and time Get current date and time in ISO 8601 format. We’ll use that later.
Step 3: Run TZIdentifier Scriptable script Run TZIdentifier script. See below for the simple code. We’ll refer to its output later.
Step 4: Ask for file suffix Prompt for the file suffix and create a text variable of the full file path. Okay you get it, I won’t keep saying “we’ll use that later”.
Step 5: Pull latest commits Pull any new commits to the local repo in Working Copy.
Step 6: Ask if you want to attach a photo Ask if I want to attach a photo to the bulletin.
Step 7: If Yes Self explanatory.
Step 8: Browse for photo then save it and stage it. Browse Files.app for the photo, save the photo to the proper path in Working Copy and stage it for commit.
Step 9: Ask for alt text Ask for image alt text.
Step 10: Create body of photo post Create the body of the photo bulletin and save it to BulletinBody variable.
Step 11: If you don't want to wattach a photo If you don’t want to attach a photo…
Step 12: Create text-only bulletin Create text only bulletin and save it to BulletinBody variable, then end the if statement.
Step 13: Save post file to repo Save BulletinBody to a Markdown file in Working Copy and stage it for commit.
Step 14: Commit and sign Commit all staged files with a simple commit message and sign the commit with the key Working Copy already has.
Step 15: Push to remote Push changes to remote.
Step 16: Show a fancy notification at the end Show a fancy notification at the end.

At this point my work is done and Netlify takes the wheel. Once the shortcut is done pushing the commit, Netlify will detect the commit to the main branch, pull it, build it, then serve it.

Appendix

Here’s the TZIdentifier script run in Scriptable:

const tz = Intl.DateTimeFormat().resolvedOptions().timeZone

function main() {
  Script.setShortcutOutput(tz)  
}

main()

Final notes

I had a lot of fun building this. It holds the highest honor an automation can receive: I use it all the time. It’s the most convenient way to publish to a Jekyll site I’ve ever worked out and it’s how I publish 9/10 posts to Bulletin.

  1. A note on capitalization. “Shortcuts” is a noun but it’s also the name of the app itself. Classic Apple. My executive editorial decision is to capitalize ’Shortcuts’ and not ’shortcut’. ↩︎

  2. From what I can tell Netlify is one of the most common ways to host a Jekyll site online besides Github Pages. It’s a really pleasant experience to set up, and they have a free tier that will work for most hobbyists like me. I have nothing but good vibes for the company. ↩︎

  3. I need to run a script for this because I need the timezone database name for… uh… Jekyll reasons, and as far as I can tell there’s no other way to get that on iOS. ↩︎

Brief automations: Playing a random album from Plex

Another installment in my series on listening to music is forthcoming and it will mostly be a love letter disguised as a 1000+ word use guide for Plexamp. In the meantime, this is a slightly out of context taste.

My music library lives under the watchful eye of a Plex server. The server pulls down a lot of metadata that makes artist and album pages much more delightful to browse than iTunes/Music.app ever did. I then use Plexamp to listen to music both at and away from home. I really love this setup.

Besides the official Plex and Plexamp clients, there is an unofficial Python Plex library whose goal is to “match all capabilities of the official Plex Web Client”. I’ve been playing with it for a while, it is impressive, and this is the first of many uses I have in mind for it.

Play a random album the simple way

I keep all the albums I own as CDs in a Collection called ‘💿’.1 Sometimes I want to put on some music but I don’t have a specific album in mind and end up scrolling the collection aimlessly.

A common way to deal with this kind of choice paralysis is to let a random picker choose for you. This is very easily done using the Python library.

Here is a simple implementation.

import random
from plexapi.server import PlexServer

BASEURL = 'http://192.168.1.123:32400'
TOKEN = '<insert your own token here>'
plex = PlexServer(BASEURL, TOKEN)

owned = plex.library.section('Music').searchAlbums(collection='💿')
plex.client('KEF').playMedia(random.choice(owned))

Requirements:

  • pip install plexapi
  • Know the local or remote IP address of your server.
  • Your X-Plex-Token for authentication. Here’s how to find it.
  • Know the name of the client that will play the album. This is cool because it doesn’t have to be on the same machine running the script! In my case I have a machine running Plexamp connected to my KEF speakers.

Steps:

  • Import the random library and the PlexServer class.
  • Create an instance of your server with the correct url and token.
  • Get a list of the albums in the ‘💿’ collection.
  • Tell the client to play a random album from that collection.

So that’s amazing and simple. Here’s how you can make it amazing and a little fancy.

Playing a random album the glamorous way

A random choice from a large collection can be jarring. Too decisive, you know? One compromise you can make between that and choosing from the whole collection yourself is to get random to offer you two – or more – candidates to choose from.

The implementation is a bit involved but still pretty straightforward.

#! /usr/local/bin/python3

import random
import requests
import subprocess

from PIL import Image
from io import BytesIO
from plexapi.server import PlexServer
from rich.console import Console

CONSOLE = Console(color_system='truecolor')
BASEURL = 'http://192.168.1.123:32400'
TOKEN = '<insert your own token here>'

plex = PlexServer(BASEURL, TOKEN)
owned = plex.library.section('Music').searchAlbums(collection='💿')

albums = {
    album.title: album
    for album in random.sample(owned, 2)
}

albumart = [
    Image.open(BytesIO(requests.get(candidate.thumbUrl).content)).resize((500, 500), Image.LANCZOS)
    for candidate in albums.values()
]

merged = Image.new('RGBA', (1020, 500))
for ii, art in enumerate(albumart):
    padding = 0 if ii == 0 else 20
    merged.paste(art, (ii*500 + padding, 0))
merged.save('/var/tmp/amp.png')


CONSOLE.print('\n')
subprocess.run(['/Applications/kitty.app/Contents/MacOS/kitty', 'icat', '/var/tmp/amp.png'])

CONSOLE.print('\nPick an album')
choices = ' '.join(['"'+albumtitle+'"' for albumtitle in albums.keys()])
choice = (
    subprocess.check_output(
        f"/usr/local/bin/gum choose {choices} --cursor '' --selected.foreground='#7851a9'",
        shell=True,
        encoding='UTF-8')
    .rstrip()
)

plex.client('KEF').playMedia(albums[choice])

CONSOLE.print(
    f'\n  [italic]Now Playing: '
    f'[#9966cc]{albums[choice].title} ({albums[choice].year})[/#9966cc] '
    f'by [#47c1ff]{albums[choice].artist().title}'
    '\n',
    justify='center'
)

Requirements: I wanted to make this aesthetically pleasing, so there are some splurgy requirements.

Steps:

  • Same imports from the simple implementation. Then a few imports for image processing, reading the album art from the server, and pretty printing in the console.
  • Get a list of the albums in the ‘💿’ collection.
  • Get the titles for two random albums, then get the album art for those two albums.
  • Merge the album art into one image. I have to do this because as far as I can tell kitty won’t let me display two images next to each other in the terminal.
  • Tell kitty to display the merged image.
  • Use gum to ask the user which album to play.
  • Tell the client to play the chosen album.
  • Display a “Now Playing” status with the album title, release year, and artist.

Other notes:

  • The characters appearing as in the code are music glyphs in the PragmataPro font I use in kitty. You can see it in the video.
  • Resizing the album art to 500×500 is hardcoded across the script. You could set that as a variable to change later. Also some album art isn’t perfectly square and will look silly when resized to a square. I might deal with that later.
  • It’s more idiomatic to use tempfile to get a path to a temporary filename. You can read more about the tradeoffs here.
  • I wrote this to make it easy to accept the number of albums as an argument instead of that also being hardcoded in the script.
  • You could build this out to also ask the user which collection they want to pick from. I plan to do just that.

And that’s it. Kinda swanky.

  1. This also has music I bought from Bandcamp, Qobuz, Boomkat, etc. But it’s mostly CDs. ↩︎

Archive