In the last few months, I've moved away from using Spotify and back to using my own music collection, largely driven by tracks which I include in my playlists disappearing off the service due to licensing issues. Moving fully back to local media has left to issues keeping my library in sync across devices, so I've begun using Jellyfin, an open source media server to store my collection and make it available to all my devices. However, the default web interface in Jellyfin did not provide the same efficiency I liked from Clementine, my music player I used locally.

Much like foobar2000, Clementine has a very efficient interface for the way in which I tend to listen to music - i.e. rapidly creating a playlist of disparate tracks via search, listening to it for a few days or weeks, then making a new collection. The same is not true for Jellyfin's web interface (and wasn't true for Spotify either). So I built my own client to replicate that experience.

Preserve

Preserve is a web based media player frontend to a jellyfin server. It aims to replicate the experience of using players like foobar2000 or Clementine with its two panel design allowing you to quickly search tracks and assemble/order a playlist how you like, including full keyboard controls. It's fully open source, under GPLv2+.

Since it is a jellyfin client, you will first need to host your music using a Jellyfin server, but once that is done you can use Preserve in your browser at preserveplayer.com or install a desktop client from the Preserve Gitlab releases.

Preserve v0.4.0 Screenshot

Tech

Preserve is built using Vue.js 3 and Typescript. It was migrated from Vue 2 to Vue 3 during development as the then-beta Vue 3.0 led to a significant performance improvement. It uses web APIs for actual media playback, including on desktop where the client is an Electron client.

For testing, Cypress is used. To allow testing the application in the absence of a jellyfin server, axios is used for HTTP requests. This allows the use of axios-mock-adapter for mocking out HTTP responses allowing the application to run against a test data source for functional testing.

In addition, the jellyfin project provides an autogenerated axios client from the swagger definitions with full typescript support, which made things much nicer to work with.