README.md
⎇
Raw

Pico Pixel Player icon

Pico Pixel Player is a lightweight, self-hostable audio player with an ElysiaJS backend and SolidJS frontend. It lets you play audio files directly from your server with a clean, responsive UI.

Features

  • Lightweight: Minimal dependencies, fast performance
  • Easy Setup: Configure with just a .env file
  • Responsive UI: Works seamlessly on desktop and mobile
  • Offline Capable: Progressive Web App (PWA) support and local caching of files
  • Transcoding: Optionally transcode files at a selected bitrate and format to your client
  • Directory Listing: Browse files in their original directory structure

Screenshot

screenshot

Setup

  1. Clone the repository:
git clone <repository-url>
cd pico-pixel-player
  1. Write/adjust these settings in a file called .env:
HOST_PORT=1234
MUSIC_ROOT=/path/to/your/music
  1. Start the service:
docker-compose up  # or podman-compose up

Configuration

You can configure the backend with the following environment variables:

  • COVER_REGEX: JS-compatible regex to match filenames in a directory to find a matching cover art. Searches the directory structure upwards. Set to an empty string to disable cover detection.
  • EXCLUDE_EXTENSION: comma-separated list of of file extensions to ignore completely, e.g. txt,log,nfo. If unset, uses a safe set of text files common in downloaded music archives. Useful because some files can get mis-scanned, e.g. some CD-scan .log files get scanned as mp1

Important Notes

  • No Authentication: The app has no built-in auth. Run it behind a proxy with basic auth for security. Simple login form might get added in the future.

Non-Goals

  • Metadata-Based Views: No support for filtering by genre, artist, etc. Use other projects for this
  • Multiple users: Right now everything besides the actual file hosting is stored on the server. When syncing is implemented, it will only be single storage. Permissison systems are also not planned. If distinct permissions/syncs are absouletely required, hosting multiple instances is an option

FAQ

  • What is the "Disable chunked transcoding" option for?
    • By default the backend sends the transcoded media as it progresses, which uses "chunked transfer", i.e. without the usual content-length of normal HTTP requests. Some browser (safari cough cough) seem to be very selective about the sources of <audio> elements, and choke on sources that are transferred via this method. This option forces the server to transcode the whole file before sending it, improving compatibility with these browser, at the cost of increased latency.
  • The playback stops automatically at some point on my mobile device when I put the browser in the background or turning my screen off
    • In my testing at least mobile firefox behaves this way, with no apparent solution. It seems to stop after changing the sources of the audio element at some point. Either use a browser that doesn't behave like this (Chrome on Android seems to work), or wrap the PWA in a native app (e.g. https://www.pwabuilder.com/)
  • I'm getting "Quota exceeded" errors when trying to sync files or
  • My synced files randomly don't work, are missing
    • By default websites aren't granted infinite storage or have persisten data. The frontend requests these permissions by calling navigator.storage.persist() on startup, which causes some browsers to show a permissions popup (e.g. firefox), while others just seem to ignore this request and use a heuristic like interaction amount and bookmarking instead. So if you have the error described above you either are running out of actual disk storage, or you need to check what heuristics your browser uses and trigger them.
  • My server is online, but I'm getting loading failed errors for everything
    • If you have set up basic auth, then the PWA can interact in a weird way with it, where the pwa itself loads fine because it loaded from cache, but any request fails because the basic auth is gone. Usually can be fixed by loading the page, waiting a few seconds and then reloading, which should give you the auth prompt.

Known issues

  • Range requests are not correctly handled in Bun right now, and e.g. doesn't send the total byte length correctly. I worked around this by sending a chunked transfer-encoded response, and setting the range and content-length header manually, which seems to work with the browsers I tested, but still might cause issues in some cases
  • Some of the transcoded formats behave weirdly in some browsers, e.g. safari seems to dislike ogg containers, and chrome has seeking issues with some webm transcoded files. If you have any code suggestions to improve the handling, feel free to open a PR at https://gitlab.com/Konata390/pico-pixel-player
  • Some files (especially mp3) fail to either be listed or to be played. I encountered some mp3 files that could be played fine, but had some weird metadata issues that caused the file-type/music-metadata libraries to not be able to scan them, which blocks them from being played in the browsers. The solution is to run ffmpeg -i INPUTFILE -c copy OUTPUTFILE on them, afterwards they are scanned just fine

Attributions