Elke collectie houdt zijn eigen plek #72

Merged
roelof merged 1 commit from positie-per-collectie into main 2026-08-06 15:31:04 +02:00
Owner

Closes #70

Er was één afspeelrij per luisteraar, en daarmee één plek in de hele bibliotheek. Een collectie is een andere bibliotheek en geen volgende pagina van deze — het verlaten ervan stopt de muziek — dus met één rij landde terugkomen waar de collectie die je intussen bezocht had gebleven was.

PlaybackEntity is nu één rij per luisteraar per collectie; de twee id's samen zijn de sleutel. UpdatedUtc krijgt er een taak bij: de nieuwste rij is waar de luisteraar het laatst was, en dat is waar een client die koud opstart in hervat.

  • GET /api/playback?collection={id} vraagt naar die ene collectie; zonder vraag naar de laatste van allemaal.
  • Bij het opslaan bepaalt de server in welke collectie een plek hoort, uit de track. Een client die dat mocht zeggen zou in een collectie kunnen schrijven waar de track niet in zit.
  • Een track zonder collectie houdt geen plek: die staat in geen enkele lijst die een client toont, dus er is nergens naar te hervatten.

De migratie vult bij in plaats van te defaulten

Wat EF genereerde zette de kolom op NOT NULL DEFAULT 0 en legde er dan een foreign key op naar collections — wat geen bestaande rij kan waarmaken. De eerste luisteraar met een bewaarde positie had de hele migratie omgetrokken, en die is er live.

Hij voegt de kolom nullable toe, vult hem uit de track van elke rij, gooit weg wat overblijft, en haalt hem dan pas aan. Nagelopen tegen een database met beide soorten rijen: de bestaande positie overleefde mét de juiste collectie, de positie op een track zonder collectie verdween.

Klaarzetten, niet afspelen

In alle drie de spelers hetzelfde. Een collectie wordt net zo vaak aangeklikt om te bladeren als om te luisteren, en muziek die bij elke klik aangaat is erger dan de stilte die het vervangt. Eén druk op play gaat verder.

De desktopspeler kan dat nu doordat MpvPlaybackService.Play de pause-eigenschap expliciet zet — om dezelfde reden als start: hij blijft staan als hij eenmaal geschreven is. ShowAsync is wat ResumeAsync en CueAsync delen, namelijk alles behalve of het begint.

Nagemeten

Testserver met twee collecties, via de API:

Testalbums Testlijst laatste
nog niets afgespeeld 204
na spelen in Testalbums op 42s track 4, 42s 204 track 4
daarna in Testlijst op 7s track 4, 42s track 14, 7s track 14

De middelste kolom is het hele punt: Testalbums houdt zijn eigen plek terwijl er in Testlijst gespeeld wordt.

De desktopspeler is erop gestart en hervatte netjes in de nieuwste collectie, spelend. De wissel zelf is niet met de hand aangeklikt — onder Wayland is er geen invoergereedschap — dus die weg is op API-niveau en op code geverifieerd, niet door te klikken. Android: tsc en eslint schoon, niet op een toestel gedraaid.

