Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Lyrion Music Server (LMS) provider

Open
#348 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
1/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Stale
Tech stack
go
Domain
backend

Research direction

PR #349 is already open and the provider is implemented, so this is not available as a first contribution. For orientation, read the existing remote providers and the LMS implementation under external/lyrion/; run its tests, including the env-guarded live suite with CLIAMP_LYRION_LIVE_URL set. Done is covered by the open PR’s implementation and tests.

Written by the indexing model from the issue text.

Description

Problem

cliamp supports seven self-hosted / remote music backends (Navidrome, Plex, Jellyfin, Emby, Audiobookshelf, Qobuz, Tidal) but not Lyrion Music Server (LMS, formerly Logitech Media Server) — the long-running server behind the Squeezebox ecosystem, still actively maintained and very widely deployed on home NAS boxes.

Today an LMS user has no way to reach their library from cliamp, and there's no bridge that closes the gap:

  • The LMS Subsonic plugin goes the wrong direction — it lets LMS consume an external Subsonic library, it doesn't expose the LMS library over the Subsonic API. So the existing Navidrome provider can't be pointed at it.
  • The LMS UPnP bridge can't adopt cliamp, since cliamp isn't a UPnP renderer (that was raised in #117, which was closed by pointing at the Plex provider).

Proposal

Add a lyrion provider that treats LMS as a library backend, exactly like the other remote providers: browse over its JSON-RPC API, play through cliamp's own engine.

This fits the existing provider seam very cleanly:

cliamp interface LMS query
playlist.Provider playlists, playlists tracks
provider.Searcher titles with search:
provider.ArtistBrowser artists, albums artist_id:
provider.AlbumBrowser albums with sort: + offset/count
provider.AlbumTrackLoader titles album_id: sort:albumtrack

Playback needs no new machinery — LMS serves the original file at /music/<track_id>/download, so tracks are ordinary Stream: true HTTP tracks that route through the existing buffered pipeline alongside Subsonic/Jellyfin/Plex. No new dependencies: it's plain JSON over HTTP.

Deliberately not proposed: SlimProto / Squeezebox player emulation. That would invert cliamp's architecture (the server would drive playback and own the queue) and is a much bigger project — anyone who wants sync groups and multi-room is better served running squeezelite.

Known limitations worth stating up front:

  • LMS records play counts against a player playing a track. Since cliamp plays the file directly rather than through an LMS player, cliamp listening leaves no history on the server. There's no honest PlaybackReporter mapping, so it doesn't implement one.
  • A library can also contain tracks contributed by server plugins (Spotty, etc.). LMS accepts a download request for those and then never sends any bytes, so playback stalls on them. These are now hidden by default, with show_unplayable = true to surface them flagged-but-visible — see the update below for why the default flipped.

Mockups / references

I have this implemented and tested against a live LMS 9.2.0 instance (16,663 tracks) and am happy to open a PR — filing this first to check you'd want it in tree before sending the diff.


Update — findings from testing against a live server

PR #349 is open and now verified end to end against LMS 9.2.0 with a real library (16,663 tracks, 4,225 artists, 1,293 albums, 114 saved playlists). Three things came out of that which weren't obvious from the docs, and which changed the design:

1. Plugin-contributed content needed hiding, not just flagging. My first pass returned plugin tracks marked Unplayable but still visible, reasoning that hiding library content misrepresents the library. That assumed plugin content was a minority garnish. On the test server it wasn't: all 114 saved playlists were Spotty imports, every track inside them a spotify:track:… entry. The provider pane was 114 entries that all did nothing. Plugin tracks and plugin-imported playlists are now omitted by default, with show_unplayable = true restoring the old behaviour.

Filtering playlists costs nothing extra — the playlists query returns each playlist's origin URL in the same response, so one added tags:u separates spotify:playlist:… from file://…. One rough edge remains and is documented rather than fixed: an album made entirely of plugin tracks still appears and opens empty (41 of 1,293 on the test server). Unlike playlists, the albums query carries no origin field, so classifying albums would cost ~1,300 extra round trips.

2. Credentials must not go on the track. Worth flagging for anyone writing a similar provider: Track.Path is persisted verbatim to resume state and to the play history. LMS authenticates with the user's actual account password rather than a revocable token (unlike Plex/Navidrome), so putting credentials in the stream URL writes that password to disk in plaintext. Tracks now carry a bare lyrion://track/<id> and a registered SourceResolver applies credentials at play time, the same shape the Tidal provider uses.

3. Two LMS API details that are easy to get backwards. The albums query uses uppercase S for artist_id, while titles uses lowercase s for the same field (lowercase s in albums is a sort textkey). Since LMS silently omits any field whose tag letter you didn't request, getting this wrong returns albums with a blank artist and no error anywhere. Separately, LMS returns tracknum and year as quoted strings while duration and id come back as numbers, in the same response object — decoding has to accept both. Both are pinned by tests now.

The PR includes an env-guarded live test suite (following the netease precedent) so this is reproducible against your own server:

CLIAMP_LYRION_LIVE_URL=http://lms.local:9000 go test ./external/lyrion/ -run Live -v
Dominant language
Go
Stars
4.4k
Forks
307
Avg merge
3d 8h
Merged PRs (30d)
34

Getting set up

  • No Dockerfile or Docker Compose file
  • Has a pull request template
  • No contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from bjarneo/cliamp

All issues in bjarneo/cliamp

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.