Skip to content

Windows: the Spotify pill through the system's media session, and an opt-in new-song announcement - #374

Closed
shakibbinkabir wants to merge 2 commits into
Louis-CFM:mainfrom
shakibbinkabir:spotify-windows
Closed

shakibbinkabir wants to merge 2 commits into
Louis-CFM:mainfrom
shakibbinkabir:spotify-windows

Conversation

@shakibbinkabir

@shakibbinkabir shakibbinkabir commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

#372 brought the Spotify pill to Linux and left Windows with "no music source yet". This adds that source, and, as a separate commit, an opt-in announcement of each new song. Part of #322, for Spotify only, like the pill on the Mac and on Linux.

Commit What Needs
1 ba0daa7 Windows: the Spotify pill, through the system's media session. No view of its own: the page, the card and Mochi's dance are #372's, untouched. nothing
2 e428a68 A new song can open the island on its card for a moment. Windows and Linux, off by default. The idea and its look are @Edurique's, from #83. 1

Take 1 alone if 2 is not for Coucou: it is a behaviour the Mac does not have, which is why it is its own commit and off unless turned on.

1. The Spotify pill on Windows

Playing Paused
card, playing card, paused
Among the pills Folded, while it plays
overview compact

(The teal VS Code Mochi is my own colour setting, not part of this.)

How it reads Spotify

  • No account, no key, no network call. Spotify reports its track to Windows (System Media Transport Controls) and the pill reads that, behind the same five functions the Linux client implements. The cover comes with the session too, so nothing is fetched.
  • No polling. While the pill is declared, one thread (coucou-spotify) sleeps on a channel. Windows wakes it for SessionsChanged (Spotify starting or quitting) and for the session's MediaPropertiesChanged, PlaybackInfoChanged and TimelinePropertiesChanged. Undeclaring the pill sends it Stop and removes the handlers.
  • A playing track is not news. Spotify updates its timeline as it plays, so a reading goes to the island only when something changed other than the clock running on (is_news, with 1.5 s of slack before it counts as a seek).
  • Spotify only. The session is picked by its app id: SpotifyAB.SpotifyMusic_… (Microsoft Store) or Spotify.exe (spotify.com). A browser or another player is never shown.
  • Controls: play/pause, next, previous and seek go through the session. Open Spotify follows a spotify: link, which starts it or brings it forward; when nothing registered that link, the download page.

Where Windows differs

All of it is in windows/README.md too.

  • Shuffle and repeat are left out of the card. Spotify answers true to TryChangeShuffleActiveAsync and TryChangeAutoRepeatModeAsync, and three seconds later the session still reports them off. I checked that outside Coucou as well. Buttons that do nothing seemed worse than no buttons, so the state carries modes (false on Windows, true on Linux) and the card hides the two.
  • Volume. The session has none. The slider moves Spotify's level in the Windows volume mixer, not Spotify's own slider.
  • No Spotify URI in a session. Tracks get a spotify:local:<artist>:<album>:<title> id, so an ad is not recognised as one and shows under the name Spotify gives it.
  • The cover is sent through the same spotify-artwork event, and sent again when its bytes change: Spotify names the new track a moment before it hands over the picture.

2. A new song

A new song: the island opens on Spotify's card for three seconds and folds back

The real island, with the real Spotify skipping to its next track (muted in the Windows mixer for the recording, hence the volume at zero). The VS Code pill is in front before, and gets its place back after.

When Spotify moves on to another song, the island opens on Spotify's card for three seconds and folds back, and the pill that was in front is in front again. A light in Mochi's colour breathes behind him, the cover glows and a sheen crosses it, so it reads as news and not as an island that opened by accident. No sound: music is playing.

This is #83's announcement, rebuilt on the card and the state machine as they are today. @Edurique is co-author of the commit.

  • Off by default, with one row under Spotify in Settings → Integrations. The island never opens on its own for news that asks nothing (a finished deploy only shows the compact island), and the Mac does not do this, so it is something to turn on rather than something that starts happening.

    The new row in Settings

  • What a new song is: one that starts after another. Not the first heard since Spotify started (the compact island already shows for that), not the same one going on after a pause or a seek, never an ad. Windows names a track before it says it plays; it is announced once it does.

  • Never over the user. Not when the island is open, under the mouse, pinned, or waiting for an answer. The mouse coming, a key or an alert makes it an open island like any other: the auto-close delay applies again, the usual sounds come back, and the front stays where the user sees it. It never takes the keyboard.

  • The state machine gains glance(seconds): open, and fold after its own delay instead of the auto-close preference. It is the hover-open's short countdown with another length, and it ends the same way (userInteracted).

  • The light is Mochi's colour, so a colour picked for the pill in Settings → Active pills is the light's too:

    The same, with a violet Mochi

  • Nothing of the card changes outside those three seconds. The light is three one-shot animations under an announce class that the card only wears while a song is announced.

