Skip to content

feat(ui): show lyrics in the mini-player - #602

Merged
InstaZDLL merged 2 commits into
mainfrom
feat/580-mini-player-lyrics
Sep 9, 2026
Merged

feat(ui): show lyrics in the mini-player#602
InstaZDLL merged 2 commits into
mainfrom
feat/580-mini-player-lyrics

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Closes #580 — raised by @jo-el414, and originally in discussion #503.

The mini-player could play a track but not show a word of it. Anyone using the widget as their whole surface had to restore the main window just to read along.

What it does

A Mic2 toggle in the top bar opens the current track's lyrics in the same slot the up-next list uses.

  • Synced LRC scrolls itself, centring the active line. Clicking a line seeks to it.
  • The active word takes the progressive karaoke fill, through the same useKaraokeWordFill the immersive column uses — so the sweep stays continuous between the 4 Hz player:position events instead of stepping every 250 ms.
  • Unsynced payloads and radio sessions render as plain scrollable text.
  • Idle and empty states are distinguished: nothing playing reads differently from a track with no lyrics.

Three decisions that aren't obvious from the diff

The overlay is mounted only while open, and that is the point. useTrackLyrics fetches on every track change. This is a second webview, so its hook instance is a genuinely separate fetch rather than a second consumer of the main window's — leaving it mounted behind a closed overlay would fire an extra fetch_lyrics per track for lyrics nobody asked to see. Unmounting puts that cost behind the user's actual request, and the backend cache serves the overlap when both surfaces are open at once.

The two overlays now share one state slot ("none" | "queue" | "lyrics") rather than a boolean each. They both cover the whole content area, so two independent flags would let them stack. A side effect worth noting: whichever overlay is open now marks the cover / title / seek subtree inert, which the up-next list previously did only for local playback.

No editing surface. At 280×380, draggable down to 240×320, there is no room for the side panel's source label, provider picker, or the import / refetch / clear actions — those stay in the main window. And unlike up-next, this is not gated on Spotify playback, matching the player bar's own lyrics toggle, which is likewise ungated.

Scope

  • One new string across all 17 locales. The button label and the header reuse the existing lyrics.* keys rather than duplicating them.
  • docs/features/ui.md and docs/features/integrations.md updated — "one lyrics fetch, two consumers" is now three, and the progressive fill is no longer immersive-only.
  • Second commit is comment-only tidy-up in SettingsView / OnboardingModal, no behaviour change.

Checks

bun run typecheck · bun run lint · prettier --check on every changed file — all green. No Rust touched.

Not verified on a running app: this box has no display, so the karaoke fill and the auto-scroll at 280×380 want a look before merge.

#582 (the standalone floating lyrics window) stays separate and stalled.

Summary by CodeRabbit

  • Nouvelles fonctionnalités

    • Ajout d’un lecteur de paroles synchronisées dans le mini-lecteur, avec défilement automatique et progression mot par mot.
    • Prise en charge des paroles synchronisées, non synchronisées, radio et des titres sans paroles.
    • Les overlays de paroles et de file d’attente sont désormais exclusifs pour une navigation plus claire.
  • Accessibilité

    • Le contenu principal devient inactif lorsqu’un overlay est ouvert, tout en conservant la barre supérieure interactive.
  • Documentation et traductions

    • Documentation mise à jour et messages d’absence de paroles ajoutés dans toutes les langues disponibles.

Closes #580, asked for in discussion #503. The mini-player could play a
track but not show a word of it, so anyone using the widget as their
whole surface had to restore the main window to read along.

A Mic2 toggle in the top bar opens the lyrics in the same slot the
up-next list uses. Synced LRC scrolls itself and centres the active
line; clicking a line seeks to it; unsynced payloads and radio sessions
render as plain scrollable text.

Three decisions worth stating, because none is obvious from the diff:

The overlay is mounted only while open. useTrackLyrics fetches on every
track change, so leaving it mounted behind a closed overlay would fire a
second fetch_lyrics per track from this webview on top of the main
window's — this is a separate webview, so it is a genuinely separate
fetch and not a second consumer of the main window's. Unmounting puts
that cost behind the user's actual request, and the backend cache serves
the overlap when both surfaces are open.

The two overlays share one state slot rather than a boolean each. They
both cover the whole content area, so two independent flags would let
them stack. Whichever is open now marks the cover / title / seek subtree
inert, which the up-next list previously did only for local playback.

The active word takes the progressive karaoke fill, through the same
useKaraokeWordFill the immersive column uses — so the sweep stays
continuous between the 4 Hz player:position events instead of stepping
every 250 ms. The side panel deliberately keeps the cheap discrete
version because it is a strip beside something else; the mini-player is
a dedicated reading surface, so it takes the fill despite being smaller.

No editing surface: at 280x380, draggable down to 240x320, there is no
room for the source label, provider picker or the import / refetch /
clear actions. Those stay in the main window. Unlike up-next this is not
gated on Spotify playback, matching the player bar's own lyrics toggle.

One new string in all 17 locales; the button label and the header reuse
the existing lyrics keys rather than duplicating them.

Claude-Session: https://claude.ai/code/session_01Mvi54fX8T3MyxNX1asWsxd
The settings tab bar and the onboarding wizard both opened their doc
comment by describing what they resemble before describing what they do.
The comparison dated from when neither existed and carries nothing now
that both are built and documented in docs/features/ui.md — a reader
lands on the shape rather than the resemblance.

