Dear Reader,
Firstly my apologies that this issue has landed in your inbox slightly later than scheduled. I was ill just before the holidays and then my family were ill during them so I didn’t get the writing time I’d initially envisioned before finishing for Christmas! However, I still managed to work on a number of different projects over the festive period including a further update to the Music Library Tracker, an update to one of my personal logging apps for the books I’m reading, an overhaul of an app I built to track mine and a friends gaming time, and a new iPad app idea to entertain my children in the car (and possibly save my wife from being propelled through my windscreen).
Unfortunately during the collation of this issue it became clear that it was becoming a bit too lengthy even for me so I’ve left out the discussion around my Game Track app. Look out for that in the next issue as I still have a few features to add!
As a bonus (maybe), I’ve put together some end of year recommendations based on the games I’ve played and various media I’ve consumed throughout 2022.
I hope all of you had a wonderful Christmas and were able to get a decent amount of downtime or time to work on your own projects depending on your own preferences. I personally can’t stand to not do any coding across the holidays – I literally feel withdrawal after a few days – but I do try to only work on smaller fun projects rather than doing anything “serious”.
Finally, many thanks to all of you who picked up a copy of Return To Dark Tower Assistant. I said in the last issue “it may only get single-digit downloads, but it’s an app I’m proud of”; happily, it’s close to breaking 100 downloads which was very unexpected. Thank you to all those that spread the word or got it for themselves.
I hope you’ll find something of interest in today’s issue and I look forward to hearing any feedback you may have.
— Ben
Contents
Music Library Tracker v2.0 build 3
Bookmark, an app for logging reading time
Back Seat Shuffle, an iPad prototype
End of year recommendations
Roadmap
Music Library Tracker v2.0 build 3
First of all, a big thank you to all of you who joined the Music Library Tracker TestFlight Beta from the last issue and to those of you who got in touch to report issues or provide other feedback. This is the first time in a long while that I’ve provided beta access to one of my projects so I’m very grateful to all of you who have made the process worth while.
Due to all of the feedback, there are a few issues that have come to light that I’ve been working to address.
Playlist generation
It appears that some of the Spatial Audio BETA playlists are not containing all of the tracks that are listed within the Spatial Audio tab in the app. I’ve tweaked the way these playlists are generated so songs are added in batches which will hopefully alleviate the problem (I haven’t been able to replicate this as I only have a few hundred upgraded tracks, alas). If you go into the settings panel within the app, you’ll find a new button that lets you recreate your playlist so if you are affected by this issue please hit that button to see if it resolves the issue.Spatial Audio matching does not work on macOS
To be honest, the macOS build was not something I’d planned but is instead a consequence of Apple’s move to it’s own CPUs (“Apple Silicon”). If you have one of their newer machines, you can install iOS apps and use them in a mode akin to an iPad simulator. I hadn’t paid this any mind as the APIs I use to access the media library do not exist on mac so I assumed this wouldn’t work but I’ve had people message in to say the app itself with it’s monitoring of your library does actually work on an Apple Silicon mac! However, this new Spatial Audio feature doesn’t work likely due to the APIs not returning the correct identifiers. I need to look into this in more detail but it looks likely that I’ll need to just hide the Spatial Audio tab on macOS if it doesn’t work there.Sort options within Spatial Audio tab
At the moment the tracks are sorted by artist name, then album name, then track order but I’ve had a request to provide a few more sorting options in the same way that you can sort tracks in other areas of the app. I’ll add this in the next update.The app shows tracks that are no longer available in Spatial Audio
This is a bit of a trickier one. I had naively assumed that if a track were upgrade to Spatial Audio then it would stay that way. To that end, the database I built will stop checking the details of a track that has been updated as it was a waste of server resources. It turns out that tracks can revert back to non-Spatial Audio issues; this is allegedly due to them being created via upmixing software which Apple does not allow (so they get onto Apple Music and then are pulled when Apple enforces it’s policy). I’m going to update my Spatial Audio Finder in the first instance so upgraded tracks can be reverted back to non-Spatial status but how to handle this in the app is a little trickier as I’ll need to always send your entire library for matching and then somehow flag when a track has been removed from the list (and remove it from the auto-generated playlist). My idea at the moment is that this is something that should likely appear within the regular “Activity” section of the app and would show as a change of the track metadata. In any case, it was too much to think about during the Christmas break so I shall put some thought to it before the next update!
I think that is most of the feedback covered. As I mentioned, the tweak to the Apple Music playlist generation should be available for you now in TestFlight and will show as v2.0 build 3. I’ve also added an option within the settings panel to disable the Apple Music playlist should you not wish to have this feature (it is enabled by default).
If you have not yet tried out the update, you can use the button below to download the beta for free.
* Music Library Tracker v2.0 will run on any iOS device running iOS 13 or greater. If you already have Music Library Tracker installed then this will update that version; you won’t be able to downgrade. This beta will expire when the app update is publicly released in January.
I would greatly appreciate any feedback you may have, especially if you run into any problems with the Spatial Audio matching. You can always comment on this post, provide feedback directly through TestFlight, or email me via ben@bendodson.com.
Also, feel free to publicly share any screenshots, videos, or thoughts on the app update (although I’d obviously prefer you share any issues you encounter with me first!)
Bookmark
I love tracking what I do. I don’t know why, but I get a sense of satisfaction in seeing what I’ve done over a particular time period (as you’ll see when you get to the recommendations in this issue). My current suite of tracking apps are:
Video games - custom app named Game Track
Board games - Board Game Stats
TV shows - Trakt
Films - Trakt
Books - custom app named Bookmark
Projects - Timery for Toggl
In addition I track a number of health metrics, mostly from the Apple Watch and a variety of apps that work with HealthKit.
A few years ago I built an app I named Time Well Spent for keeping track of the books I was reading, TV shows I was watching, and projects I was working on. The app was my first foray into SwiftUI and I also experimented with Swift as a backend service using Vapor on top of a Heroku instance. Whilst the app worked, I was never happy with the backend stuff as the code was all a bit of a mess and it would take around 10 minutes to push a code update to the cloud due to the number of dependencies, etc, that Vapor had. I’d also decided to use MySQL as that was what I was most familiar with and so the code ended up looking like this:
return req.db.transaction { (db) -> EventLoopFuture<Book> in
return session.save(on: db).flatMap {
return BookModel.query(on: db)
.set(\.$remaining, to: progression.remaining)
.set(\.$progress, to: progression.progress)
.set(\.$editions, to: editions)
.set(\.$status, to: book.status)
.filter(\.$id == book.id)
.update()
}.transform(to: book)
}
I had very little idea how that was working back when I wrote it and I have zero idea now! All those nested returns and weird maps 🤢
The first thing to go was TV shows. I was manually adding artwork and metadata to my database to have them show up but I was never really happy with the process. I’d been using Trakt as a VIP member since 2012 for showing me the air dates of my shows so I have no idea why I wasn’t always using it to track the TV and film I was watching. When I realised I could hook it up to Plex so it would automatically tell Trakt when I finished watching something, there was almost no need for an app at all (although I do now use the official Trakt app when watching stuff on Netflix, Disney Plus, etc).
The next thing to go was projects. I had started using Timery to track how much time I was spending on client work. As all of that data was available via an API, it made sense for me to use the same process (using a Stream Deck) to track when I was working on my own side projects. I wrote a PHP script that ran every day to fetch my Toggl data and store it in my own database for projects assigned to “Dodo Apps Ltd”.
That meant the app was now only used for tracking books. You may wonder why I haven’t moved to a 3rd party app for this? Well, I’ve just never found one I liked. The closest I came was using Bookly but I absolutely detested the UI. Other apps have come and gone but the main thing I wanted was a way to agnostically log my place in a book; this should not be done on “page number” as nearly every app does as a page might change. For example, on my iPad I might be on page 200 of 358 but on my iPhone that might be 780 of 1419. Page numbers can even change on the same device due to switching fonts part way through or even an iOS update or new piece of hardware changing the visible space. The other requirement was that I could log time against multiple versions of a book; this was usually when reading on both iPhone and iPad but I would occasionally have both the paperback and eBook version and alternate between them depending on my mood.
The Time Well Spent app I built addressed all of these issues (I’ll show you how shortly) but had a tab bar interface for Books, TV Shows and Projects. All I needed to do was remove those unnecessary tabs and then I’d have my book logging app. The only other minor issue was that I had recently bought a Kindle Paperwhite and wanted to add that as an option when I logged a book; that should be fine, it was just an enum in the project after all... except it wasn't; it was also an enum in the Vapor server app which meant I’d need to recompile that and the recent Xcode changes meant that was a far more taxing prospect than I was willing to make. I left it for a few months and just logged Kindle books as "paperback" but I finally put my foot down last week and rebuilt the server code in PHP. This saved me $7 a month on Heroku hosting1 and let me add Kindle as a viable option within the app.
The app is now complete and rebranded as Bookmark:
The initial page lists the number of books I’m currently reading along with percentage completed and estimated time to finish reading. When you tap into a book, you can see the same stats along with the number of “editions” I currently have along with the option to add another (so I can track an iPhone and iPad version of the same book). The final screen is the data for the current edition which requires a position, introduction, and length; this is all agnostic as I mentioned earlier in that it isn’t necessarily a “page” as those can change in the digital world (although Kindle does have a static id known as a Location).
The formula for working out the percentage completed is very simple:
progress = (position - introduction) / (length - introduction)
Calculating a rough “time remaining” is also fairly simple:
(1 - progress) / (progress / totalHoursSoFar)
With this I end up getting a fairly accurate idea of how long it will take me to finish a book. Crucially, this is also accurate after just one logged session as the introduction of a book is taken into account. With other apps, I’ve found that a 30 page foreword or front loaded illustrations and maps can drastically skew reading time with it only becoming more accurate the further you get through the book.
These calculations also work well if the length parameter changes. For example, if I change the font size on my iPad then I just update the length and everything will still work as I’m not calculating the change between reading sessions but instead logging the duration I read for along with my current position as a percentage.
The final thing I added was support for audiobooks:
The difference here is that I only want to log how much time is remaining; there is no need for a duration as it can be determined automatically and I don’t need to worry about the intro as there are no “how long to finish” calculations. However, it’s all stored in the same way; the UI is asking for time remaining but it will just subtract that from the length to determine a position in seconds and store that.
Oh, I also updated the app icon:
The previous icon when the app was Time Well Spent was based on the Swiss Railway Clock but for Bookmark I decided to show a red bookmark over the top of some text from the opening chapter of one of my favourite books, The Prince by Niccolò Machiavelli.
I highly doubt I’ll do anything else with this app as it is built purely to deal with my idiosyncrasies with time and reading on multiple platforms. For most people Book Tracker or Bookly are fine choices but if you’re reading this and thinking “I want this app” then let me know!
Back Seat Shuffle
If I’m going on a long drive with my two young children, I’ll load up an iPad with some videos and stick it in a pouch on the back of a seat to keep them entertained. Initially this started as a few films and a couple of their TV series on a USB-C stick but I’ve gradually started putting a few shows directly onto the iPad so they can be played via VLC. Why? Well, when using an external drive you’re limited to using the Files app which uses Quick View for video playback; this is fine for a film but for TV you have to go and start a new episode after the previous one finishes (and that involves my wife precariously leaning into the back without a seatbelt which isn’t ideal). I moved to using VLC for TV shows as they then play sequentially avoiding that problem but it can’t play from an external drive so I have to put things directly onto the limited storage of the device.
For a couple of weeks I’ve been toying with the idea of whether I could build a better app, one that would let me:
Plug in an external drive
Show each series with a nice image
Play episodes randomly without needing to copy the video to the device
After a 3 hour drive to visit my mother, the priority for this has now increased exponentially 😂
To begin with, I needed to know if it is even possible to view external files within an app on iOS. It is, and has been since the introduction of UIDocumentPickerViewController
in iOS 13 however the documentation left me a little confused:
Both the open and export operations grant access to documents outside your app’s sandbox. This access gives users an unprecedented amount of flexibility when working with their documents. However, it also adds a layer of complexity to your file handling. External documents have the following additional requirements:
The open and move operations provide security-scoped URLs for all external documents. Call the
startAccessingSecurityScopedResource()
method to access or bookmark these documents, and thestopAccessingSecurityScopedResource()
method to release them. If you’re using aUIDocument
subclass to manage your document, it automatically manages the security-scoped URL for you.Always use file coordinators (see
NSFileCoordinator
) to read and write to external documents.Always use a file presenter (see
NSFilePresenter
) when displaying the contents of an external document.Don’t save URLs that the open and move operations provide. You can, however, save a bookmark to these URLs after calling
startAccessingSecurityScopedResource()
to ensure you have access. Call thebookmarkData(options:includingResourceValuesForKeys:relativeTo:)
method and pass in thewithSecurityScope
option, creating a bookmark that contains a security-scoped URL.
External files can only be accessed via a security-scoped URL and all of the tutorials I’d seen online relating to this were demonstrating how you could access a file and then copy it locally before removing that scope. I was therefore unsure how it would work in terms of streaming video (as it would go out of scope and lose security clearance) nor if I’d be able to retain access after displaying a directory and then wanting to start playback.
It turns out that it is all possible using a system known as “bookmarks”. In practice, a user will be shown their external drive in an OS controlled modal view and can select a folder, the URL of which is returned to my app. I then call the “start accessing security scoped resource” and convert that URL to a bookmark which is stored locally on my device and then close the security scoped resource. That bookmark can be used at any point to gain access to the drive (so long as it hasn’t been disconnected in which case the bookmark tells the app it is “stale” and therefore no longer working) and you can then interact with the URL the bookmark provides in the same way as you would with a local file.
I now have a basic prototype working which lets me select a directory and starts playing a video. I’ve named it “Back Seat Shuffle”.
All I need to do now is build out the actual interface so it looks a bit nicer and then the autoplay functionality so it will play another random video from the same directory when the current one ends.
Why have I told you this fairly long-winded and technical story? Well, this is one of those apps that will never see the light of day beyond the one very specific device I use in the car maybe twice a year. However, it demonstrates how you can approach any project:
Idea > Investigate > Prototype > Complete
I see people every day online that think the first part, the idea, is everything. That’s not true, but neither is it sensible to try and take your idea and jump to the end stage without a) investigating whether it is even feasible or b) testing the core functionality to make sure it works.
With this app, I was unsure whether APIs would exist to allow this (as it isn’t a feature in a great many media apps I’ve tried) so I needed to investigate; that showed that it looked possible but I was still not 100% clear on how it would in practice hence the need for a prototype. The joy of working this way is that you can see incremental progress towards your goal and the work required to get from prototype to finished app is mercifully small!
End of year recommendations
As we’ve come to the end of 2022 I thought I’d do something slightly different this issue and instead pick my favourite video games, board games, TV shows, films, and books from across the year.
Video Games
I played 94 different games in 2022 for a combined time of 639 hours (~26.5 days)2. This was split across Xbox (345 hrs), PC (176 hrs), Steam Deck (48 hrs), iOS (39 hrs), Switch (28 hrs), Playdate (2 hrs), and Quest (0.5 hrs).
My most played games were:
Elden Ring - 104hrs
Farming Simulator 22 - 74hrs
Rocket League - 53hrs
Stardew Valley - 38hrs
Vampire Survivors - 30hrs
My favourite games were…
#3. Citizen Sleeper
This was the hardest slot to pick as there were a number of very good games this year, but I think Citizen Sleeper gets it for the way in which it mixed up a well written cyberpunk story with a cool dice mechanic plus the clocks mechanic from Blades in the Dark. It’s available on Game Pass and has had some free DLC updates already so definitely worth trying.
#2. Tinykin
I’m a big fan of “collectathon” games like Banjo-Kazooie so Tinykin was a wonderful surprise when it appeared on Game Pass. It evokes those old collectable games from the ‘90s but improves the user experience significantly with a high level of polish. It is also beautiful to look at with it’s mixture of 2D cartoon characters in a rich “Honey I Shrunk The Kids” style world. This would easily have been my #1 if not for…
#1. Elden Ring
I’ll go ahead and say this is probably my favourite game of all time, something I don’t say lightly. I had never played a FromSoftware game before and typically do not like “hard” fights so it was a surprise to me when a few days before launch I decided I’d give it a try, and then an even bigger surprise when it sunk it’s hooks into me and didn’t let go for over 100 hours. The fights are hard but your ability to go away and level up by exploring mean that you’re never really stuck. However, it’s the exploration that got me. This game is huge. Seriously huge. It’s also detailed. Insanely detailed. I haven’t experienced the thrill of exploration in this way since Breath of the Wild and this takes that and dials it up significantly. There is so much to see and do yet I know I have not seen anywhere near everything. This game pretty much ruined the rest of the year for me as there was nothing even close to being in it’s league. Since finishing it I’ve watched countless hours of lore videos on YouTube, bought 2 huge bound books that detail every aspect of the game, and gone all in on the most expensive pledge for the upcoming board game. This is not just the game of the year, it is the game of the century.
Board Games
I have only recently started tracking the time I spend on board games so I don’t have any particular breakdowns this year. Instead, I’ll share my top 3 games I played in 2022:
#3: Escape the Dark Sector
A fun little game for 1-4 players that sees you trying to escape a space station in a narrative adventure akin to a Fighting Fantasy book, just with cards and a beefier combat mechanic based on dice rolls. I’ve only played it a couple of times but I really dig the black and white sci-fi aesthetic and the narrative gameplay.
#2: Sleeping Gods
If Escape the Dark Sector was my favourite bite-sized narrative adventure, Sleeping Gods is my buffet-sized narrative adventure. You crew a ship in the 1920s that has been lost in a strange world and need to find your way home. The game comes with a giant atlas which you sail across and a “choose your own adventure” style tome that is filled with quests to complete and choices to make. One of my favourite things is that you unlock keyword cards when you complete certain tasks and these keywords open up extra choices in the narrative; it’s a very smart way of taking the branching dialogue of something like an Inkle video game and bringing it back to the tabletop.
#1: Return to Dark Tower
I already talked about this game a lot last issue but it was definitely my favourite game this year due to the way it takes an app-driven board game to the next level by letting the app control a physical component on the table. A grown man shouldn’t squeal with delight when a plastic tower lights up or makes a sound but I do. Every. Single. Time. I like the game so much I made an app to improve the speed of play. I’ve ordered the upcoming Covenant expansion along with a backorder of the previous Alliances expansion so looking forward to hopefully getting some new content to play with later this year!
TV Shows
I watched 33 TV shows for a combined time of 217 hours (~9 days) in 2022. It’s incredibly hard for me to even pick a top 3 as there were a lot of great shows including Severance, The Lord of the Rings: The Rings of Power, Star Wars: Andor, Only Murders in the Building, and House of the Dragon. Any of those could have been up there as they each had their own special moments (although I will give a shout out to Andor and House of the Dragon as I had such low expectations going in!).
They all pail in comparison to the final season of Better Call Saul though which is my #1 recommendation this year. There simply wasn’t anything to match the characters, storylines, and incredible art direction3. There are a few niggles I have with the ending but even still it towers above everything else on my watched list.
Films
I usually don’t watch a large number of films so I kicked the year off with a weekly “Monday Movie” with the aim to watch 50 films by the end of the year. I managed 38 but ashamedly 18 of those were Marvel films due to me trying to keep pace with the new podcast Marvel Calls (I’d only ever seen a handful so it’s been interesting to go through them and understand more of what is actually happening in Guardians of the Galaxy, for example).
I only watched four films that were released this year – Death on the Nile (it was alright), Chip ‘n Dale: Rescue Rangers (surprisingly good), The Bob’s Burgers Movie (better than expected), and Glass Onion (wait for it) - so instead I’ll just pick the 3 films that I enjoyed the most this year from everything I watched:
#3: Calibre
The story of a pair of friends who go shooting in the Scottish Highlands and end up attempting to cover up an accident. I won’t say more than that but I think about this film a lot. Excellent acting with a small cast in a slightly creepy village. Highly recommended.
#2: Glass Onion
I told you we’d get there. The sequel to Knives Out (which I genuinely believed was a fever dream after I watched it on a plane whilst I was ill) which was released on Netflix just last week. Daniel Craig gets to swagger around solving a traditional locked-room mystery set during the pandemic. Top marks for Craig’s fashion stylings and saying “shitballs” in his inimitable Southern drawl.
#1: The Life Aquatic with Steve Zissou
Oh how I love me a Wes Anderson film. The colours, the framing, the colours, Jeff Goldblum, did I mention the colours? Beautifully shot with some fine performances from Bill Murray and the aforementioned Goldblum. I mean just watch this. Need I say more?
Books
I have had an exceptionally bad year when it comes to reading. I aim to read for 30 minutes per day and finish 20 books per year but I reached a paltry average of 6 minutes per day (~40 hours total) and only finished 9 books. They also weren’t that good 🤦🏻♂️
If I had to pick a favourite it would be The Haunting of Ashburn House by Darcy Coates as it was fairly standard “spooky house on the hill” but in a modern setting. I also really enjoyed The Thursday Murder Club by Richard Osman but everybody does hence it’s ongoing dominant position at the top of the book charts. However, neither of those came out this year so my only recommendation I can really give is Severance: The Lexington Letter, a free companion book to the Severance TV show that answers some questions and adds a few more.
I’ll do better this year. Promise. 🤞🏻
Roadmap
The roadmap is my way of committing to what I’m going to do over the next 2 weeks.
15th December - 4th January
Issue a TestFlight update for Music Library Tracker v2.0 ✅
Rebuild Game Track ✅
Tidy up Time Well Spent ✅
As I mentioned in the introduction, the Game Track work is done but I was already hitting the “post too long for email” message on Substack without going through that so I’ll save that for the next issue when I will have done a bit more to it. I was very happy to get the Time Well Spent app rebranded to Bookmark and even happier to have started on something small and new in the form of Back Seat Shuffle.
5th January - 18th January (Issue #4)
Keep working on Music Library Tracker v2.0 to resolve the issues mentioned above. I also want to improve the UI, especially on iPad.
I’d like to start looking into Swift Charts so will aim to add a stats page to Game Track. I’m also keen to look at a particular new API in iOS 16…
Whilst I don’t need Back Seat Shuffle until I go on holiday in March I’d like to get it finished off as otherwise it’ll gnaw away at me! I’ll stick the code up on GitHub.
That wraps it up for this issue. I hope you found something of interest and that you’ll be able to recommend the newsletter to your friends, family, and colleagues. You can always comment on this issue or by emailing me directly via ben@bendodson.com
Heroku has a free plan but it puts your server to sleep. This isn’t a huge issue but it meant that when I opened the app to log something I’d have to wait 10-20 seconds for it to be available; this was fairly tedious so I was paying $7 a month to avoid that. This was a bit extravagant when I was logging books, tv, and projects but it was utterly ridiculous when it was just books, especially in a year where I read very little.
If you’re really interested you can download a csv of my 2022 gaming time.
OK, Severance gets there on art direction. Whilst you’re down here you can also see everything I watched (tv and films) on my Trakt year in review.