feat: rework !similar to build and play discovery playlists

Default !similar now discovers similar artists/tracks, resolves each
against YouTube in parallel via ThreadPoolExecutor, fades out current
playback, and starts the new playlist. Old display behavior moves to
!similar list subcommand.

New helpers: _search_queries() normalizes Last.fm/MB results into search
strings, _resolve_playlist() resolves queries to _Track objects in
parallel. Falls back to display mode when music plugin not loaded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
user
2026-02-23 23:56:51 +01:00
parent b658053711
commit dd4c6b95b7
5 changed files with 357 additions and 173 deletions

View File

@@ -1791,19 +1791,22 @@ key is configured; falls back to MusicBrainz automatically (no key
required).
```
!similar Similar to currently playing track
!similar <artist> Similar artists to named artist
!similar play Queue a random similar track
!similar play <artist> Queue a similar track for named artist
!similar Discover + play similar to current track
!similar <artist> Discover + play similar to named artist
!similar list Show similar (display only)
!similar list <artist> Show similar for named artist
!tags Genre tags for currently playing artist
!tags <artist> Genre tags for named artist
```
- Default `!similar` builds a discovery playlist: finds similar artists/tracks,
resolves each against YouTube in parallel, fades out current playback, and
starts the new playlist
- `!similar list` shows results without playing (old default behavior)
- When an API key is set, Last.fm is tried first for richer results
- When no API key is set (or Last.fm returns empty), MusicBrainz is
used as a fallback (artist search -> tags -> similar recordings)
- `!similar play` picks a random result and delegates to `!play`
(searches YouTube for the artist + title)
- Without the music plugin loaded, `!similar` falls back to display mode
- MusicBrainz rate limit: 1 request/second (handled automatically)
Configuration (optional):