feat(discord): add server cover art source (#462)

* feat(discord): add server cover art source

The old Apple Music toggle is replaced with a radio selector which let's you choose
between Apple Music, Server and no image.

It's important to note that the server needs to be publicly accessible.

Translations have been added for all locales

* feat(discord): toggle UI for cover source and tightened defaults

- Replace cover-source radio buttons with three indented sub-toggles
  (none / server / apple) under Discord Rich Presence; mutex via
  setDiscordCoverSource — turning one on flips the others off.
- Default discordCoverSource is now 'server' for fresh installs
  (opt-in friendly: own server, no third-party data leak). Existing
  users keep their state via the legacy bool migration.
- Tighten template defaults: details {artist}, state {title}, largeText
  unchanged. Existing users keep their persisted values.

* docs(contributors): credit Sayykii + changelog entry for #462

---------

Co-authored-by: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com>
This commit is contained in:
Sayykii
2026-05-05 22:30:23 +03:00
committed by GitHub
parent 8d8c1aa8a3
commit e1f2cb4c37
13 changed files with 159 additions and 51 deletions
+39 -10
View File
@@ -269,6 +269,13 @@ const CONTRIBUTORS = [
'WebView2 idle hooks when Tauri windows are hidden — Windows GPU and compositor mitigation (PR #273)',
],
},
{
github: 'Sayykii',
since: '1.46.0',
contributions: [
'Discord Rich Presence: cover art from your own server (Subsonic getAlbumInfo2) with three-way picker — none / server / Apple Music (PR #462)',
],
},
{
github: 'Psychotoxical',
since: '1.0.0',
@@ -2803,14 +2810,36 @@ export default function Settings() {
</div>
{auth.discordRichPresence && (
<>
<div className="settings-section-divider" />
<div className="settings-toggle-row">
<div>
<div style={{ fontWeight: 500 }}>{t('settings.discordAppleCovers')}</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{t('settings.discordAppleCoversDesc')}</div>
</div>
<label className="toggle-switch" aria-label={t('settings.discordAppleCovers')}>
<input type="checkbox" checked={auth.enableAppleMusicCoversDiscord} onChange={e => auth.setEnableAppleMusicCoversDiscord(e.target.checked)} />
<div className="settings-toggle-row" style={{ padding: '4px var(--space-3) 4px var(--space-6)', fontSize: 13 }}>
<div style={{ fontWeight: 500 }}>{t('settings.discordCoverNone')}</div>
<label className="toggle-switch" aria-label={t('settings.discordCoverNone')}>
<input
type="checkbox"
checked={auth.discordCoverSource === 'none'}
onChange={e => auth.setDiscordCoverSource(e.target.checked ? 'none' : 'server')}
/>
<span className="toggle-track" />
</label>
</div>
<div className="settings-toggle-row" style={{ padding: '4px var(--space-3) 4px var(--space-6)', fontSize: 13 }}>
<div style={{ fontWeight: 500 }}>{t('settings.discordCoverServer')}</div>
<label className="toggle-switch" aria-label={t('settings.discordCoverServer')}>
<input
type="checkbox"
checked={auth.discordCoverSource === 'server'}
onChange={e => auth.setDiscordCoverSource(e.target.checked ? 'server' : 'none')}
/>
<span className="toggle-track" />
</label>
</div>
<div className="settings-toggle-row" style={{ padding: '4px var(--space-3) 4px var(--space-6)', fontSize: 13 }}>
<div style={{ fontWeight: 500 }}>{t('settings.discordCoverApple')}</div>
<label className="toggle-switch" aria-label={t('settings.discordCoverApple')}>
<input
type="checkbox"
checked={auth.discordCoverSource === 'apple'}
onChange={e => auth.setDiscordCoverSource(e.target.checked ? 'apple' : 'none')}
/>
<span className="toggle-track" />
</label>
</div>
@@ -2825,7 +2854,7 @@ export default function Settings() {
type="text"
value={auth.discordTemplateDetails}
onChange={e => auth.setDiscordTemplateDetails(e.target.value)}
placeholder="{artist} - {title}"
placeholder="{artist}"
/>
</div>
<div className="form-group" style={{ marginBottom: '0.75rem' }}>
@@ -2835,7 +2864,7 @@ export default function Settings() {
type="text"
value={auth.discordTemplateState}
onChange={e => auth.setDiscordTemplateState(e.target.value)}
placeholder="{album}"
placeholder="{title}"
/>
</div>
<div className="form-group">