muse: request a single song, get it tagged in your library

Lidarr's smallest unit is a MusicBrainz release, so asking for one track
means monitoring a whole discography. Soulseek trades individual files but
has no concept of a request. muse bridges the two: search, click, and the
song lands in the library correctly tagged.

The design point is that the user picks the exact track before anything
downloads, so muse holds artist, album, year and track number as ground
truth and tags deterministically rather than inferring them afterwards from
whatever a stranger named the file.

Search is Deezer rather than MusicBrainz, decided on measurement:
MusicBrainz put eight covers above the real recording for "radiohead creep"
and never surfaced Queen for "bohemian rhapsody" across 90 results, because
its index matches a word in a cover's title as readily as in the artist
field. Re-ranking cannot rescue a result set missing the right row.

Imports are os.link(), so downloads keep seeding from the Soulseek share
while the library gets a second name for the same bytes.
This commit is contained in:
aryansingh committed 2026-08-04 03:05:45 -05:00
commit 269f13524d
7 files changed
+874

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
name: release
# Publishes ghcr.io/<owner>/muse. The package inherits this repo's visibility
# on first publish, so it lands PRIVATE — pulling it needs a token with
# read:packages (see README, "Pulling on a server").
on:
push:
branches: [main]
tags: ["v*"]
# Docs-only edits shouldn't burn a build or move :latest.
paths-ignore:
- "**.md"
- ".gitignore"
workflow_dispatch:
concurrency:
# A newer push makes an in-flight build pointless.
group: release-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # required to push to GHCR
steps:
- uses: actions/checkout@v4
- name: Sanity-check the app before publishing
run: |
python3 -m pip install --quiet -r requirements.txt
python3 -c "import app; print('app imports OK')"
- uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
# Automatically provided; no PAT needed for pushing from CI.
password: ${{ secrets.GITHUB_TOKEN }}
- name: Tags and labels
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=short
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
# amd64 only: the only host that runs this is x86_64. Adding arm64
# means QEMU emulation and a 3-5x slower build for nothing.
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Summary
run: |
echo "### Published" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY