- Settle on a model I am satisfied with for multi Koto Libraries and implement it. All of it.
- Implement per-Playlist settings such as randomization and model (moving that out of the database too).
- Implement a Solarized built-in theme, since that is a fairly popular stylistic choice. I would love to hear your ideas on additional themes too, even silly / fun ones!
koto_cartographer_get_library_by_uuidkoto_cartographer_get_library_containing_pathkoto_cartographer_get_libraries_for_storage_uuidkoto_cartographer_get_libraries
koto_album_get_uuid, which returns a pointer to the KotoAlbum's UUID, which is consistent with other classes / structs we have like Artist, Playlist, and Track. This function gets used for sanity checking in Cartographer, so when we add an Album we actually make sure we don't add it when it already exists. It is additionally used in some of our Artist code and file indexer.
Once this was done, I separated out our functions responsible for reading from our database tables, moving it to reside in the same section of our codebase as Cartographer and our database helper functions. This helped clean up the library code so it would not be so unwieldy to refactor, cleanup, and mentally parse.
For several weeks after that, I was hard at work on our new multi-Library functionality. In Dev Diary 9, I mentioned that was still working on determining the best model for implementing indexing and organizing content across libraries. I am fairly happy with the current implementation, though there is always room for improvement, so time to detail the direction I opted to take.
The biggest changes to our folder and file indexing was the refactoring of the file indexing logic into a dedicated file indexing function. While this may not sound exciting, it is worth noting that this functionality was previously specific to Koto Albums. Obviously this poses a problem for content which have no albums and in scenarios where we may have music directly within a specific folder that we may associated with an artist, but in reality can by any arbitrary content, e.g. royalty free holiday music in specific folders that would otherwise be treated as artists. In scenarios where we have multiple CDs within an album, this code was added as another "depth" checking in our folder indexing function, whereas previously it was also in the Album.
To aid in simplifying the logic for our file indexing as well as track sorting, I implemented several functions:
koto_track_helpers_get_name_for_file: This function takes in the full path to the file as well as an optional name of an artist. We will attempt to get the ID3 information for the file and if successful, return the "title" tag provided by the metadata assuming it is a correct string. If it is not a valid string or we failed to get ID3 information, we use our previous file indexing logic we had in the album to clean up the file name, including removing the name of the artist, hyphens, extra spaces, etc.koto_track_helpers_get_position_based_on_file_name: This function will attempt to get the position of the track based on its file name. This existed previously as a "koto util" but was moved to a more sensible location for consistency.- Multiple sorting functions such as
koto_track_helpers_sort_tracks_by_uuidaid in reducing duplicate track sorter code. This sorting logic saw substantial cleanup, type checking, and simplification as well, so I am in a much happier place with how we perform sorting, and it is done in a manner that is consistent across the application.
XDG_MUSIC_DIR, another Library at a different mount point, and yet another on a removal storage? Also not a problem.
Each of the paths for our Artists, Albums, and Tracks are stored in dedicated tables with a reference to the UUID of that specific content type, with a collation of the metadata being stored in the respective artists, albums, and tracks tables. This reduces the overall size of our database by not storing metadata per each path, and simplifies any logic that would be required for mounting, dismounting, or indexing Libraries on the fly. These paths get loaded in and we will iterate through them as part of our dedicated "get_path" functions that we have on the various structs, like koto_track_get_path. At the moment, this will just iterate through each Library that the content is in and return the first hit, however the goal in the future is to:
- Prioritize local storage, even going so far as prioritizing local NVMe storage over HDDs when possible.
- Leverage our availability check to ignore any Libraries which are not currently available. This is especially useful for removable media devices.
This is made even more useful given we actually keep track of all KotoTracks within a KotoArtist in addition to any Albums. This is then leveraged as part of a new signal we emit during the "finalizing" of a KotoArtist called "has-no-albums" and as the name implies, informs our UI that there are no albums associated with an Artist. This enables us to dynamically swap either to the list view (if we received the "has-no-albums") or the flowbox view when there are Albums (notified via "album-added"). Since it is trivial enough to switch between them, it is quite likely that I can so some future refining to make it possible to choose one view as a persistent option, so if you prefer a list you could always use that.
This last bit of work started to get done towards the end of the last stream for this month, so there is still some work to be done on enabling playback of the entire artist via an actual UX. We now generate an ephemeral (temporary) KotoPlaylist for the Artist, similar to what we end up doing for a KotoAlbum, we just have to build a UI to start listening to that playlist, like leveraging our KotoCoverArt and its click-to-play functionality.
So yea, I did not get around to some of the Playlist settings I wanted to, or even that Solarized theme. However spending a month in the weeds of architecture is paying off and I am finally able to move on to sexier items.
Goals for July:
- Finish the implementation of the artist page in the "no albums" scenario.
- Design and implement the user experience for audiobook listing, selection, and playback.
- Implement our 10-band equalizer and playback speed controls.
