From c50addaacf69a7ea1ad304affae927497f168465 Mon Sep 17 00:00:00 2001 From: Psychotoxical Date: Fri, 17 Apr 2026 15:33:58 +0200 Subject: [PATCH] fix(discord): remove dead fields, timeChanged invoke loop, and unsupported {paused} placeholder Co-Authored-By: Claude Sonnet 4.6 --- src-tauri/src/discord.rs | 29 ++++++++--------------------- src/locales/de.ts | 2 +- src/locales/en.ts | 2 +- src/locales/es.ts | 2 +- src/locales/fr.ts | 2 +- src/locales/nb.ts | 2 +- src/locales/nl.ts | 2 +- src/locales/ru.ts | 2 +- src/locales/zh.ts | 2 +- src/store/playerStore.ts | 10 ++-------- 10 files changed, 18 insertions(+), 37 deletions(-) diff --git a/src-tauri/src/discord.rs b/src-tauri/src/discord.rs index fc4a8aee..590c68b9 100644 --- a/src-tauri/src/discord.rs +++ b/src-tauri/src/discord.rs @@ -34,10 +34,6 @@ pub struct DiscordState { pub artwork_cache: Arc>>, /// HTTP client for iTunes API requests. blocking::Client is Clone (Arc-internally). pub http_client: Client, - /// Last calculated start timestamp for the current track (for freezing timer when paused). - pub last_start_timestamp: Mutex>, - /// Track whether we were playing in the last update to detect transitions. - pub was_playing: Mutex, } impl DiscordState { @@ -49,8 +45,6 @@ impl DiscordState { .timeout(std::time::Duration::from_secs(5)) .build() .unwrap_or_else(|_| Client::new()), - last_start_timestamp: Mutex::new(None), - was_playing: Mutex::new(false), } } } @@ -223,16 +217,13 @@ fn try_connect() -> Option { } /// Apply a template string, replacing placeholders with actual values. -/// Supported placeholders: {title}, {artist}, {album}, {paused} -fn apply_template(template: &str, title: &str, artist: &str, album: Option<&str>, is_playing: bool) -> String { - let paused_text = if is_playing { "" } else { "(Paused) " }; +/// Supported placeholders: {title}, {artist}, {album} +fn apply_template(template: &str, title: &str, artist: &str, album: Option<&str>) -> String { let album_text = album.unwrap_or(""); - template .replace("{title}", title) .replace("{artist}", artist) .replace("{album}", album_text) - .replace("{paused}", paused_text) } /// Update the Discord Rich Presence activity. @@ -245,11 +236,11 @@ fn apply_template(template: &str, title: &str, artist: &str, album: Option<&str> /// `cover_art_url` is provided. If false (default), fall back to the Psysonic app icon /// without making any external request — required for privacy opt-in. /// - `details_template`: template string for the "details" field. Default: "{artist} - {title}". -/// Supported placeholders: {title}, {artist}, {album}, {paused} +/// Supported placeholders: {title}, {artist}, {album} /// - `state_template`: template string for the "state" field. Default: "{album}". -/// Supported placeholders: {title}, {artist}, {album}, {paused} +/// Supported placeholders: {title}, {artist}, {album} /// - `large_text_template`: template string for the large image tooltip. Default: "{album}". -/// Supported placeholders: {title}, {artist}, {album}, {paused} +/// Supported placeholders: {title}, {artist}, {album} #[tauri::command] pub async fn discord_update_presence( state: tauri::State<'_, DiscordState>, @@ -258,7 +249,6 @@ pub async fn discord_update_presence( album: Option, is_playing: bool, elapsed_secs: Option, - duration_secs: Option, cover_art_url: Option, fetch_itunes_covers: bool, details_template: Option, @@ -304,13 +294,13 @@ pub async fn discord_update_presence( // Apply templates for the three configurable text fields. let details_str = details_template.as_deref().unwrap_or("{artist} - {title}"); - let details_text = apply_template(details_str, &title, &artist, album.as_deref(), is_playing); + let details_text = apply_template(details_str, &title, &artist, album.as_deref()); let state_str = state_template.as_deref().unwrap_or("{album}"); - let state_text = apply_template(state_str, &title, &artist, album.as_deref(), is_playing); + let state_text = apply_template(state_str, &title, &artist, album.as_deref()); let large_text_str = large_text_template.as_deref().unwrap_or("{album}"); - let large_text = apply_template(large_text_str, &title, &artist, album.as_deref(), is_playing); + let large_text = apply_template(large_text_str, &title, &artist, album.as_deref()); let assets = if let Some(ref url) = artwork_url { Assets::new() @@ -365,8 +355,5 @@ pub fn discord_clear_presence(state: tauri::State) -> Result<(), S *guard = None; } } - // Clear saved timestamp so next track starts fresh - let mut start_guard = state.last_start_timestamp.lock().unwrap(); - *start_guard = None; Ok(()) } diff --git a/src/locales/de.ts b/src/locales/de.ts index bbc56051..d13e9809 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -540,7 +540,7 @@ export const deTranslation = { discordAppleCovers: 'Cover über Apple Music für Discord laden', discordAppleCoversDesc: 'Sendet Künstler- und Albumname an die Apple-Such-API, um Cover für dein Discord-Profil zu finden. Standardmäßig aus Datenschutzgründen deaktiviert.', discordTemplates: 'Benutzerdefinierte Textvorlagen', - discordTemplatesDesc: 'Passen Sie an, welche Informationen in Ihrem Discord-Profil angezeigt werden. Variablen: {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Passen Sie an, welche Informationen in Ihrem Discord-Profil angezeigt werden. Variablen: {title}, {artist}, {album}', discordTemplateDetails: 'Primäre Zeile (details)', discordTemplateState: 'Sekundäre Zeile (state)', discordTemplateLargeText: 'Album-Tooltip (largeText)', diff --git a/src/locales/en.ts b/src/locales/en.ts index 29278607..dce69d1d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -542,7 +542,7 @@ export const enTranslation = { discordAppleCovers: 'Fetch covers from Apple Music for Discord', discordAppleCoversDesc: 'Sends the artist and album name to Apple\'s search API to find cover art for your Discord profile. Disabled by default for privacy.', discordTemplates: 'Custom text templates', - discordTemplatesDesc: 'Customize what information is shown on your Discord profile. Variables: {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Customize what information is shown on your Discord profile. Variables: {title}, {artist}, {album}', discordTemplateDetails: 'Primary line (details)', discordTemplateState: 'Secondary line (state)', discordTemplateLargeText: 'Album tooltip (largeText)', diff --git a/src/locales/es.ts b/src/locales/es.ts index f75e587c..917870c7 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -543,7 +543,7 @@ export const esTranslation = { discordAppleCovers: 'Obtener portadas de Apple Music para Discord', discordAppleCoversDesc: 'Envía el artista y nombre del álbum a la API de búsqueda de Apple para encontrar portadas para tu perfil de Discord. Desactivado por defecto por privacidad.', discordTemplates: 'Plantillas de texto personalizadas', - discordTemplatesDesc: 'Personaliza qué información se muestra en tu perfil de Discord. Variables: {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Personaliza qué información se muestra en tu perfil de Discord. Variables: {title}, {artist}, {album}', discordTemplateDetails: 'Línea principal (details)', discordTemplateState: 'Línea secundaria (state)', discordTemplateLargeText: 'Tooltip del álbum (largeText)', diff --git a/src/locales/fr.ts b/src/locales/fr.ts index 049bbc7b..7a8e7c79 100644 --- a/src/locales/fr.ts +++ b/src/locales/fr.ts @@ -538,7 +538,7 @@ export const frTranslation = { discordAppleCovers: 'Récupérer les pochettes via Apple Music pour Discord', discordAppleCoversDesc: 'Envoie le nom de l\'artiste et de l\'album à l\'API Apple pour trouver une pochette pour votre profil Discord. Désactivé par défaut pour des raisons de confidentialité.', discordTemplates: 'Modèles de texte personnalisés', - discordTemplatesDesc: 'Personnalisez les informations affichées sur votre profil Discord. Variables : {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Personnalisez les informations affichées sur votre profil Discord. Variables : {title}, {artist}, {album}', discordTemplateDetails: 'Ligne principale (details)', discordTemplateState: 'Ligne secondaire (state)', discordTemplateLargeText: 'Info-bulle album (largeText)', diff --git a/src/locales/nb.ts b/src/locales/nb.ts index 498bac91..17bc34a8 100644 --- a/src/locales/nb.ts +++ b/src/locales/nb.ts @@ -537,7 +537,7 @@ export const nbTranslation = { discordAppleCovers: 'Hent covere fra Apple Music til Discord', discordAppleCoversDesc: 'Sender artist- og albumnavn til Apples søke-API for å finne cover til Discord-profilen din. Deaktivert som standard av personvernhensyn.', discordTemplates: 'Egendefinerte tekstmaler', - discordTemplatesDesc: 'Tilpass hvilken informasjon som vises på Discord-profilen din. Variabler: {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Tilpass hvilken informasjon som vises på Discord-profilen din. Variabler: {title}, {artist}, {album}', discordTemplateDetails: 'Primær linje (details)', discordTemplateState: 'Sekundær linje (state)', discordTemplateLargeText: 'Album-verktøytips (largeText)', diff --git a/src/locales/nl.ts b/src/locales/nl.ts index d3782fc2..d3673cc6 100644 --- a/src/locales/nl.ts +++ b/src/locales/nl.ts @@ -537,7 +537,7 @@ export const nlTranslation = { discordAppleCovers: 'Hoezen ophalen via Apple Music voor Discord', discordAppleCoversDesc: 'Stuurt artiest- en albumnaam naar de Apple-zoek-API om een hoes te vinden voor je Discord-profiel. Standaard uitgeschakeld vanwege privacy.', discordTemplates: 'Aangepaste tekstsjablonen', - discordTemplatesDesc: 'Pas aan welke informatie wordt weergegeven op je Discord-profiel. Variabelen: {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Pas aan welke informatie wordt weergegeven op je Discord-profiel. Variabelen: {title}, {artist}, {album}', discordTemplateDetails: 'Primaire regel (details)', discordTemplateState: 'Secundaire regel (state)', discordTemplateLargeText: 'Album-tooltip (largeText)', diff --git a/src/locales/ru.ts b/src/locales/ru.ts index 62957c4b..a10f5c0c 100644 --- a/src/locales/ru.ts +++ b/src/locales/ru.ts @@ -560,7 +560,7 @@ export const ruTranslation = { discordAppleCovers: 'Загружать обложки через Apple Music для Discord', discordAppleCoversDesc: 'Отправляет имя исполнителя и альбома в Apple Music API для поиска обложки для профиля Discord. По умолчанию отключено из соображений конфиденциальности.', discordTemplates: 'Пользовательские шаблоны текста', - discordTemplatesDesc: 'Настройте, какая информация отображается в профиле Discord. Переменные: {title}, {artist}, {album}, {paused}', + discordTemplatesDesc: 'Настройте, какая информация отображается в профиле Discord. Переменные: {title}, {artist}, {album}', discordTemplateDetails: 'Основная строка (details)', discordTemplateState: 'Вторичная строка (state)', discordTemplateLargeText: 'Подсказка альбома (largeText)', diff --git a/src/locales/zh.ts b/src/locales/zh.ts index 3a816d76..0035d320 100644 --- a/src/locales/zh.ts +++ b/src/locales/zh.ts @@ -533,7 +533,7 @@ export const zhTranslation = { discordAppleCovers: '通过 Apple Music 为 Discord 获取封面', discordAppleCoversDesc: '将艺术家和专辑名称发送至 Apple 搜索 API,以为 Discord 个人资料查找封面图片。出于隐私考虑,默认禁用。', discordTemplates: '自定义文本模板', - discordTemplatesDesc: '自定义在 Discord 个人资料上显示的信息。变量:{title}, {artist}, {album}, {paused}', + discordTemplatesDesc: '自定义在 Discord 个人资料上显示的信息。变量:{title}, {artist}, {album}', discordTemplateDetails: '主行 (details)', discordTemplateState: '副行 (state)', discordTemplateLargeText: '专辑提示 (largeText)', diff --git a/src/store/playerStore.ts b/src/store/playerStore.ts index 06545f4c..76f88873 100644 --- a/src/store/playerStore.ts +++ b/src/store/playerStore.ts @@ -692,7 +692,6 @@ export function initAudioListeners(): () => void { let discordPrevTemplateDetails: string | null = null; let discordPrevTemplateState: string | null = null; let discordPrevTemplateLargeText: string | null = null; - let discordPrevCurrentTime: number | null = null; function syncDiscord() { const { currentTrack, isPlaying, currentTime } = usePlayerStore.getState(); @@ -723,8 +722,7 @@ export function initAudioListeners(): () => void { const detailsTemplateChanged = discordTemplateDetails !== discordPrevTemplateDetails; const stateTemplateChanged = discordTemplateState !== discordPrevTemplateState; const largeTextTemplateChanged = discordTemplateLargeText !== discordPrevTemplateLargeText; - const timeChanged = Math.abs(currentTime - (discordPrevCurrentTime ?? -1)) > 1; // Only update if time changed by more than 1 second - if (!trackChanged && !playingChanged && !coversSettingChanged && !detailsTemplateChanged && !stateTemplateChanged && !largeTextTemplateChanged && !timeChanged) return; + if (!trackChanged && !playingChanged && !coversSettingChanged && !detailsTemplateChanged && !stateTemplateChanged && !largeTextTemplateChanged) return; discordPrevTrackId = currentTrack.id; discordPrevIsPlaying = isPlaying; @@ -732,17 +730,13 @@ export function initAudioListeners(): () => void { discordPrevTemplateDetails = discordTemplateDetails; discordPrevTemplateState = discordTemplateState; discordPrevTemplateLargeText = discordTemplateLargeText; - discordPrevCurrentTime = currentTime; invoke('discord_update_presence', { title: currentTrack.title, artist: currentTrack.artist ?? 'Unknown Artist', album: currentTrack.album ?? null, isPlaying, - // Always pass elapsedSecs so backend can handle both playing and paused states. - // Backend will freeze timer when paused using end timestamp. - elapsedSecs: currentTime, - durationSecs: currentTrack.duration, + elapsedSecs: isPlaying ? currentTime : null, // coverArtUrl is intentionally not passed — Subsonic URLs require auth. // iTunes cover fetching is only done when explicitly opted in. coverArtUrl: null,