Featured image for Dev Diary 2: Koto February Progress Report (A-side)

Dev Diary 2: Koto February Progress Report (A-side)

February 17, 2021

In this development diary, I provide an update on progress made on Koto in late January and first half of February 2021.

#Background

Current Mockup of local music As a short background for those that are not familiar, Koto is an in-development audiobook, music, and podcast manager that is designed for and caters to a modern desktop Linux experience. It is intended to be a unification of the benefits of both streaming services (content discovery, synchronization) and local content, as well as a bridge where necessary. I provide a deep-dive into it in my Dev Diary 1: Koto - Foundations blog post.

#Bootstrapped

During the first stream of Koto, I worked on bootstrapping Koto, that is to say I set up the project (which GNOME Builder was an immense help in enabling, especially with the Meson build files and postinstall bits) and some of the initial structure to the application, such as the GtkWindow, HeaderBar, etc. There was a lot of fumbling about early on, since my more formal introduction to C aside from needing to patch other software (or the kernel) was just days prior starting with a rather well written C Primer by the Enlightenment Foundation Library (EFL) developers. Writing GTK applications in C was foreign to me, not to say there is not considerably more to learn about GTK and GLib still. I was fairly optimistic early on that the application would be GTK4 and while that is certainly remains a possibility for the future, unfortunately there was considerable changes made in GTK4 which made sub-classing some classes, such as the GtkHeaderBar, no longer possible. This is actually something I discovered when researching a compilation error and it turns out there is actually a Vala issue filed regarding it as well. Sub-classing is especially useful because it enables you to derive your own classes (in our case of the GtkHeaderbar it would be a "custom" headerbar with our own methods, members, etc.) while inheriting the variables and methods of its parent class. If you ever have watched Mad Max, you can imagine it like bolting on a bunch of stuff to one of the vehicles. You got your spikes, flamethrowers, human catapults, instruments. Fundamentally it is still a vehicle, you just added on to it. Going from GTK3 to GTK4 means losing out on the ability to add your own spikes and flamethrowers, which is not really fun. You have to put in the extra work to change your implementation, work that should not have been necessary (IMO) to begin with. So for now, I am working on Koto as a GTK3 application while still experimenting around with EFL (more to save myself from GLib than anything else). I am remaining cognizant of the changes made between GTK3 and GTK4 and relying less on functionality that has gone away to hopefully reduce any future headache in a GTK3 to GTK4 migration should I desire to make that move. At the moment, GTK4 "stable" is in its early days, so we may see improvements made without breaking ABI that will make the transition easier down the road. crosses fingers This initial bootstrapping additionally involved me tinkering with the Glade UI templating. I ended up getting fairly frustrated with the graphical, drag-and-drop-esque experience integrated into GNOME Builder and not feeling like wanting to write XML, I just started opting to manually program the rest of the widgets in C. I still need to go back and replace the GtkWindow UI and Headerbar templates, but overall that work is fairly trivial. The benefit of not engaging so extensively with the templating system is I ended up diving head-first into the world of GLib macros for defining types and Object instantiation much sooner than anticipated, which is crucial to building up your own widgets.

#Widget Galore

While having the Matryoshka doll equivalent to classes and widgets (where a widget is used in another widget, which builds on top of yet another widget) might sound convoluted, if done right it can lend itself to a simpler, more consistent codebase, as you are centralizing the logic for various functionality, whether that is something as simple as updating an icon in a custom button to having shared logic for navigation to a generic content indexing backend. Over the last couple weeks of streams, as the foundations for Koto's backend and frontend have developed, I have been proactively working to reduce code duplication. Some examples:
  1. Initially when implementing the PlayerBar, I had some repetitive code for generating various buttons for backwards, play / pause, forward, etc. buttons. I recognized this was going to be a problem quickly and changed it to be a utility function called koto_create_flat_icon_button which took in the name of the icon and the desired size, applying the flat class and returning the GtkButton. Nothing crazy.
  2. During my second stream when I was diving into building out the Koto sidepane navigation widget class (KotoNav), I recognized that across the primary navigation as well as the Devices sidepane, there would be duplicate logic for the expanders. So I implemented a KotoExpander which has a custom header and uses the GtkRevealer to toggle the visibility of content we set via a GtkBox. Furthermore, I implemented a KotoFlipperButton which allows us to easily flip between two different images / icons for a GtkButton, enabling us to for example switch between ▼ and ▲ caret icons depending on the Expander state.
  3. During my third and fourth stream, I implemented a shared KotoButton class to leverage across various parts of the UI, immediately moving to leverage it in the KotoExpander. This enables me to have unified logic for buttons with icons and images (both treated as GdkPixBuf), text, and even a custom badge (useful for indicating in the navigation that you have new podcasts to listen to, as an example).