Closes #70 Er was één afspeelrij per luisteraar, en daarmee één plek in de hele bibliotheek. Een collectie is een andere bibliotheek en geen volgende pagina van deze — het verlaten ervan stopt de muziek — dus met één rij landde terugkomen waar de collectie die je intussen bezocht had gebleven was. `PlaybackEntity` is nu **één rij per luisteraar per collectie**; de twee id's samen zijn de sleutel. `UpdatedUtc` krijgt er een taak bij: de nieuwste rij is waar de luisteraar het laatst was, en dat is waar een client die koud opstart in hervat. - `GET /api/playback?collection={id}` vraagt naar die ene collectie; zonder vraag naar de laatste van allemaal. - Bij het opslaan bepaalt de **server** in welke collectie een plek hoort, uit de track. Een client die dat mocht zeggen zou in een collectie kunnen schrijven waar de track niet in zit. - Een track zonder collectie houdt geen plek: die staat in geen enkele lijst die een client toont, dus er is nergens naar te hervatten. ## De migratie vult bij in plaats van te defaulten Wat EF genereerde zette de kolom op `NOT NULL DEFAULT 0` en legde er dan een foreign key op naar `collections` — wat **geen bestaande rij kan waarmaken**. De eerste luisteraar met een bewaarde positie had de hele migratie omgetrokken, en die is er live. Hij voegt de kolom nullable toe, vult hem uit de track van elke rij, gooit weg wat overblijft, en haalt hem dan pas aan. Nagelopen tegen een database met beide soorten rijen: de bestaande positie overleefde mét de juiste collectie, de positie op een track zonder collectie verdween. ## Klaarzetten, niet afspelen In alle drie de spelers hetzelfde. Een collectie wordt net zo vaak aangeklikt om te bladeren als om te luisteren, en muziek die bij elke klik aangaat is erger dan de stilte die het vervangt. Eén druk op play gaat verder. De desktopspeler kan dat nu doordat `MpvPlaybackService.Play` de `pause`-eigenschap expliciet zet — om dezelfde reden als `start`: hij blijft staan als hij eenmaal geschreven is. `ShowAsync` is wat `ResumeAsync` en `CueAsync` delen, namelijk alles behalve of het begint. ## Nagemeten Testserver met twee collecties, via de API: | | Testalbums | Testlijst | laatste | |---|---|---|---| | nog niets afgespeeld | — | — | 204 | | na spelen in Testalbums op 42s | track 4, 42s | 204 | track 4 | | daarna in Testlijst op 7s | **track 4, 42s** | track 14, 7s | track 14 | De middelste kolom is het hele punt: Testalbums houdt zijn eigen plek terwijl er in Testlijst gespeeld wordt. De desktopspeler is erop gestart en hervatte netjes in de nieuwste collectie, spelend. **De wissel zelf is niet met de hand aangeklikt** — onder Wayland is er geen invoergereedschap — dus die weg is op API-niveau en op code geverifieerd, niet door te klikken. Android: `tsc` en `eslint` schoon, niet op een toestel gedraaid.
Er was één afspeelrij per luisteraar, en daarmee één plek in de hele
bibliotheek. Een collectie is een andere bibliotheek en geen volgende pagina van
deze — het verlaten ervan stopt de muziek — dus met één rij landde terugkomen
waar de collectie die je intussen bezocht had gebleven was.

PlaybackEntity is nu één rij per luisteraar per collectie; de twee id's samen
zijn de sleutel. UpdatedUtc krijgt er een taak bij: de nieuwste rij van een
luisteraar is waar hij het laatst was, en dat is waar een client die koud
opstart in hervat.

GET /api/playback?collection={id} vraagt naar die ene collectie, zonder vraag
naar de laatste van allemaal. Bij het opslaan bepaalt de server zelf in welke
collectie een plek hoort, uit de track: een client die dat mocht zeggen zou in
een collectie kunnen schrijven waar de track niet in zit. Een track zonder
collectie houdt geen plek — die staat in geen enkele lijst die een client toont,
dus er zou nergens naar te hervatten zijn.

De migratie vult bij in plaats van een standaardwaarde te zetten. Wat EF
genereerde zette de kolom op NOT NULL DEFAULT 0 en legde er dan een foreign key
op, wat geen bestaande rij kan waarmaken — de eerste luisteraar met een bewaarde
positie had de hele migratie omgetrokken. Hij voegt de kolom nullable toe, vult
hem uit de track van elke rij, gooit weg wat overblijft en haalt hem dan pas
aan. Nagelopen tegen een database met allebei de soorten rijen erin.

In alle drie de spelers geldt hetzelfde: bij terugkeer in een collectie wordt de
bewaarde track klaargezet, niet afgespeeld. Een collectie wordt net zo vaak
aangeklikt om te bladeren als om te luisteren, en muziek die bij elke klik
aangaat is erger dan de stilte die het vervangt. Eén druk op play gaat verder.
De desktopspeler kan dat nu doordat MpvPlaybackService.Play de pause-eigenschap
expliciet zet, om dezelfde reden als start: hij blijft staan als hij eenmaal
geschreven is.

Nagemeten tegen een testserver met twee collecties:

  nog niets afgespeeld                          204
  na spelen in Testalbums op 42s
    in Testalbums    track 4, positie 42
    in Testlijst     204
    laatste          track 4
  daarna in Testlijst op 7s
    in Testalbums    track 4, positie 42   <- eigen plek behouden
    in Testlijst     track 14, positie 7
    laatste          track 14

Closes #70

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
roelof merged commit 980d1e6120 into main 2026-08-06 15:31:04 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
KavalirOS/RockHeaven!72
No description provided.