Changeset d8f7d9c in Klonkt for src/services/PlaylistService.js


Ignore:
Timestamp:
08/16/2026 01:44:46 PM (3 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
d68ee3a
Parents:
21257e4
Message:

Playlists: uitgavedatum en MusicBrainz release-id op een album

Stap 1 van shaer-756s. Het album bestaat al als ding -- een playlist met
kind='album', met eigen id, titel, artiest, jaar, hoes en een eigen
AP-collectie. Wat ontbrak om het als Album uit te geven zijn twee velden.

release_date en niet year: die kolom blijft en wordt gewoon getoond,
maar hun AlbumSerializer leest released als een DateField. Een jaartal
als 2024-01-01 versturen is een dag verzinnen, en dat is precies wat we
bij artiesten en albums niet doen. Volledige datum of niets -- ook
2024-02-31 valt af, want Date rolt die stil door naar 2 maart en dan
bewaren we iets anders dan er ingetypt is.

mb_release_id is de tegenhanger van sites.mb_artist_id: dezelfde
verwijzing naar MusicBrainz, een niveau lager.

ALLEEN BIJ kind='album', en dat wordt in PlaylistService afgedwongen en
niet alleen in het scherm. De API ligt open -- de post-editor gebruikt
hem ook -- en een scherm is geen bewaking. Omschakelen naar afspeellijst
maakt de velden ALTIJD leeg, ook als de aanroeper er niets over zei:
anders houdt een album dat je tot mixtape ombouwt zijn uitgavedatum, en
duikt die weer op zodra iemand hem terugzet. Het leespad geeft ze ook
niet door bij een afspeellijst, zodat een oude rij niet alsnog lekt.

In de editor staan de velden onder Type en verdwijnen ze als je naar
playlist schakelt. Daar hoorde een CSS-regel bij: .pl-field is display:
flex en dat wint van het hidden-attribuut -- zonder .pl-field[hidden]
{ display: none } bleven ze gewoon staan.

Co-Authored-By: Claude Opus 5 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/PlaylistService.js

    r21257e4 rd8f7d9c  
    1515import { v4 as uuid } from 'uuid';
    1616
     17/**
     18 * Een volledige datum of niets (shaer-756s).
     19 *
     20 * STRIKT, en dat is de hele functie. `year` bestaat al en blijft; dit veld
     21 * bestaat juist omdat een jaartal geen uitgavedatum is. Zou hij "2024"
     22 * doorlaten en er 2024-01-01 van maken, dan stond er straks een dag op de
     23 * federatie die niemand ooit heeft ingevoerd -- en dan hadden we het veld net
     24 * zo goed niet kunnen toevoegen.
     25 *
     26 * Ook 2024-02-31 valt af: dat is geen strengheid om de strengheid, Date rolt
     27 * hem stilletjes door naar 2 maart en dan slaan we iets anders op dan er
     28 * ingetypt is.
     29 */
     30function normDatum(v) {
     31  const s = String(v == null ? '' : v).trim();
     32  if (!s) return null;
     33  if (!/^\d{4}-\d{2}-\d{2}$/.test(s)) return null;
     34  const d = new Date(`${s}T00:00:00Z`);
     35  return Number.isNaN(d.getTime()) || d.toISOString().slice(0, 10) !== s ? null : s;
     36}
     37
     38/** Een MusicBrainz-id of niets. Zelfde vorm als sites.mb_artist_id. */
     39function normMbid(v) {
     40  const s = String(v == null ? '' : v).trim().toLowerCase();
     41  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(s) ? s : null;
     42}
     43
    1744class PlaylistService {
    1845
     
    5279    const rows = db.prepare(`
    5380      SELECT p.id, p.title, p.artist, p.year, p.cover_url, p.kind,
     81             p.release_date, p.mb_release_id,
    5482             p.created_at, p.updated_at,
    5583             (SELECT COUNT(*) FROM playlist_tracks WHERE playlist_id = p.id) AS track_count
     
    6593      cover: r.cover_url || '',
    6694      kind: r.kind || 'album',
     95      release_date: r.release_date || '',
     96      mb_release_id: r.mb_release_id || '',
    6797      track_count: r.track_count,
    6898      created_at: r.created_at,
     
    86116    if (!id) return null;
    87117    const p = db.prepare(`
    88       SELECT id, title, artist, year, cover_url, kind, created_at, updated_at
     118      SELECT id, title, artist, year, cover_url, kind, release_date, mb_release_id, created_at, updated_at
    89119      FROM playlists WHERE site_id = ? AND id = ?
    90120    `).get(siteId, id);
     
    125155      cover: p.cover_url || fallbackCover,
    126156      kind: (p.kind === 'playlist') ? 'playlist' : 'album',
     157      // Leeg als het een afspeellijst is -- de opslag houdt ze daar al leeg,
     158      // maar dit is de plek waar de editor leest en die mag niet afhangen van
     159      // wat er toevallig in de kolom stond.
     160      release_date: p.kind === 'playlist' ? '' : (p.release_date || ''),
     161      mb_release_id: p.kind === 'playlist' ? '' : (p.mb_release_id || ''),
    127162      tracks: mappedTracks,
    128163    };
     
    141176    const kind = data.kind === 'playlist' ? 'playlist' : 'album';
    142177
     178    // Alleen een UITGAVE draagt deze twee. Een afspeellijst heeft geen
     179    // uitgavedatum en geen release-id, en dat onderscheid is precies wat de
     180    // keuze album/playlist betekent (shaer-cyg). Het afdwingen gebeurt HIER en
     181    // niet alleen in het scherm: een scherm kun je omzeilen -- de API ligt open
     182    // voor de post-editor -- en dan staat er stille rommel op een mixtape die
     183    // later als Album de deur uit gaat.
     184    const uitgave = kind === 'album';
     185    const releaseDate = uitgave ? normDatum(data.release_date) : null;
     186    const mbRelease = uitgave ? normMbid(data.mb_release_id) : null;
     187
    143188    const tx = db.transaction(() => {
    144189      db.prepare(`
    145         INSERT INTO playlists (id, site_id, title, artist, year, cover_url, kind, created_at, updated_at)
    146         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
     190        INSERT INTO playlists (id, site_id, title, artist, year, cover_url, kind, release_date, mb_release_id, created_at, updated_at)
     191        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    147192      `).run(
    148193        id, siteId, title,
     
    150195        Number.isFinite(+data.year) && +data.year > 0 ? +data.year : null,
    151196        String(data.cover || '').trim() || null,
    152         kind, now, now,
     197        kind, releaseDate, mbRelease, now, now,
    153198      );
    154199      this._writeTracks(id, siteId, data.tracks);
     
    171216    if (!id) return false;
    172217    const existing = db.prepare(
    173       'SELECT id FROM playlists WHERE site_id = ? AND id = ?'
     218      'SELECT id, kind FROM playlists WHERE site_id = ? AND id = ?'
    174219    ).get(siteId, id);
    175220    if (!existing) return false;
     
    177222    const fields = [];
    178223    const values = [];
     224    // Wat wordt het NA deze wijziging? `kind` hoeft niet in data te staan, dus
     225    // val terug op wat er ligt.
     226    const nieuwKind = Object.prototype.hasOwnProperty.call(data, 'kind')
     227      ? (data.kind === 'playlist' ? 'playlist' : 'album')
     228      : (existing.kind || 'album');
    179229    if (Object.prototype.hasOwnProperty.call(data, 'title')) {
    180230      const v = String(data.title || '').trim();
     
    193243    }
    194244    if (Object.prototype.hasOwnProperty.call(data, 'kind')) {
    195       fields.push('kind = ?'); values.push(data.kind === 'playlist' ? 'playlist' : 'album');
     245      fields.push('kind = ?'); values.push(nieuwKind);
     246    }
     247    // De uitgavevelden. Wordt dit een afspeellijst, dan gaan ze ALTIJD leeg --
     248    // ook als de aanroeper er niets over zei. Anders houdt een album dat je tot
     249    // mixtape ombouwt zijn uitgavedatum en zijn release-id, en die duiken dan
     250    // weer op zodra iemand hem terugzet. Een veld dat niet meer mag bestaan
     251    // hoort weg te zijn, niet te wachten.
     252    if (nieuwKind !== 'album') {
     253      fields.push('release_date = ?'); values.push(null);
     254      fields.push('mb_release_id = ?'); values.push(null);
     255    } else {
     256      if (Object.prototype.hasOwnProperty.call(data, 'release_date')) {
     257        fields.push('release_date = ?'); values.push(normDatum(data.release_date));
     258      }
     259      if (Object.prototype.hasOwnProperty.call(data, 'mb_release_id')) {
     260        fields.push('mb_release_id = ?'); values.push(normMbid(data.mb_release_id));
     261      }
    196262    }
    197263    fields.push('updated_at = ?'); values.push(new Date().toISOString());
Note: See TracChangeset for help on using the changeset viewer.