Welcome to Kirsle.net! This is the personal website of Noah Petherbridge, and it's where my various software projects and web blog lives.

Music Management

Noah Petherbridge
Posted by Noah Petherbridge on Thursday, July 28 2016 @ 08:37:46 PM

Manually managing a music collection of MP3 files on disk is such a pain in the ass that I felt like blogging about it.

First, you have cloud music services like Google Play Music which can't detect duplicates properly. The Google Music Manager will just keep re-re-re-redownloading my library from the cloud and creating duplicate files on disk over and over, with file names ending in (1).mp3, (2).mp3, etc., like it knows exactly what it's doing. Can't it just take a SHA-1 sum first and realize the MP3 I already have is exactly the same as the one they have on their side?

And then you have stupid media player programs that try to modify and reorganize your music library on your behalf. Even open source media players for Linux do this. What, do they think they're iTunes? I don't want them to touch my file system. So they end up creating duplicate songs, because they decided to update my MP3 and in the process they also decided to rename it, to be as compatible as possible with what, MS-DOS!? Only instead of just renaming the original, they copy it to a new name. And then the media player's library shows duplicate copies of the song.

On Linux I used to prefer to use XMMS as my media player. It's a Winamp 1.x clone and it has no opinions at all about your filesystem. But it was written with GTK+ 1.x and it looks ugly as sin on modern Linux desktops, and other forms of bit rot cause it to intermittently not work anymore on Fedora so I had to move on to other media players. I used to use Banshee but it seems broken atm on Fedora 24, so I'm using Clementine which really wants to touch my files and has a lot of feature bloat that I don't really need...

Nowadays I end up just tarring up my whole music folder and keeping it far, far away from where any media player will find it. So then I know I can always nuke my entire music collection and re-extract it from the tarball and be back to a known good state.

When I buy new music from Google Play, I nuke its entire downloads folder, have it download my entire library again from the cloud because it can't do anything more complicated than that, and then go in and pluck out the MP3's I just bought to put them in the tarball where they won't be touched again by any software that wants to mess with them.

I only have 192 songs in my collection so far. I can't imagine being one of those people with 20,000 songs, as problems like this would just compound themselves so much. 20,000 songs with 30,000 duplicate MP3's on disk?

And this is all to say nothing about missing/spotty ID3 tags on the files. That's the #1 reason I nuked my old collection of randomly downloaded music and started buying them back from Google and Amazon, with the assumption that the MP3s obtained from them will have full and accurate sets of metadata attached.

And why won't Clementine just shuffle my entire library instead of making me create a playlist that includes the entire library first? ffs.

XMMS apparently works again on Fedora 24

Looks like XMMS works for the moment, so I'm just gonna use that for now.

Also, Spotify is not an option. I prefer to own my own files.


[ 1 comment | Add comment | Permalink ]

A review of Linux desktop environments

Noah Petherbridge
Posted by Noah Petherbridge on Friday, June 17 2016 @ 12:11:21 PM

The next version of Fedora (24) is coming out soon, so I decided a couple weeks ago that I'd take a tour of all the different desktop environments and see if I like any of them enough to switch from Xfce. My original desktop environment of choice was GNOME 2, and I had jumped ship to Xfce after GNOME 3 was released because I was no fan of the tablet-focused, feature-stripped interface of the new desktop and GNOME 2.32 was, in my opinion, the pinnacle of the desktop metaphor for Linux.

At the time I switched, Xfce was on version 4.8 and was a little bit clunky and somewhat of a step back from what GNOME 2 had to offer; however, I somewhat liked the Xfce panel better than the gnome-panel when it came to customization. In the GNOME 2 panel, you could drag and drop applets wherever you want them, but they'd sometimes "move around" if the panel or other applets changed size (for example, by increasing your screen resolution or by the Notification Area showing fewer tray icons than it did when you put your panel together). In Xfce, the placement of each applet was an explicit configuration, i.e. you'd need to insert a Spacer Applet set to expand to fill as much space as possible if you wanted left-aligned and right-aligned applets on the same panel.

I loved the GNOME 2 two-panel layout, so I always configured my Xfce desktops to match:

Xfce two-panel layout

This blog post won't be very screenshot heavy, but I link to the websites for all the desktop environments if you haven't seen what they look like, so you can check them out.

Here's how my desktop environment tour went.


I've updated my blog!