Comments only; no behaviour change.

Claude-Session: https://claude.ai/code/session_01Mvi54fX8T3MyxNX1asWsxd
@InstaZDLL InstaZDLL added scope: frontend React/Vite frontend (src/) scope: i18n Translations (src/i18n/) scope: docs Docs, README, assets type: feat New feature size: l 200-500 lines labels Sep 9, 2026
@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 61661d23-1de0-43af-9e9b-0d537938d3fe

📥 Commits

Reviewing files that changed from the base of the PR and between 2e1760f and 773865f.

📒 Files selected for processing (22)
  • docs/features/integrations.md
  • docs/features/ui.md
  • src/components/common/OnboardingModal.tsx
  • src/components/views/MiniPlayer.tsx
  • src/components/views/SettingsView.tsx
  • src/i18n/locales/ar.json
  • src/i18n/locales/de.json
  • src/i18n/locales/en.json
  • src/i18n/locales/es.json
  • src/i18n/locales/fr.json
  • src/i18n/locales/hi.json
  • src/i18n/locales/id.json
  • src/i18n/locales/it.json
  • src/i18n/locales/ja.json
  • src/i18n/locales/ko.json
  • src/i18n/locales/nl.json
  • src/i18n/locales/pt-BR.json
  • src/i18n/locales/pt.json
  • src/i18n/locales/ru.json
  • src/i18n/locales/tr.json
  • src/i18n/locales/zh-CN.json
  • src/i18n/locales/zh-TW.json

Included review availability: 9 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 10 reviews per hour.


📝 Walkthrough

Walkthrough

Le mini-lecteur ajoute un overlay de paroles exclusif avec chargement, synchronisation, défilement automatique, recherche par ligne et rendu des paroles non synchronisées. Les contrôles, l’accessibilité, la documentation et les traductions sont mis à jour.

Changes

Paroles du mini-lecteur

Layer / File(s) Summary
Rendu et synchronisation des paroles
src/components/views/MiniPlayer.tsx, docs/features/integrations.md
MiniLyricsOverlay charge les paroles du morceau, gère les états sans contenu et affiche les paroles synchronisées avec remplissage progressif des mots. Les paroles non synchronisées, radio ou non analysables utilisent un rendu texte.
État et contrôles des overlays
src/components/views/MiniPlayer.tsx
L’état overlay coordonne exclusivement la file d’attente et les paroles. Les boutons ouvrent ou ferment les overlays. Le contenu masqué devient inerte pour le clavier et le lecteur d’écran.
Documentation et traductions
docs/features/ui.md, src/components/common/OnboardingModal.tsx, src/components/views/SettingsView.tsx, src/i18n/locales/*
La documentation décrit le nouvel overlay et ses contraintes. Les références à « Lokal-style » sont retirées. Les traductions ajoutent les libellés du mini-lecteur et son état sans paroles.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~30 minutes

Merge Risk: ⚪ Minimal · up to 77386

No actionable merge-blocking risk is established in the current changes.

Sequence Diagram(s)

sequenceDiagram
  participant Lecteur
  participant OverlayParoles
  participant useTrackLyrics
  participant useKaraokeWordFill
  Lecteur->>OverlayParoles: ouvrir les paroles
  OverlayParoles->>useTrackLyrics: charger les paroles du morceau
  useTrackLyrics-->>OverlayParoles: retourner le contenu et l’état
  OverlayParoles->>useKaraokeWordFill: calculer le remplissage du mot actif
  useKaraokeWordFill-->>OverlayParoles: retourner la progression
  OverlayParoles-->>Lecteur: afficher et faire défiler les paroles
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Les changements fonctionnels et la documentation sur les paroles restent liés à #580. En revanche, le nettoyage des commentaires dans SettingsView et OnboardingModal, ainsi que la suppression des ment… Retirer ces modifications non liées ou les déplacer dans une PR distincte. Conserver ici uniquement les changements nécessaires au mini-lecteur, aux traductions et à la documentation correspondante.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. (19 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed La PR répond à l’objectif de #580 en ajoutant une vue des paroles au mini-lecteur. Elle couvre les paroles synchronisées et non synchronisées, la recherche de paroles, le défilement, la recherche au c…
Title check ✅ Passed Le titre décrit clairement l’ajout des paroles dans le mini-lecteur. Il suit aussi le format Conventional Commits avec le scope ui.
Description check ✅ Passed La description explique le comportement, les choix techniques, le périmètre, les vérifications exécutées et la limitation de validation visuelle. Elle référence aussi l’issue liée. Les sections formel…
Full details: Out of Scope Changes check

Explanation

Les changements fonctionnels et la documentation sur les paroles restent liés à #580. En revanche, le nettoyage des commentaires dans SettingsView et OnboardingModal, ainsi que la suppression des mentions « Lokal-style », ne sont pas nécessaires à cette fonctionnalité.

Full details: Docstring Coverage

Explanation

Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. (19 skipped: 19 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/580-mini-player-lyrics

Comment @coderabbitai help to get the list of available commands.

@InstaZDLL
InstaZDLL merged commit 646f795 into main Sep 9, 2026
15 checks passed
@InstaZDLL
InstaZDLL deleted the feat/580-mini-player-lyrics branch September 9, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: docs Docs, README, assets scope: frontend React/Vite frontend (src/) scope: i18n Translations (src/i18n/) size: l 200-500 lines type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Lyrics view in Miniplayer.

1 participant