From 4eedf59d44a8e417604fe4bca467a9ff676188be Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Wed, 11 Feb 2026 20:48:30 +0100 Subject: [PATCH] Update Spotify width-aware text Amp-Thread-ID: https://ampcode.com/threads/T-019c4e3e-ee34-77fd-98b0-6769b0567dd9 Co-authored-by: Amp --- AGENTS.md | 1 + README.md | 3 +- src/image.rs | 4 +-- src/lib.rs | 2 +- src/main.rs | 90 ++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 69 insertions(+), 31 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6e07ad4..dfcf791 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,6 +3,7 @@ ## Overview Standalone CLI application to interact with the Display FS V1 family (0.96 inch + 3.5 inch), detect if it's connected, and display content. +Spotify now-playing output is width-aware on both display sizes. ## Hardware diff --git a/README.md b/README.md index ae88025..189236b 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,8 @@ The `--orientation` flag switches between landscape (160x80, default) and portra ### Spotify Now Playing (macOS) -Display the currently playing Spotify track: +Display the currently playing Spotify track. The title/artist lines automatically truncate +to the current display width (including large-screen auto-fit): ```bash # Show once diff --git a/src/image.rs b/src/image.rs index c21aac5..d26e138 100644 --- a/src/image.rs +++ b/src/image.rs @@ -195,8 +195,8 @@ pub fn measure_multiline_text(text: &str, font_size: f32) -> (u32, u32) { (max_width, total_height) } -const MIN_FONT_SIZE: f32 = 8.0; -const MAX_FONT_SIZE: f32 = 72.0; +pub const MIN_FONT_SIZE: f32 = 8.0; +pub const MAX_FONT_SIZE: f32 = 72.0; const HORIZONTAL_PADDING: u32 = 8; const VERTICAL_PADDING: u32 = 4; diff --git a/src/lib.rs b/src/lib.rs index aaeb81e..079e6b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ pub use image::{ calculate_max_lines_oriented, create_blank_image_for_display, create_text_image, create_text_image_for_display, create_text_image_oriented, image_to_rgb565_bytes, image_to_rgb565_bytes_for_display, image_to_rgb565_bytes_oriented, measure_text_with_font_size, - Orientation, DISPLAY_HEIGHT, DISPLAY_WIDTH, + Orientation, DISPLAY_HEIGHT, DISPLAY_WIDTH, MAX_FONT_SIZE, MIN_FONT_SIZE, }; pub use port::{ find_display_port, is_display_connected, open_connection, DisplayConfig, DisplayModel, diff --git a/src/main.rs b/src/main.rs index 4743e71..a892f26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ use clap::{Parser, Subcommand, ValueEnum}; use display_fs::{ - calculate_auto_fit_size_for_display, create_text_image_for_display, find_display_port, - get_now_playing, image_to_rgb565_bytes_for_display, is_display_connected, open_connection, + calculate_auto_fit_size_for_display, calculate_max_chars_per_line_for_display, + create_text_image_for_display, find_display_port, get_now_playing, + image_to_rgb565_bytes_for_display, is_display_connected, open_connection, send_image_to_display_for_model, split_into_pages_for_display, DisplayConfig, DisplayModel, - Orientation, + Orientation, MIN_FONT_SIZE, }; use std::process::{Command, ExitCode}; use std::thread; @@ -453,28 +454,18 @@ fn run_spotify(args: SpotifyArgs) -> ExitCode { let interval = Duration::from_secs_f32(args.display.effective_delay()); loop { - let text = match get_now_playing() { - Some(np) if np.is_playing => { - format!( - "♪ {}\nby {}", - truncate(&np.track, 18), - truncate(&np.artist, 18) - ) - } - Some(np) => { - format!( - "|| {}\nby {}", - truncate(&np.track, 18), - truncate(&np.artist, 18) - ) - } - None => "Spotify not running".to_string(), - }; - - let current = get_now_playing().map(|np| (np.track, np.artist)); + let now_playing = get_now_playing(); + let current = now_playing + .as_ref() + .map(|np| (np.track.clone(), np.artist.clone())); let should_update = current != last_track; if should_update { + let max_line_len = spotify_max_line_len(&args.display, orientation, display_config); + let text = match now_playing { + Some(np) => format_spotify_text(&np.track, &np.artist, np.is_playing, max_line_len), + None => "Spotify not running".to_string(), + }; let font_size = if args.display.auto { let size = calculate_auto_fit_size_for_display( &text, @@ -525,12 +516,57 @@ fn run_spotify(args: SpotifyArgs) -> ExitCode { ExitCode::SUCCESS } -fn truncate(s: &str, max_len: usize) -> String { - if s.chars().count() <= max_len { - s.to_string() - } else { - format!("{}...", s.chars().take(max_len - 3).collect::()) +fn spotify_max_line_len( + display: &DisplayOptions, + orientation: Orientation, + config: DisplayConfig, +) -> usize { + if display.auto { + return calculate_max_chars_per_line_for_display( + MIN_FONT_SIZE, + orientation, + config.width as u32, + config.height as u32, + ); } + + calculate_max_chars_per_line_for_display( + display.font_size, + orientation, + config.width as u32, + config.height as u32, + ) +} + +fn format_spotify_text(track: &str, artist: &str, is_playing: bool, max_len: usize) -> String { + let prefix = if is_playing { "♪" } else { "||" }; + let prefix_len = prefix.chars().count(); + let track_line = format!( + "{} {}", + prefix, + trim_to_width(track, max_len.saturating_sub(prefix_len + 1)) + ); + let artist_line = format!("by {}", trim_to_width(artist, max_len.saturating_sub(3))); + + format!("{}\n{}", track_line, artist_line) +} + +fn trim_to_width(text: &str, max_len: usize) -> String { + if max_len == 0 { + return String::new(); + } + + let text_len = text.chars().count(); + if text_len <= max_len { + return text.to_string(); + } + + if max_len <= 3 { + return text.chars().take(max_len).collect(); + } + + let truncated: String = text.chars().take(max_len - 3).collect(); + format!("{}...", truncated) } fn detect_display() -> ExitCode {