In the near future, my previously implemented koto_create_flat_icon_button function will be deprecated in favor of using the KotoButton for our expander arrows, and KotoFlipperButton with either be deprecated or switched to sub-classing our KotoButton. To break it down a little better, here is a wire-frame design of Koto that details how is / it will be (after the above mentioned deprecations and sub-classing). Some of the dimensions are exaggerated to assist with visualizing, other design elements omitted that are not relevant. In the end, having these custom widgets will allow us to iterate on the design much more quickly, especially as we built it out alongside various parts of the internal works.

#Indexer

Towards the end of the stream which took place on February 9th 2021, I started work on the file indexer for Koto. This file indexer will be responsible for iterating through a list of content libraries provided as directories, currently set to XDG_MUSIC_DIR but will be expanded on as the indexer work continues. It will look for files in the immediate directory, as well as all sub-directories, and does so on a separate thread to prevent blocking the UI. This iteration is done through usual syscalls like opendir and readdir to get the directory entry structs. When we encounter a file, we leverage libmagic to get the MIME type of the file, rejecting anything that isn't an audio file (starts with audio/) or an image file (image/), as these are currently the two types of files we care about. No doubt it will be expanded on in the future, but the primary task at the moment is to take all that information, and break it out into the following structures:
  • KotoIndexedLibrary: This will hold references to all our indexed content for that specific library, such as audiobooks, podcasts, and music. Within the library structure, we will have a HashTable (think of it as a basic key/value storage) for various content, currently music_artists. The value of each artists is a KotoIndexedArtist.
  • KotoIndexedArtist: This structure will detail the name of each artist, the path to the artwork for the artist (if any), the filepath to it on the system, and contains a HashTable of albums, the value of each album is a KotoIndexedAlbum
  • KotoIndexedAlbum: This structure will detail the name of each album, the path to the artwork (if any), and a HashTable of songs, the value of each being a KotoIndexedFile.
  • KotoIndexedFile: This structure simply has the "parsed name", file name and path. The parsed name is expected to be either extrapolated based on various formats (01 - In Your Honor from the In Your Honor album of Foo Fighters just being In Your Honor as the parsed name) or from the ID3v2 information. I expect this indexed file data to grow significantly as we integrate playlists, tags, genres, etc.
At the moment, we are not adding any information into those structures, this is expected to occur over the next couple weeks as we build out the indexer in preparation for more UX development.

#Summary of Work

Over the last few weeks, the following has been done:
  1. Initial bootstrapping of the project.
  2. Building several widgets, taking the project from being just a window and a headerbar to having a playerbar, navigation, and a clear separation between the navigation and "primary" content view.
  3. Beginnings of the file indexer.

#Upcoming

Over the next couple weeks, my goals are:
  1. Migrate the KotoWindow and KotoHeaderBar away from using Glade UI templating.
  2. Deprecate koto_create_flat_icon_button and update KotoFlipperButton to leverage our new KotoButton.
  3. Leverage the file indexer in building our the structures we have made currently, changing them as needed.
  4. Investigate various ID3 parsing libraries to determine the best to use (e.g. id3lib and taglib).
  5. Design the Sqlite database schema and begin to perform transactions based on our structured data.
  6. Set up SASS / SCSS compilation and move existing styling from CSS to SASS, continuing to polish the user experience to reflect the mockup as time goes on.

#Streams (So Far)

All development streams happen on my Twitch every Tuesday and Thursday from 12pm-5pm GMT+2 / EEST (Eastern European Standard Time). If you miss these streams, Iupload all of them to Odysee so be sure to check them out!