From 2bea55bedd4080e1db2226c010d489dcd6450811 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:02:31 +0200 Subject: [PATCH] feat(playlists): suggestion-row preview UX (#365) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(playlists): suggestion-row preview UX (30s preview, double-click play-next, scroll keep) Reworks the interaction on the suggestion rows below a playlist so users can audition songs before deciding what to do with them. - New "Preview" pill button left of each track title plays a 30-second mid-song sample via a parallel HTML5 audio element. The main player pauses on the first preview and auto-resumes when the preview ends. Switching previews chains without re-resuming. External main-player playback (spacebar, mediakey) cancels the preview without resuming. Animated underline shows the 30 s progress. - Double-click the row to insert the song at queueIndex + 1 and skip to it ("Play next"). Single-click is intentionally inert so a stray click next to the preview button no longer drops a song into the queue by accident. Tooltip on the row makes the affordance discoverable. - The + button still adds to the playlist, and now restores the .main-content scroll position so the page no longer jumps to the top after pressing it. - i18n keys in all 8 locales: playlists.preview / previewStop / previewShort / previewStopShort / suggestionDoubleClickPlayNext. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(playlists): WebKitGTK NULL-instance crash on preview teardown cucadmuh hit GLib-GObject-CRITICAL: invalid (NULL) pointer instance / g_signal_connect_data assertion failed, with the UI freezing after clicking a preview button. Root cause was the audio-element lifecycle: - `audio.src = ''` to "stop" leaves WebKitGTK's GStreamer playbin in a half-initialized state. The next signal_connect dereferences NULL. - Creating `new Audio()` per click stacked half-torn-down playbins during rapid switches. - `loadedmetadata` listeners on orphaned audio elements could call play() on an already-discarded instance. Fix: reuse one