Unfortunately I did not have much time to update my blog. But I’m not dead and neither audioserve is – actually last half of year or so I focused on building new client. As of now new client is ready for production (version 0.3.3 +) and server has some new functionality too, mainly to support new client.
There is now online demo automatically built from master branch (shared secret is mypass).
Main idea behind new client was to implement same caching possibilities as older Android client had. I felt this is really key feature to assure smoothness of listening experience and resilience to short term network unavailability and possibility to listen when offline.
Key technology for that is Service Worker and Cache Storage – this enables to cache ahead audio files and also store content of whole folder for off-line playback (provided that relevant api responses for that folder are in cache too – these are cached also via Service Worker into custom network-first cache).
It took me some time to play around with Service Worker, I wanted to build functionality from scratch to learn more about it and I also bit suspected that prepared solutions (like Workbox) would not work for may use case – I did have quite particular requirements for audio files caching. Some interesting problems I met:
- You cannot rely on Service Worker life time, especially Firefox is quite aggressive on killing Service Worker, if client pages are not active.
This caused problems, if there is a queue of longer files to be preloaded. I solved this with periodic polling of service worker while it is preloading files. - Regular Cache and Cache Storage filled via Service Worker can interfere in quite complex ways. Better to set Cache-Control to no-store for resources that are managed by custom cache.
- Do not cache error responses – custom cache can cache everything, so do not cache errors like 401 (lesson learned :-). However 404s can be different story – see later discussion.
Another notable functionality in web client are folder icons. I’m not much of fan of too visual applications (text information is enough for my navigation), neither I do have consistent cover images in my collection, but it’s kind of standard for such an application so I added it in. It brought couple of interesting aspect:
- I had to build scaling and caching service in audioserve server, so that icons are served efficiently. Initially icon is created from cover image stored in folder – it’s scaled to given size (configurable with 128px default) and then stored in cache (on file system, not memory, linux does good job on caching frequently used files, if there is enough memory). Next time same icon is served from cache.
- This opened another yet unsolved problem – how to get cover image for single file audiobooks – .m4b files. So I extended media-info sub crate to extract cover from .m4b (where it is represented as another stream of video type and MJPEG codec).
- On client side I implemented efficient loading of folder icons within subfolders list – using `
IntersectionObserver
as recommended by PWA guidelines. Interestingly provided third party solution for Svelte did not fit well. First reason is mentioned in the link, second reason came from need to be able to quickly cancel download of icon, that left view. - It also brought interesting issue of 404 responses caching – in my collection I do have quite a lot of folders without cover image – so 404 responses are returned for their icons. But since collection content is rather static, it would make sense, in this case, to cache them. I looked over internet articles and general opinion is that it make sense to cache them, if there is good reason for it. However practice is bit different – I had enabled cache via Cache-Control header on 404 response, but only Chrome supports it, Firefox is not caching 404s, even when it has proper header.
(Indeed the proper solution would be to provide information from the server – if subfolder has icon or not)
I also had couple of issues with Chrome browser where I discovered some bugs – while first one with MediaSession
implementation is still pending, second one – regression in range input was to my surprise resolved very quickly.
So this is where audioserve is now, near future plans are (mostly now driven by users feedback by github issues):
- Add finished and last modified information to files (server) and appropriate support in web client
- Solve icons 404s – just for fun, I’d like to play with 404 cache in client, but proper solution will also require change in collections cache on server.
For long term ideas, I was thinking about:
- Improve Rust binding to libavformat and libavcodec so I can implement transcoding in Rust and have more control over it.
- Use Web Audio API – something that will implement custom player and will interact better with server, especially for transcoded streams.
- The two activities above may lead to DASH support of something like this – adaptable bandwidth and more reliable playback. Will see.
So that all for now – if you are using audioserve and have some ideas or problems please share them via GitHub issues.