Noah Petherbridge
Posted by Noah Petherbridge on Friday, June 03 2016 @ 03:30:02 PM

...and I don't mean by writing this post. ;)

I run Kirsle.net on a custom Python CMS I wrote called Rophako and I just added a bunch of improvements to the blog platform in it.

I've been wanting to start working on some larger blog articles, things that could take me a few days to write, and my blog had no support for saving drafts. You had to write and publish your blog posts in one sitting. The only alternative was to make the posts "private," where only the site admin(s) can see them, but that would still cause them to "go live" and be listed along with normal public posts and was a messy workaround.

So now my blogging platform has proper support for saving drafts; they stay invisible (even for admins) on all of the normal blog pages, and can only be seen in bulk on a dedicated "drafts" page. While I was putting all that together, I added similar support for private posts, giving them their own index too where you can see only those posts rather than have to go hunting for them.

For visibility purposes, draft and private posts get little tags next to their author/date lines so an admin can tell at a glance what they're looking at. Normal end users won't see those, though. ;)

I've also finally implemented a feature I wanted to from the beginning: sticky posts. The blog database schema has always had a "sticky" field, but it was always set to false and the Create/Edit Post page gave no way to change that value. The back-end code did have logic to bucket sticky posts higher on the index list than normal ones, but there was no (easy) way to make a post sticky to begin with.

Sticky posts will also get a little "[Sticky]" tag next to their author/date lines, and those ones can be seen by normal end users.

I also fixed a handful of smaller bugs/problems. I've removed the ability to set a custom date/time when editing a blog post. This caused confusion between your web browser's local time and the time zone of the server. So instead, the server always picks the latest UTC Unix time on new entries. When editing an existing entry, there's a checkbox option to reset the time to latest when saving, if you want to bump an old post to the top.


[ 0 comments | Add comment | Permalink ]

Principle of Least Astonishment

Noah Petherbridge
Posted by Noah Petherbridge on Tuesday, March 22 2016 @ 05:29:07 AM

In user interface and software design, the principle of least astonishment states that "if a necessary feature has a high astonishment factor, it may be necessary to redesign the feature." It means that your user interface should behave in a way that the user expects, based on their prior knowledge of how similar interfaces behave.

This is a rant about Mac OS X.

At my new job, they gave me a Macbook Pro to work on because they standardized around Apple products. At first I figured I would just get used to OS X, and it was difficult not to because this Macbook didn't take very well to Linux (most notably, its retina display causes problems in Linux; Linux can deal with high-density displays, but it's currently quite difficult to connect an external standard DPI monitor and get everything to scale correctly).

I ran OS X full-time at work for about three months and came to the conclusion that Mac developers apparently don't care at all for the principle of least astonishment. (Note that this isn't a jab at Apple, because most of these problems come from popular third party apps, but perhaps Apple gave apps more control than they should have over window management features).

(I eventually had them swap out my Macbook Pro with a standard HP laptop on which I installed Linux).

The OS X Dock and Window Switching

One of my biggest sources of frustration is the dock and window switching features of OS X.

The dock groups all windows of a like application into one single icon on the dock. If you have multiple windows of the same app open, clicking its dock icon will bring all of the windows to the front. Which window then has the keyboard's focus is up to the alignment of the stars. There's no option to ungroup windows into different icons.

To switch windows you hit Command-Tab (⌘Tab), which is like Alt-Tab in Windows and Linux except it only switches between applications and not windows. When you ⌘Tab to an app, again all windows of that app come to the foreground and you can't predict which of its windows has your keyboard's focus.

  • Example: Adium. Adium regularly has at least two windows open: the buddy list window and the chat window. Every single time I ⌘Tab to Adium, the buddy list window takes the focus, even if the chat window was the last one I used. I always have to then ⌘` (to switch windows between the current application) to focus the chat window.
  • Example: iTerm2. If I had two iTerm windows open, then every single time I ⌘Tab to iTerm, it would focus the opposite window from the one I had last time. For example I could ⌘Tab from iTerm "A" to Firefox to iTerm "B" to Firefox to iTerm "A". This was particularly frustrating because usually when I have two iTerm windows open it's because I want one to sit mostly idle; maybe it's watching system resources or running a long task and I didn't want it to take up a tab on my main window.
  • Example: Minecraft. Every time I would ⌘Tab to and from a Minecraft window, the Command key would become "stuck" within Minecraft. For example I'd ⌘Tab to it and start typing stuff in chat, but when I type the letter "a" it behaves as though I typed ⌘A to select all text and then I'd subsequently end up deleting it. To remedy this I'd have to again ⌘Tab away and back again from Minecraft to "unstick" the key.

Another example is Google Chrome, but this one can't be summed up with just one bullet point.

Chrome has Web Apps, and for example we'll pick on the Hangouts app. Web apps get their own icon inside of the Chrome Web Apps launcher, and when you open them, they get their own icon on your OS X dock. This sounds good in theory, but under the hood the web app is still running as Google Chrome and OS X's window management problems still apply.

Even though you have two icons on your dock (Chrome and Hangouts), they both refer to the same application. If you ⌘Tab to Chrome, Hangouts also comes to the foreground. If you ⌘Tab to Hangouts, Chrome also comes up. You still have all the same problems of not knowing which window will grab the focus when you ⌘Tab to either app. For example, if you had Hangouts active earlier, and later you ⌘Tab to Chrome, the Hangouts window gets the keyboard focus even though you wanted the Chrome window.

It appears that it is up to the individual app how they deal with their app being switched to. Some apps focus the last window you were working from, some apps focus the next window in their own list, some apps always focus a specific window every time.

You can't simply learn one time how window switching and the dock works and apply that knowledge to every app you run. If you run a new app for the first time, you can't predict how it will behave without testing it. This is a violation of the principle of least astonishment.

The Zoom Button

The zoom button is on the window title bar of most apps, and it's roughly analogous to the "maximize" button on Windows and Linux.

As of Mac OS X Yosemite and El Capitan, the default behavior of the Zoom button is to put the current app into full screen mode (not maximized). If you just wanted to maximize the window instead, you have to hold the Option key while clicking on the Zoom button, or else double-click the title bar of the window.

Most apps behave this way, but some do their own crazy thing instead.

  • Example: Google Chrome. Trying to maximize Chrome using the standard way that works in most apps does not in fact maximize Chrome. It only expands it vertically, but not horizontally. To maximize Chrome, you have to push Option+Shift+Zoom (or Option+Shift+double click the title bar).
  • Example: a past version of iTunes. I'll admit that this example is outdated, but the way iTunes behaved on Mac OS X Leopard was equally surprising. Back then, the Zoom button maximized most apps by default, except in iTunes, when it would instead shrink iTunes down into a minimalistic playback control window. The window would actually get significantly smaller instead of larger when you click the Zoom button.

I don't have other examples because thankfully my set of applications I work with mostly did The Right Thing™.

The point of my complaint about the Zoom button is that it's not possible to simply learn one time about what the Zoom button does and how to maximize a window. It appears that every app is capable of overriding the behavior of this button and do their own thing with it. If you run a new app for the first time, you can't know in advance what will happen when you click this button. This is a violation of the principle of least astonishment.

The Command Key and Other Behaviors

The command key in general is a source of many problems.

There are a few Command-key shortcuts that globally apply to all apps. These are shortcuts like ⌘X, ⌘C, and ⌘V for cut, copy and paste. Besides this, it is apparently possible for apps to bind their own actions to the command key, and one app's set of keyboard shortcuts won't necessarily be the same in another, similar, app.

  • Example: Adium again. In most apps, if you want to insert a literal line break character in a text box (where hitting Return/Enter would send the message), you would hold down Shift when hitting Return. For example, Slack behaves this way. But in Adium, this will cause the message to be sent anyway. Instead you have to hold Option and hit Return; or was it Command? I'd always screw this up three different ways before figuring it out again.
  • Example: Atom vs. all other text interfaces I used. In Atom, hitting the Home key would put the cursor at the beginning of the current line of text, and End would put it at the end of the line. In most other apps with large text areas, Home instead puts the insertion cursor at the beginning of the entire document, and End at the end of the document.
  • Example: iTerm2 and Atom's tab switching shortcuts. In iTerm2 the way to switch from one tab to the next was to hit ⌘+Left or Right arrow. In Atom, this shortcut doesn't do anything. Instead you'd do Control-PageUp or PageDn, which is more similar to how apps like Atom behave on other platforms besides OS X. I haven't tested tab switching shortcuts in other apps.

The one good thing I liked about the Command key is that it made it easy to copy and paste text from a terminal. Control-C has a special function in terminals, so being able to copy without halting the running application was a neat feature. In Linux land most terminal emulators make you push Shift-Ctrl-C to copy text.

The general feeling I got from the use of the Command key on Mac OS X is that nobody can agree on what it should be used for. Every developer uses it differently in their app, and sometimes there's no rhyme or reason for why one shortcut binds to Command instead of to Control or Option. I feel that if Linux developers decided they wanted to add a new modifier key for shits and giggles, the same sort of absolute mess would follow. Instead, for the most part, nobody in Linux makes very much use of the Command key at all (in Linux the Command key is called Super, and is the same as the Windows key on a standard keyboard). In most Linux desktop environments nothing at all is bound to the Super key, although the GNOME Shell desktop makes some use of it for window switching purposes.

In contrast, the Windows key on a Windows OS is very well defined. There are a handful of global Winkey shortcuts (for example, Windows+R to open the Run dialog, or Windows+L to lock your screen). These shortcuts apply globally throughout the OS, and no third party software that I'm aware of binds their own shortcuts to the Windows key. If that's even possible for an app to do, I don't know. Mac OS X would be better off not allowing application writers to bind custom actions to the Command key because they clearly can't be trusted with it.

This keyboard shortcut mess is a violation of the principle of least astonishment.

I'll probably update this blog post with additional examples as I find them. I still dual-boot my personal Macbook Air with Linux and OS X.

Managing Your $GOPATH for Multiple Go Projects

Noah Petherbridge
Posted by Noah Petherbridge on Friday, March 18 2016 @ 04:40:34 AM

This is a cool tip I picked up from checking out other peoples' Go projects.

When you're new to Go, the documentation tells you about $GOPATH which tells Go where to install packages and where the source codes to your project and its dependencies live. A lot of people might set $GOPATH to be $HOME/go, and work on their projects out of ~/go/src/github.com/myname/myproject.

Using one global GOPATH like this has its problems though:

  • You have to git clone your projects into ugly directory paths to make sure they're inside the GOPATH. I usually prefer to just have a folder like ~/git/myproject instead, and I don't want to symlink it into my GOPATH so that Go finds it.
  • The third-party dependencies of all of your Go projects get intermingled in the same GOPATH. This is especially problematic if two different projects need the same third-party dependency, but they use different versions of that dependency.

So, the solution I found to this problem is to use a Makefile for your project that creates a private GOPATH for you. Here's an example Makefile from one of my projects:

CURDIR = $(shell pwd)
GOPATH = "$(CURDIR)/.gopath"
all: build

# `make setup` to set up git submodules
    git submodule init
    git submodule update

# `make run` to build and run the bot
run: gopath
    GOPATH=$(GOPATH) GO15VENDOREXPERIMENT=1 go run cmd/scarecrow/main.go

# `make fmt` runs gofmt
    gofmt -w src

# `make build` to build the binary
        go build -i -o scarecrow cmd/scarecrow/main.go

# Sets up the gopath / build environment
    mkdir -p .gopath/src/github.com/aichaos/scarecrow bin
    ln -sf "$(CURDIR)/src" .gopath/src/github.com/aichaos/scarecrow
    ln -sf "$(CURDIR)/vendor" .gopath/src/github.com/aichaos/scarecrow/src

My project's directory structure is laid out like this:


With this project layout, the bulk of my source code is under the /src directory (to keep the root of the repo clutter-free), the actual executable program is under the /cmd directory, and third-party dependencies are under /vendor (using the Go 1.5 vendor experiment).

Instead of running go run cmd/scarecrow/main.go, I type make run. My Makefile then generates a custom private GOPATH at /.gopath, makes symbolic links to all the relevant files underneath, and runs the program from the context of that GOPATH.

The ~/.gopath directory structure looks like this:

          /src -> ../../../../../src (link)
            /vendor -> ../../../../../../vendor (link)

This way the private GOPATH has all the necessary directory structures that Go needs to find my project's source code and its vendored modules, and I don't have to clutter my global GOPATH. Also, this makes it easy to just git clone my project any place I want, like ~/git/scarecrow and not worry too much about the Go configuration.

As a side note, with the Go 1.5 vendor experiment I used git submodules to add the third-party dependencies to my project. On a fresh git clone I just type make setup which initializes and clones the submodules.


[ 0 comments | Add comment | Permalink ]

Web Tools

Fan Club