Changeset d8f7d9c in Klonkt for src/services/PlaylistService.js
- Timestamp:
- 08/16/2026 01:44:46 PM (3 weeks ago)
- Branches:
- main
- Children:
- d68ee3a
- Parents:
- 21257e4
- File:
-
- 1 edited
-
src/services/PlaylistService.js (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/PlaylistService.js
r21257e4 rd8f7d9c 15 15 import { v4 as uuid } from 'uuid'; 16 16 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 */ 30 function 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. */ 39 function 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 17 44 class PlaylistService { 18 45 … … 52 79 const rows = db.prepare(` 53 80 SELECT p.id, p.title, p.artist, p.year, p.cover_url, p.kind, 81 p.release_date, p.mb_release_id, 54 82 p.created_at, p.updated_at, 55 83 (SELECT COUNT(*) FROM playlist_tracks WHERE playlist_id = p.id) AS track_count … … 65 93 cover: r.cover_url || '', 66 94 kind: r.kind || 'album', 95 release_date: r.release_date || '', 96 mb_release_id: r.mb_release_id || '', 67 97 track_count: r.track_count, 68 98 created_at: r.created_at, … … 86 116 if (!id) return null; 87 117 const p = db.prepare(` 88 SELECT id, title, artist, year, cover_url, kind, created_at, updated_at118 SELECT id, title, artist, year, cover_url, kind, release_date, mb_release_id, created_at, updated_at 89 119 FROM playlists WHERE site_id = ? AND id = ? 90 120 `).get(siteId, id); … … 125 155 cover: p.cover_url || fallbackCover, 126 156 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 || ''), 127 162 tracks: mappedTracks, 128 163 }; … … 141 176 const kind = data.kind === 'playlist' ? 'playlist' : 'album'; 142 177 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 143 188 const tx = db.transaction(() => { 144 189 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 147 192 `).run( 148 193 id, siteId, title, … … 150 195 Number.isFinite(+data.year) && +data.year > 0 ? +data.year : null, 151 196 String(data.cover || '').trim() || null, 152 kind, now, now,197 kind, releaseDate, mbRelease, now, now, 153 198 ); 154 199 this._writeTracks(id, siteId, data.tracks); … … 171 216 if (!id) return false; 172 217 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 = ?' 174 219 ).get(siteId, id); 175 220 if (!existing) return false; … … 177 222 const fields = []; 178 223 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'); 179 229 if (Object.prototype.hasOwnProperty.call(data, 'title')) { 180 230 const v = String(data.title || '').trim(); … … 193 243 } 194 244 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 } 196 262 } 197 263 fields.push('updated_at = ?'); values.push(new Date().toISOString());
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)