9 years of hacking, (Still) Searching for the Perfect Media Player

Fae
7 min readFeb 28, 2016

--

A long time ago, there was Winamp and Foobar2000. And for a while I was happy using a mix of the two. But they had some really annoying bad habits.

Frequently “I accidentally your playlist” with no warning or undo. Losing all metadata when a file path changed, or generally just being poor at looking after metadata. And having an inexplicable allergy to to mixing audio and videos in the same list.

In December 2006 I had an idea and wrote a blog post on Live Journal (it was that long ago). It had nothing to with any of the above annoyances — fixing those came later. It started with an idea for a better way to do “shuffle all”.

So I had a go at implementing it, and then sort of never stopped.

More than just random.

As a self-taught “programmer” who had no idea what she was doing and who only really knew one language, it got written in that. And that language was VB6.

But I was strangely determined. I still don’t really know why. And I knew quite a lot of VB6 thanks to reading literally hundreds of examples on Planet Source Code. I wrote my own “controls” (widgets) and did lots of owner-drawn UI directly via the Win32 API (it performed so much better than the built in VB6 APIs).

Little details are important.

And after getting something sort of working that did this new way of random play all, I moved on to adding all the other things that annoyed me in other media players. Lots of little things like being able to easily choose which screen it went full screen on. I solved the “keeping metadata when files are moved” by hashing (MD5) every file and matching by hash when files appeared and disappeared. It tracked play starts and finishes separately so I could sort of work out which tracks I skipped a lot.

A copepod icon.

I called it “terra” because it seemed like a good name at the time and the icon was a copepod extracted from a picture taken by a prototype Continuous Plankton Recorder because I was a marine biologist and it seemed liked a good thing for an icon.

The final edition of terra looked something like this.

The last .exe build I have for terra seems to be dated December 28 2008. I guess this is around the time I realised I had reached the limits of what it was worth building in VB6. Belatedly SCMed src is on GitHub, though I doubt it will ever be relevant ever again.

Because terra was made in VB6 it only worked on Windows, and by 2009 I desperately wanted to move everything to Ubuntu, a full rewrite was required. I eventually settled on Java (which I was still very new to) and the Eclipse RCP UI framework, as it seemed the best choice for native looking cross-platform support and I really wanted positionable panels.

This rewrite was called Morrigan, suggested by a friend as a sort of pun and reference to terr(a|or). Morrigan’s first commit was August 10 2009. I took a week off work and started coding. But it took quite a while to get feature comparable with terra. My last use of terra might have been around March 2010.

I carried over the SQLite DB schema from terra. There have been many schema updates, but essentially I have been using the “same” DB instance since 2006, and still going.

Morrigan’s GUI now looks like this.
Exhibit A: How not to use interfaces and inheritance. Very Enterprise.

Quite some years later and still working on the same code base… there are definitely some code design decisions I deeply regret. Because even by the time I started writing Morrigan I still did not really know what I was doing and just did things that seemed like a good idea at the time.

But I don’t have the time or motivation to rewrite it all right now. So recent changes just hack around past me’s poor choices.

As well as the RCP UI there is also a terminal UI you access by ssh-ing directly to the JVM (using Apache Mina’s sshd). I don’t actually use this UI that much, but it was fun to make.

There is also a terminal UI.

And then over the past couple of months I have been rebuilding the web UI using Material Design Lite. It is nice to use on both desktop and phone browsers, so I am quite happy with the result.

My phone is the remote control.

Aside from endlessly rewriting the UI (and never having all the features available in any one of them), I have also been working on making it interoperable via DLNA.

So now it play via external players (file format support permitting), can search and play media on external DLNA shares, and other DLNA things can access its media.

Given their price, I am very impressed with the Chromecast hardware. The only disappointing thing about them is their lack of any standard interface. But they do have an API. Instead of trying to add Chromecast support directly to Morrigan, it seemed better to try and make a Chromecast look like something standard, and I already had DLNA support… So I made Toadcast, a standalone Java service that advertises as a DLNA player but actually proxies all commands to a pre-chosen Chromecast.

So I run Toadcast on my home server along side a headless install of Morrigan. When I click play in a Morrigan UI it tells Toadcast to play which tells the Chromecast to play.

It works surprisingly well. The only downside is that Chromecasts have limited file type support. For example it can not decode MKV, and the Chromecast Audio can not play video files (i.e. just the sound from video files). I started to prototype Transtoad, a UPnP service that dynamically transcodes to formats that Chromecasts like, but that is far from usable yet.

If I do create Transtoad to help Toadcast play media as directed by Morrigan, I fear I will have accidentally microserviced my home media system. Oh and there is also DLNAtoad, another small Java service that shares the directory its started in via DLNA.

However…

The problem I had when making terra still applies now — since I am writing code on my own and just for me, it is full of strange issues and edge cases. I rarely find them as I always use it exactly the way I had indented to use it. Also I put up with its inconsistencies and gaping feature omissions because I care / don’t care about my specific uses.

But I used terra nearly every day for ~5 years and since 2010 I have used Morrigan nearly every day. While written as shonky hobby code to try and solve a curiosity, they were strangely battle hardened by persistent daily use. I needed something that worked in a certain way, so I made it. This stuff has only really ever had one user and that user is me. But I used it every day, for years on end and it became a (small) part of my life. Along with my Twitter client (started 3 years ago) these are things that no matter how many hours I put into making them, I will still spend way more hours using them.

For me this seems totally normal, obviously any prolonged use of tech is going to require writing some code to fill in the gaps. That is just how it is. Is this unusual? I have met many developers, but know really very few who maintain long-term personal code like this (or I just haven't been paying attention and don’t know that they do).

While I would love for other people to have a play and try and use some of my stuff (its all on GitHub), be warned that some of it is not going to be obvious how to use out the box. But if you do try, please feel free to ask me questions.

Also please keep in mind that this media player thing is just a work in progress and not really finished yet.

--

--