What differs from #83: three seconds instead of 4.5; off by default instead of on; the light in the Mochi's colour instead of Spotify's green; and the cover stays the card's small one. #83 puts a large cover in Mochi's place, which would restyle the card #372 shipped, so that part is not here.

The repo's rules

  • No new dependency. Only more features of the windows crate that is already there. Cargo.lock is unchanged.
  • No network, nothing stored, no secret. One new setting, announceSongs, false when absent from an older settings.json.
  • The pill id is unchanged (integration_spotify). Its support goes from "linux" to "yes", and the "linux" support kind, which only this pill used, goes away.
  • Nothing shipped is restyled. The card is Linux: the Spotify pill over MPRIS, and Mochi dances to it #372's. On Linux nothing about it changes (modes is true there); on Windows it had never been shown. The Settings row follows the rows around it (label, toggle, hint).
  • CPU. With the pill declared and Spotify open and paused, the coucou-spotify thread used 0 ms of CPU in 30 s, while Spotify touched its timeline 7 times. During 10 s of playback the page received 0 spotify events. With announcements off, a report costs one more comparison; on, one timer per song.
  • Translations. The two new strings are in extra.json in the nine languages. They were written with Claude, not by native speakers: worth a look from someone who speaks them.

Tested

Windows 11 Pro (26300), Spotify 1.303.264 from the Microsoft Store, in the built app, driving the island's own commands and listening to its events.

1, the pill

Title, artist, album, duration, position, cover read correctly
Play / pause follows
Seek to 1:00 lands there
Next, previous track and cover follow
Volume 100 → 40 → 100 mixer level follows
Spotify quits while Coucou runs the island is told 0.3 s later
Open Spotify from there Spotify starts, its session is picked up 1.8 s later, same track
Pill not declared nothing is read

2, a new song

Skip to the next track, touch nothing opens 0.25 s after the skip, stays 3 s, folds; no sound started; the pill that was in front is back
A key pressed 1.5 s in the light goes at once, the island stays for the auto-close delay (10 s here) and folds with its usual sound; Spotify stays in front
A colour picked for the pill the light is that colour (second recording)
  • npx tsc --noEmit, npm test (375 pass) and cargo test --workspace --locked (220 + 30 pass) on Windows. For 1: six Rust tests on the parts that need no Spotify (telling its session from the others, the WinRT clock, a reading becoming the island's state, a bad clock or a missing title, cover keys, is_news), and page tests for modes and the pill being offered on both systems. For 2: five tests on glance in the state machine, eight on the page (what a new song is, off by default, the front handed back, a pause between two songs, taken over, songs skipped through, not free / paused / Spotify restarted, the card's light and its colour), one on the setting.
  • Linux: pull requests are only built on Windows here, and this touches code Linux compiles and a page Linux shows, so I ran the Linux job's steps on these two commits in my fork (ubuntu-22.04): tsc, 375 page tests, cargo test --workspace --locked (246 + 34 pass), no warnings in the build. The run.

Not tested

  • Spotify from the spotify.com installer. I only have the Store build; Spotify.exe is the app id that build is known by.
  • A machine without Spotify (the registry check and the download page).
  • An ad. None came up.
  • Spotify playing on another device through Connect.
  • The listener's CPU while a track plays. It wakes for each timeline update and makes one reading; I measured what reaches the page, not the thread.
  • Linux on a real desktop, for both commits. The MPRIS code is untouched apart from modes: true in its state; the announcement is page code that Linux runs too, and I have only seen it on Windows.
  • For 2: the mouse coming onto the island during an announcement, and a permission request arriving during one. Both are handled in code (the first has a state machine test); I have not watched either happen.
  • For 2: prefers-reduced-motion. The stylesheet does not handle it anywhere yet, and this does not start.

Related

#83 (open, from before 0.2.0) adds a Spotify pill to Windows with its own views, and is where the announcement comes from. This one adds no view: a Windows source under #372's page, and that one behaviour.

🤖 Generated with Claude Code

