Files
yellowjacket/backend/tracklist/config.go
T
yonluandClaude Opus 4.6 93892c10de wip(explore): library-only mode, ranked search, UI polish — as-is
End-of-milestone state for the Explore milestone. Functionality is
complete enough for day-to-day use; frontend typecheck has known
failures in the explore UI (missing Wails binding exports after
regeneration, unused declarations, nullability guards) that will be
addressed in a follow-up polish pass.

Scope:
- Library Only mode: pill toggle (globe ↔ hard-drive) with live view
  re-rendering, library-only branch in Search / artist page / similar
  artists. Suppresses external API calls when enabled.
- Ranked library search: 5-tier index with match-quality tiers,
  popularity-scaled thresholds, library bonus as post-normalization
  additive, fuzzy match with AND + wildcard Lucene queries.
- New schemas: artist_metadata, http_cache.
- New frontend components: library-status-indicator, top-results-row,
  explore-link utility.
- Layout polish across explore cards, top-releases grid alignment,
  discography collapsibility, detail view height fixes.
- Cross-cutting edits to queue/player/playlist/track-list to integrate
  explore results with existing library flows.

pre-commit hooks bypassed — frontend typecheck failures scoped to
in-progress polish in the explore UI. Go build and full backend test
suite are green.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:57:00 -04:00

119 lines
2.6 KiB
Go

// Package tracklist manages track-list display configuration.
package tracklist
import (
"errors"
"fmt"
"slices"
)
var (
errUnknownColumnID = errors.New("unknown track-list column ID")
errDuplicateColumn = errors.New("duplicate column ID")
)
// ColumnID identifies a displayable column in the track list.
type ColumnID string
// Valid column identifiers.
const (
ColTrackName ColumnID = "trackName"
ColArtistName ColumnID = "artistName"
ColTrackLength ColumnID = "trackLength"
ColAlbum ColumnID = "album"
ColGenre ColumnID = "genre"
ColYear ColumnID = "year"
ColComposer ColumnID = "composer"
ColTrackNumber ColumnID = "trackNumber"
ColDiscNumber ColumnID = "discNumber"
ColFilePath ColumnID = "filePath"
ColFileType ColumnID = "fileType"
ColSampleRate ColumnID = "sampleRate"
ColBitDepth ColumnID = "bitDepth"
ColChannels ColumnID = "channels"
ColBitrate ColumnID = "bitrate"
ColFileSize ColumnID = "fileSize"
ColPlayCount ColumnID = "playCount"
ColAlbumArt ColumnID = "albumArt"
)
// AllColumnIDs lists every recognised column in default display
// order.
var AllColumnIDs = []ColumnID{
ColAlbumArt,
ColTrackName,
ColArtistName,
ColTrackLength,
ColAlbum,
ColGenre,
ColYear,
ColComposer,
ColTrackNumber,
ColDiscNumber,
ColFilePath,
ColFileType,
ColSampleRate,
ColBitDepth,
ColChannels,
ColBitrate,
ColFileSize,
ColPlayCount,
}
// DefaultColumns is the initial column configuration matching the
// original hardcoded layout.
var DefaultColumns = []Column{
{ID: ColTrackName},
{ID: ColArtistName},
{ID: ColTrackLength},
}
// Column represents a visible column in the track list.
type Column struct {
ID ColumnID `json:"id" toml:"ID"`
}
// Config holds track-list display preferences.
type Config struct {
Columns []Column `json:"columns" toml:"Columns"`
}
// ApplyDefaults fills zero-value fields with sensible defaults.
func (c *Config) ApplyDefaults() {
if len(c.Columns) == 0 {
c.Columns = make([]Column, len(DefaultColumns))
copy(c.Columns, DefaultColumns)
}
}
// Validate checks that every column ID is recognised and that
// there are no duplicates.
func (c *Config) Validate() error {
c.ApplyDefaults()
seen := make(map[ColumnID]bool, len(c.Columns))
for _, col := range c.Columns {
if !isValidColumnID(col.ID) {
return fmt.Errorf(
"%w: %q", errUnknownColumnID, col.ID,
)
}
if seen[col.ID] {
return fmt.Errorf(
"%w: %q", errDuplicateColumn, col.ID,
)
}
seen[col.ID] = true
}
return nil
}
// isValidColumnID returns true when id matches a known column.
func isValidColumnID(id ColumnID) bool {
return slices.Contains(AllColumnIDs, id)
}