performance: exclude lyrics if they are not enabled

This commit is contained in:
lb-a
2026-04-30 12:00:58 +02:00
parent 7a27845e75
commit 9618108f2a
3 changed files with 36 additions and 10 deletions

View File

@@ -121,6 +121,10 @@ func New(cfg *config.Config) (*Main, error) {
}, nil }, nil
} }
// downloaderMaxConnsPerHost picks the per-host idle connection cap for the
// shared download client. We floor at 16 so artwork/manifest fetches and
// concurrent track downloads to the same CDN host can reuse keep-alive
// sockets even when the user configured a tiny max_connections.
func downloaderMaxConnsPerHost(maxConnections int) int { func downloaderMaxConnsPerHost(maxConnections int) int {
if maxConnections > 16 { if maxConnections > 16 {
return maxConnections return maxConnections

View File

@@ -31,6 +31,9 @@ type Downloader struct {
barStarted atomic.Int32 barStarted atomic.Int32
} }
// downloadBufferSize sizes HTTP-to-disk copies. 1 MiB cuts read/write syscalls
// ~32x vs Go's default 32 KiB io.Copy buffer, which matters for multi-MB FLAC
// streams off CDNs that can sustain high per-connection throughput.
const downloadBufferSize = 1 << 20 const downloadBufferSize = 1 << 20
func New() *Downloader { func New() *Downloader {

View File

@@ -209,12 +209,17 @@ func (c *Client) GetMetadata(ctx context.Context, item, mediaType string) (map[s
if album, ok := resp["album"].(map[string]any); ok { if album, ok := resp["album"].(map[string]any); ok {
enrichTidalImage(album) enrichTidalImage(album)
} }
if lyrics, lrc := c.fetchTrackLyrics(ctx, item); lyrics != "" || lrc != "" { // Lyrics live on a separate endpoint, so fetching them costs an extra
if lyrics != "" { // rate-limited roundtrip per track. Users who don't embed lyrics can
resp["lyrics"] = lyrics // opt out via metadata.exclude = ["lyrics"].
} if !c.lyricsExcluded() {
if lrc != "" { if lyrics, lrc := c.fetchTrackLyrics(ctx, item); lyrics != "" || lrc != "" {
resp["lyrics_synced"] = lrc if lyrics != "" {
resp["lyrics"] = lyrics
}
if lrc != "" {
resp["lyrics_synced"] = lrc
}
} }
} }
} }
@@ -222,6 +227,15 @@ func (c *Client) GetMetadata(ctx context.Context, item, mediaType string) (map[s
return resp, nil return resp, nil
} }
func (c *Client) lyricsExcluded() bool {
for _, k := range c.cfg.Session.Metadata.Exclude {
if strings.EqualFold(strings.TrimSpace(k), "lyrics") {
return true
}
}
return false
}
func (c *Client) fetchTrackLyrics(ctx context.Context, trackID string) (string, string) { func (c *Client) fetchTrackLyrics(ctx context.Context, trackID string) (string, string) {
params := url.Values{} params := url.Values{}
params.Set("deviceType", "PHONE") params.Set("deviceType", "PHONE")
@@ -277,10 +291,11 @@ func (c *Client) GetDownloadable(ctx context.Context, trackID string, quality in
} }
if c.cfg.Session.Tidal.PreferAtmos { if c.cfg.Session.Tidal.PreferAtmos {
if c.trackSupportsAtmos(ctx, trackID) { // No tracks/{id} pre-check: getAtmosDownloadable already validates
if d, _ := c.getAtmosDownloadable(ctx, trackID); d != nil { // each candidate response via playbackLooksAtmos and falls back
return d, nil // through the format-specific trackManifests paths.
} if d, _ := c.getAtmosDownloadable(ctx, trackID); d != nil {
return d, nil
} }
} }
@@ -295,6 +310,10 @@ func (c *Client) GetDownloadable(ctx context.Context, trackID string, quality in
} }
if status == http.StatusOK { if status == http.StatusOK {
if d := downloadableFromPlaybackManifest(resp); d != nil { if d := downloadableFromPlaybackManifest(resp); d != nil {
// Tidal's playbackinfo sometimes returns an m4a (HIGH/AAC)
// stream even when LOSSLESS+ was requested. There is no
// lossless m4a tier, so retry via the openAPI v2 manifest
// before settling for the downgrade.
if quality >= 2 && d.Extension == "m4a" { if quality >= 2 && d.Extension == "m4a" {
if strict, strictErr := c.getDownloadableFromTrackManifest(ctx, trackID, quality); strictErr == nil && strict != nil { if strict, strictErr := c.getDownloadableFromTrackManifest(ctx, trackID, quality); strictErr == nil && strict != nil {
return strict, nil return strict, nil