This commit is contained in:
kveld9
2026-04-16 20:34:55 -03:00
parent b6812de26b
commit 28844e8456
12 changed files with 13111 additions and 740 deletions
+34 -15
View File
@@ -216,6 +216,19 @@ fn try_connect() -> Option<DiscordIpcClient> {
Some(client)
}
/// 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 — " };
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.
///
/// - `is_playing`: true = playing (timer shown), false = paused (no timer, state shows "Paused").
@@ -225,6 +238,12 @@ fn try_connect() -> Option<DiscordIpcClient> {
/// - `fetch_itunes_covers`: if true, fetch artwork from the iTunes Search API when no
/// `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}
/// - `state_template`: template string for the "state" field. Default: "{album}".
/// Supported placeholders: {title}, {artist}, {album}, {paused}
/// - `large_text_template`: template string for the large image tooltip. Default: "{album}".
/// Supported placeholders: {title}, {artist}, {album}, {paused}
#[tauri::command]
pub async fn discord_update_presence(
state: tauri::State<'_, DiscordState>,
@@ -235,6 +254,9 @@ pub async fn discord_update_presence(
elapsed_secs: Option<f64>,
cover_art_url: Option<String>,
fetch_itunes_covers: bool,
details_template: Option<String>,
state_template: Option<String>,
large_text_template: Option<String>,
) -> Result<(), String> {
// Resolve artwork on a dedicated blocking thread — reqwest::blocking must not
// run on the Tokio async executor directly.
@@ -273,28 +295,25 @@ pub async fn discord_update_presence(
let client = guard.as_mut().unwrap();
// Discord RPC only exposes two visible text rows (details + state).
// The application name "Psysonic" is shown automatically by Discord as the
// header line. Album goes into large_text — visible as a hover tooltip on
// the cover art icon.
let large_text = album.as_deref().unwrap_or("Psysonic");
// 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 state_str = state_template.as_deref().unwrap_or("{album}");
let state_text = apply_template(state_str, &title, &artist, album.as_deref(), is_playing);
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 assets = if let Some(ref url) = artwork_url {
Assets::new()
.large_image(url.as_str())
.large_text(large_text)
.large_text(&large_text)
} else {
// Fallback to default Psysonic icon
Assets::new()
.large_image("psysonic")
.large_text(large_text)
};
// When paused, show "Paused" as the state text (replaces artist name).
let state_text: String = if is_playing {
artist.clone()
} else {
"Paused".to_string()
.large_text(&large_text)
};
// ActivityType::Listening causes the Discord client to auto-start a running
@@ -308,7 +327,7 @@ pub async fn discord_update_presence(
let mut activity = Activity::new()
.activity_type(activity_type)
.details(&title)
.details(&details_text)
.state(&state_text)
.assets(assets);