shakibbinkabir and others added 2 commits October 9, 2026 05:58
The Linux pill reads Spotify over MPRIS. Windows has System Media Transport
Controls: every player reports its track to the system and takes play, pause,
next… through it. The pill now reads Spotify's session there, behind the same
five functions the Linux client implements, so the page is the Linux one.

- No polling: one thread sleeps on a channel while the pill is declared, and
  Windows wakes it when a session comes or goes or Spotify's changes. Spotify
  updates its timeline as it plays; only a jump counts as news, so a playing
  track sends the island nothing.
- Spotify only: the session is picked by its app id (the Store build and the
  one from spotify.com). A browser playing a video is not shown.
- The cover comes with the session, so nothing is fetched.
- The session has no volume: the slider moves Spotify's level in the Windows
  volume mixer.
- Shuffle and repeat are left out of the card on Windows. Spotify answers that
  it changed them and changes nothing, so `modes` in the state tells the card.
- The session carries no Spotify URI: tracks get a `spotify:local:` id, so
  there is no page to open and an ad is not recognised as one.
- "Open Spotify" follows a `spotify:` link, which starts it or brings it
  forward; without Spotify, its download page.

The pill is now offered on both systems (`support: "yes"`), and the
Linux-only support kind this pill had introduced goes away with its last user.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When Spotify moves on to another song, the island opens on Spotify's card for
three seconds and folds back, and the pill that was in front gets its place
again. A light in Mochi's colour breathes behind him, the cover glows and a
sheen crosses it, so it reads as news and not as an island that opened by
accident. No sound: music is playing.

The idea and its look are Edurique's, from Louis-CFM#83. It is rebuilt here on the card
and the state machine as they are today, and nothing of the card changes
outside those three seconds.

- Off by default (Settings → Integrations → Spotify → Announce new songs).
  The island never opens on its own for news that asks nothing, and the Mac
  does not do this, so it is something to turn on.
- A new song is one that starts after another: not the first heard since
  Spotify started, not the same one going on after a pause or a seek, never
  an ad. Windows names a track before it says it plays; it is announced once
  it does.
- Never over an island that is open, under the mouse, pinned or waiting for
  an answer. The mouse coming, a key or an alert makes it an open island like
  any other: the auto-close delay applies again, the usual sounds come back,
  and the front stays where the user sees it.
- The state machine gains `glance(seconds)`: open, and fold after its own
  delay instead of the auto-close preference. It is the hover-open's short
  countdown with another length, and ends the same way (`userInteracted`).
- The light takes the colour of the pill's Mochi, so a colour picked in
  Settings → Active pills is the light's too.
- Songs skipped through carry one announcement on, and the front still goes
  back to the pill that had it before the first.

Co-authored-by: Edurique <225876024+Edurique@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@shakibbinkabir shakibbinkabir changed the title Windows: the Spotify pill, through the system's media session Windows: the Spotify pill through the system's media session, and an opt-in new-song announcement Oct 9, 2026
PythonTilk added a commit to PythonTilk/coucou that referenced this pull request Oct 9, 2026
…opt-in new-song announcement

Taken from shakibbinkabir:spotify-windows while it is still open upstream.
The pill reads Spotify through the system's media session; announcing a new
song is off by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PythonTilk added a commit to PythonTilk/coucou that referenced this pull request Oct 9, 2026
…(opt-in)

Taken from shakibbinkabir's branch while it is still open upstream; its first
two commits are Louis-CFM#374, already here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown
Owner

Thank you for this! Several PRs added the Spotify pill on Windows through the system media session; #493 was merged (in #661) as the one to keep, so I'm closing this one as a duplicate. Your opt-in new-song announcement isn't in #493: feel free to send it as a small follow-up PR on top of it.


Generated by Claude Code

@Louis-CFM Louis-CFM closed this Oct 14, 2026
PythonTilk added a commit to PythonTilk/coucou that referenced this pull request Oct 18, 2026
…s on top

From upstream: the Coucou window with Flow dictation, the Notetaker and
« OK Coucou », its Spotify pill, and settings as pages in that window.
Taken over this build's own versions: « OK Coucou » replaces the hotkey
voice (removed just before), upstream's Spotify replaces Louis-CFM#374 and Louis-CFM#412
(the beat dance goes with them), and the settings pages replace the
folding groups. Kept and moved onto the pages: Updates (General), the
chat provider picker (Chat), Phone alerts and Mail (Integrations).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants