Files
yellowjacket/.planning/codebase/INTEGRATIONS.md
T
2026-02-26 16:58:25 -05:00

12 KiB
Raw Blame History

External Integrations

Analysis Date: 2026-02-26

Wails Runtime Bridge (Go ↔ TypeScript)

Primary Communication Mechanism: Events

The Wails runtime provides a bidirectional event bus between Go and TypeScript. Event names are defined as string constants that must match exactly between both sides:

  • Go: backend/events/events.go - Centralized event name constants
  • TypeScript: frontend/src/events.ts - Mirrored constants

Event Categories:

Category Direction Events
Playback Backend → Frontend PlaybackStateChanged, PlaybackFinished, TrackChanged, SeekFailed, VolumeChanged
Queue Backend → Frontend QueueChanged, QueueIndexChanged, QueueModeChanged, QueueTracksModified
Config Backend → Frontend LibraryConfigChanged, ThemeConfigChanged, TrackListConfigChanged, FavoritesConfigChanged
Playlist Backend → Frontend PlaylistCreated, PlaylistDeleted, PlaylistRenamed, PlaylistTracksChanged, PlaylistsRestored, DefaultPlaylistChanged
Library Backend → Frontend LibraryScanStarted, LibraryScanComplete

Go event emission pattern:

runtime.EventsEmit(p.ctx, events.TrackChanged, trackInfo)
runtime.EventsOn(l.ctx, events.LibraryConfigChanged, func(data ...any) { ... })

TypeScript event subscription pattern:

EventsOn(Events.TrackChanged, (trackInfo: TrackInfo | null) => { ... });

Wails Bindings (Direct Function Calls):

Go structs listed in FEBindings in backend/app.go are automatically exposed as callable functions from TypeScript. Auto-generated binding stubs live in frontend/wailsjs/go/ (do not edit).

Bound services:

  • backend/frontendutil/frontendutil.go@go/frontendutil/FrontendUtil - Directory/file picker dialogs
  • backend/config/config.go@go/config/Config - Get/set all configuration
  • backend/library/library.go@go/library/Library - Library scanning and queries
  • backend/playlist/playlist.go@go/playlist/Service - Playlist CRUD
  • backend/queue/queue.go@go/queue/Queue - Queue management
  • backend/player/player.go@go/player/Player - Playback control (play, pause, seek, volume, load)

State Synchronization Pattern:

The backend is the source of truth. The frontend requests initial state after its stores are ready:

// frontend/index.ts (after all stores import and register listeners)
void Player.EmitCurrentState();
void Queue.EmitCurrentState();

Backend responds by emitting the full current state via events, which the stores receive and cache.

Data Storage

Database: SQLite

  • Driver: modernc.org/sqlite v1.45.0 (pure-Go, no CGo)
  • DB file: ~/.local/share/yellowjacket/yj.db (Linux)
  • Connection: backend/database/database.go
  • Pragmas: WAL journal mode, busy_timeout=5000, foreign_keys=ON
  • Constraint: SetMaxOpenConns(1) (single writer)
  • Code generation: sqlc (backend/database/sqlc.yaml)
    • Schemas: backend/database/sql/schemas/*.sql (30 schema files)
    • Queries: backend/database/sql/queries/*.sql (15 query files)
    • Generated output: backend/database/sql/sqlcgen/ (DO NOT EDIT)
  • Schema migration: Custom migration system using PRAGMA user_version (backend/database/database.go, runMigrations())
    • Migration 1: Audio file property columns (sample_rate, bit_depth, channels, bitrate, file_size)
    • Migration 2: Basename column, FTS5 search index

Database Schema (key tables):

Table Purpose
audio_files Tracks with file paths, metadata references, audio properties
recordings Track metadata (title, track number, year, genre, etc.)
artists Artist entities
artist_credit Artist credit display names
artist_credit_artist M:N link between artists and credits
release_groups Albums
release_group_recordings M:N link between albums and recordings
cover_art Cover art file references
genres Genre entities
genre_recordings M:N link between genres and recordings
playlists / playlist_tracks User playlists
queue / queue_tracks Playback queue with persistence
player_state Persisted player state (volume, last track, position)
file_types Supported audio file type registry
search_index FTS5 full-text search index (file_path, title, artist, album)

File Storage:

  • Cover art cache: ~/.local/share/yellowjacket/covers/ (Linux)
    • Managed by backend/coverart/coverart.go and backend/library/coverart.go
    • Size variants: original, _sm (small), _md (medium), _lg (large)
    • Served via custom asset handler at /covers/ prefix
  • Config file: ~/.config/yellowjacket/config.toml (Linux)
    • Managed by backend/config/config.go
    • Format: TOML via github.com/BurntSushi/toml

Caching:

  • In-memory entity cache during library scans (entityCache in backend/library/library.go) - caches artist credits, artists, release groups, cover art, genres to avoid redundant DB upserts
  • No external caching service

Audio Playback

Library: github.com/gopxl/beep/v2 v2.1.1

Core audio engine providing decode → resample → control → volume → speaker pipeline.

  • Decoder: backend/metadata/decoder.go - Routes by file extension to beep decoders
  • Player: backend/player/player.go - Manages streamer chain and playback state
  • Speaker: Initialized at 44100 Hz sample rate, 100ms buffer (time.Second/10)

Supported Formats:

Format Decoder Extension
MP3 github.com/gopxl/beep/v2/mp3 (via github.com/hajimehoshi/go-mp3) .mp3
FLAC github.com/gopxl/beep/v2/flac (via github.com/mewkiz/flac) .flac
Ogg Vorbis github.com/gopxl/beep/v2/vorbis (via github.com/jfreymuth/oggvorbis) .ogg
WAV github.com/gopxl/beep/v2/wav .wav

Audio Pipeline (per track):

  1. File opened → decoded to beep.StreamSeekCloser
  2. Resampled from source sample rate to speaker rate (44100 Hz, quality=4)
  3. Wrapped in beep.Ctrl for play/pause control
  4. Wrapped in effects.Volume for volume control (base=2, range -5 to 0 internal)
  5. Registered with speaker.Play() with a beep.Callback for end-of-track notification

Speaker hardware uses github.com/ebitengine/oto/v3 (indirect dependency via beep) for cross-platform audio output.

Volume System:

  • User-facing: 0100 integer scale (player.UserVolume)
  • Internal: -5.0 to 0.0 float scale (player.Volume)
  • Conversion: backend/player/volume.go

Metadata Extraction

Library: github.com/dhowden/tag

  • Extracts ID3v2, Vorbis Comment, and FLAC tags
  • Implementation: backend/metadata/tags.go (ExtractTags, ExtractTagsFromReader)
  • Extracted fields: title, artist, album, album artist, composer, genre, year, track/disc numbers, lyrics, comment, embedded cover art

Custom Duration Parsers:

  • MP3: backend/metadata/mp3duration.go - Custom header parser for accurate duration (handles multiple ID3v2 tags that inflate go-mp3's Len())
  • FLAC: backend/metadata/flacduration.go - Custom FLAC STREAMINFO header parser
  • General: backend/metadata/duration.go - Fallback using beep decoder for WAV/OGG

Combined Extraction:

  • backend/metadata/metadata.goExtractAllMetadata() - Single-pass extraction of tags, duration, and audio properties (sample rate, bit depth, channels, bitrate, file size)

System Integrations

MPRIS2 Media Controls (Linux)

  • Implementation: backend/mediacontrols/mpris_linux.go (//go:build linux)
  • D-Bus library: github.com/godbus/dbus/v5
  • Bus name: org.mpris.MediaPlayer2.yellowjacket
  • Object path: /org/mpris/MediaPlayer2
  • Interfaces: org.mpris.MediaPlayer2 (root), org.mpris.MediaPlayer2.Player
  • Capabilities: Play, Pause, PlayPause, Stop, Next, Previous, Seek, SetPosition, Volume, Metadata push
  • Non-Linux: No-op stub (backend/mediacontrols/stub.go, //go:build !linux)

Architecture: All D-Bus property updates are dispatched via a buffered channel (updateChanSize = 64) to a dedicated goroutine, preventing deadlocks between the player mutex and godbus property mutex.

File System

  • Library scanning: backend/library/library.go - Recursive fs.WalkDir with concurrent worker pool (errgroup)
  • Disk type detection: backend/system/disktype_linux.go / backend/system/disktype_other.go - Detects HDD vs SSD for adaptive scan concurrency
  • User data directories: backend/system/userdata.go - OS-specific paths for config and data
  • Native dialogs: backend/frontendutil/frontendutil.go - Directory picker, file picker (for M3U import)

Playlist Import/Export

  • M3U/M3U8 parsing: backend/playlist/m3u.go
  • Playlist matching: backend/playlist/match.go - Fuzzy matching of playlist entries to library tracks
  • Favorites system: backend/playlist/favorites.go - Special playlist designated as favorites

Cover Art System

  • Extraction: Embedded art from audio file tags (backend/library/coverart.go)
  • Storage: Hash-based filenames in ~/.local/share/yellowjacket/covers/
  • Size variants: Small (100px), Medium (200px), Large (400px) - generated via golang.org/x/image
  • Serving: Custom HTTP handler at /covers/ prefix (backend/coverart/handler.go)
  • URL resolution: backend/coverart/coverart.goResolveURLs() converts filesystem paths to URL paths

Custom Asset Server

  • Implementation: backend/assets/handler.go
  • Serves embedded frontend dist files via Wails asset server
  • Supports custom route registration (used by cover art handler)
  • Middleware pattern captures Wails' default handler for fallback

Frontend Architecture

Entry Points

  • Main app: frontend/index.htmlfrontend/index.ts
  • View routing: DOM-based navigation via navigate CustomEvent in frontend/index.ts
  • Views: tracks, albums, playlists, artists, genres, libraries, settings, artist-details, genre-details

State Management

Singleton stores in frontend/src/store/:

  • player-store.ts - Playback state, current track, volume
  • queue-store.ts - Queue tracks, current index, play mode
  • library-store.ts - Library track listing
  • playlist-store.ts - Playlist data
  • favorites-store.ts - Favorites state
  • theme-store.ts - Theme accent color and background shade
  • search-store.ts - Search query and results
  • tracklist-store.ts - Track list column configuration

Each store subscribes to Wails events and delegates actions to backend via Wails bindings.

ReactiveController Pattern

Controllers in frontend/src/store/controllers/ connect Lit components to stores:

  • player-controller.ts, queue-controller.ts, library-controller.ts, playlist-controller.ts, favorites-controller.ts, theme-controller.ts, search-controller.ts, tracklist-controller.ts
  • Subscribe in hostConnected(), unsubscribe in hostDisconnected()

Profiling & Observability

Development Only (eliminated in production builds):

  • pprof HTTP server: localhost:6060 (backend/profiling/profiling.go, //go:build dev)
  • Endpoints: /debug/pprof/, /debug/trace
  • Block and mutex profiling enabled
  • Custom TimeOp() function for operation timing

Logging:

  • Framework: log/slog (structured, key-value pairs)
  • Dev handler: github.com/golang-cz/devslog (pretty-printed to stdout)
  • Wails logger bridge: backend/logging/logging.go (routes Wails logs through slog)
  • Pattern: Logger injected via constructors, scoped with logger.WithGroup("component")

External APIs & Services

None. YellowJacket is a fully local, offline application. There are no external API calls, cloud services, analytics, telemetry, or network requests. All data lives on the local filesystem.

CI/CD & Deployment

CI Pipeline: Not detected in the repository (no .github/workflows/, .gitlab-ci.yml, etc.)

Git Hooks (lefthook):

  • lefthook.yml - Pre-commit: go vet, golangci-lint, codegen check, frontend typecheck
  • Pre-push: protect main branch, go test, go mod verify

Distribution: Binary builds via make build-prod (obfuscated + UPX compressed)

Webhooks & Callbacks

Incoming: None Outgoing: None


Integration audit: 2026-02-26