The Problem

Building a local music library from streaming service links is fragmented: each service has its own URL scheme, metadata quality, and download method. Users end up with untagged files, messy folder structures, and no way to get a coherent, media-server-ready collection. Antra solves this by turning links from Spotify, YouTube Music, Apple Music, Amazon Music, Tidal, Qobuz, and Deezer into a fully tagged local library in FLAC, ALAC, AAC, or MP3.

What This Does

Antra is a desktop application with a Python backend (antra/) and a Wails-based GUI (antra-wails/). It fetches track metadata, downloads audio, tags files with title, artist, album, artwork, genre, and lyrics, then files them into an Artist / Album structure ready for Navidrome, Jellyfin, or Plex.

The core logic lives in antra/core/service.py orchestrates sources, engine.py handles downloads and errors, and resolver.py tracks source success. Each streaming service has a fetcher in antra/sources/ (e.g., amazon.py, apple.py, tidal.py). The GUI layer in antra-wails/ wraps the Python backend via Go bindings.

How It Is Wired

Execution starts at main in antra/__main__.py:502, which reaches 400 functions. From there, run (line 685) dispatches to either process_library_mode or process_resources. The shortest path to an external effect is main -> cleanup_project_junk (filesystem via shutil.rmtree), and process_resources -> fetch_playlist_tracks -> _fetch_spotfetch_tracks (network via SpotFetchFetcher).

The most-connected module is antra/core/models.py — 36 modules import it, making it the highest-blast-radius file. antra/core/service.py is the hub for orchestration (58 functions, 31 imports), while antra/sources/amazon.py is the most complex source (42 functions, calls out to network, filesystem, and subprocesses). The call graph shows search is called from 58 places, TrackMetadata from 30, and resolve from 16 — changing these ripples widely.

The module graph has no circular dependencies, which keeps refactoring tractable. antra/core/models.py is a stable hub (instability 0), while antra/core/service.py (0.94) and antra/core/engine.py (0.93) are highly unstable — they depend on everything else, so changes to them are low-risk but changes to their dependencies are not.

How To Use It

  • Setup: Clone with git clone https://github.com/moses-y/Antra. The repo has requirements-desktop.txt and requirements-runtime.txt for Python, and antra-wails/go.mod for the Go backend.
  • Configuration: .env.example shows required env vars. The GUI is configured via antra-wails/wails.json.
  • Running it: The Python CLI entry point is python -m antra. The desktop app builds via build_desktop.py (Wails). No Dockerfile or Makefile exists, so build commands are not documented in-repo.

Real-World Use

A user pastes a Spotify playlist link into the GUI. The backend resolves the URL via antra/core/spotify.py, fetches track metadata, downloads audio, tags it with antra/utils/tagger.py, and files it into Artist/Album/ via antra/utils/organizer.py. The result is a media-server-ready library without manual tagging.

Code Health & Issues

Static analysis found 100 issues (29 high, 71 medium) across 6 kinds. Key findings:

  • High - No test suite: 90 source files, zero test files. Any change ships with no regression signal.
  • High - Unpinned GitHub Actions: .github/workflows uses softprops/action-gh-release@v2 — a tag can be moved, risking token exposure.
  • Med - Broad exception handling: 24 instances of bare except in antra/utils/runtime.py, antra/core/config.py, and antra/core/amazon_music_fetcher.py.
  • Med - Deep nesting: 24 files with max indentation depth 10, notably antra/core/apple_fetcher.py and antra/core/spotify.py.
  • Med - No dependency scan or Dependabot in CI.
  • Med - Duplicated code: 190 repeated 6-line blocks across 30 files.
  • Low - No job timeouts in CI, missing .editorconfig and .gitattributes.

The Bottom Line

Antra is a functional, well-structured music library builder with a solid module layout and no circular dependencies. The lack of tests and unpinned CI actions are the main risks for anyone maintaining it. It is useful for users who want a self-hosted, tagged library from streaming links; engineers should add tests and pin CI before relying on it.