Changeset e679bce in Klonkt for src/assets/js/audio-player.js
- Timestamp:
- 08/22/2026 09:54:51 AM (3 weeks ago)
- Branches:
- main
- Children:
- 8bb3b09
- Parents:
- 16fd4fe
- File:
-
- 1 edited
-
src/assets/js/audio-player.js (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/assets/js/audio-player.js
r16fd4fe re679bce 158 158 let isPlaying = false; 159 159 let albumName = ''; 160 // BANDMODUS (Robins eis, 21-8): een mixtape is EEN object, geen wachtrij met 161 // nummers. De MSE-keten hieronder maakt van een wachtrij toch al een 162 // doorlopende tijdlijn -- "een trackwissel is een positie, geen omschakeling" 163 // -- dus een bandje is precies die tijdlijn, alleen anders getoond en anders 164 // bediend: je ziet de titel van het bandje, de teller loopt over het geheel, 165 // en spoelen gaat in seconden in plaats van per nummer. 166 let tapeMode = false; 160 167 // Playback pipeline. We fetch each track's bytes ourselves (X-Audio-Player 161 168 // gate; no plain media URL is ever exposed to the page) and feed them to the … … 457 464 // Current position/duration in TRACK coordinates (the MSE timeline is the 458 465 // whole chain; the UI always shows the single playing track). 459 function displayTimes() { 466 // De positie BINNEN het huidige nummer. Apart van displayTimes(), want die 467 // geeft in bandmodus de teller over de hele band -- en het opslaan van de 468 // sessie heeft juist de trackpositie nodig: bij het herstellen begint de 469 // keten opnieuw en start dit nummer weer op nul. 470 function trackTijd() { 460 471 if (useMse() && chain.length) { 461 472 const seg = currentSegment(); … … 463 474 } 464 475 return { cur: audio.currentTime || 0, dur: audio.duration }; 476 } 477 478 function displayTimes() { 479 // Een bandje heeft een teller, geen nummerpositie: hij telt door over de 480 // kant heen. Dat is letterlijk de ketentijdlijn, dus hier juist NIET 481 // terugrekenen naar trackcoordinaten. 482 if (tapeMode && useMse() && chain.length) { 483 return { cur: audio.currentTime || 0, dur: chain[chain.length - 1].end }; 484 } 485 return trackTijd(); 465 486 } 466 487 … … 505 526 // session metadata. Called from loadTrack AND from the gapless boundary-cross. 506 527 function updateTrackChrome(t) { 507 titleEl.textContent = t.title || 'Untitled'; 508 artistEl.textContent = t.artist || ''; 509 sheetTitle.textContent = t.title || 'Untitled'; 510 sheetArtist.textContent = t.artist || ''; 528 // In bandmodus staat het BANDJE op de speler. Wat er op dit moment klinkt 529 // staat eronder, zoals een cassette een titel op het label heeft en de 530 // nummers op het doosje. 531 const hoofd = tapeMode ? (albumName || 'Mixtape') : (t.title || 'Untitled'); 532 const onder = tapeMode ? (t.title || '') : (t.artist || ''); 533 titleEl.textContent = hoofd; 534 artistEl.textContent = onder; 535 sheetTitle.textContent = hoofd; 536 sheetArtist.textContent = onder; 511 537 sheetAlbum.textContent = albumName || ''; 512 538 setCoverImage(cover, t.cover); … … 579 605 queue = Array.isArray(tracks) ? tracks.slice() : []; 580 606 albumName = (opts && opts.albumName) || ''; 607 tapeMode = !!(opts && opts.asTape); 581 608 if (!queue.length) return; 582 609 loadTrack(typeof startIdx === 'number' ? Math.max(0, Math.min(startIdx, queue.length - 1)) : 0, true); … … 629 656 queue = []; 630 657 albumName = ''; 658 tapeMode = false; 631 659 loadSeq++; // cancel any in-flight load 632 660 dropPreload(); … … 1010 1038 // would leave dead buttons (flag baked into the snapshot, listener gone). One 1011 1039 // delegated listener works regardless of how many times the DOM is (re)swapped. 1040 // WELKE KNOPPEN DEZE SPELER BEDIENT. Let op: dit is een LIJST MET NAMEN, geen 1041 // regel over data-attributen. Een nieuwe knop die keurig data-pcms-track-url 1042 // en data-pcms-album-id draagt doet dus niets zolang hij hier niet bij staat. 1043 // Precies daar liep de cassetteknop op vast (21-8): de opmaak klopte, de 1044 // gegevens klopten, en er gebeurde niets. 1012 1045 const PLAY_SELECTOR = 1013 '.post-audio-track .pat-play, .post-album-tracks .pat-row, .post-album-cover-btn, .post-album-playall ';1046 '.post-audio-track .pat-play, .post-album-tracks .pat-row, .post-album-cover-btn, .post-album-playall, .tape-btn--play'; 1014 1047 document.body.addEventListener('click', (e) => { 1015 1048 const btn = e.target.closest(PLAY_SELECTOR); … … 1038 1071 // (cover-btn and playall both want to start from the beginning). 1039 1072 const startIdx = trackUrl ? tracks.findIndex(t => t.url === trackUrl) : 0; 1040 setQueue(tracks, startIdx >= 0 ? startIdx : 0, { albumName: album.dataset.pcmsAlbumTitle || '' }); 1073 // Een mixtape gaat als EEN object de speler in: de titel van het bandje 1074 // op de speler, de teller over de hele band, en spoelen in seconden. 1075 // De soort staat al op het blok (data-pcms-album-kind), dus hier is het 1076 // een doorgeefje en geen tweede plek die iets afleidt. 1077 setQueue(tracks, startIdx >= 0 ? startIdx : 0, { 1078 albumName: album.dataset.pcmsAlbumTitle || '', 1079 asTape: album.dataset.pcmsAlbumKind === 'mixtape', 1080 }); 1041 1081 } catch(err) { console.error('[pcms-audio] bad album JSON', err, album.dataset.pcmsAlbum); } 1042 1082 } else if (trackData) { … … 1092 1132 // 9. Public API 1093 1133 // ============================================================ 1134 /** 1135 * SPOELEN, in seconden over de hele band. 1136 * 1137 * Op de MSE-motor is dit precies wat een cassette doet: `audio.currentTime` 1138 * IS de tijdlijn van de hele keten, dus over een nummergrens heen spoelen is 1139 * gewoon doortellen. Geen trackwissel, geen nieuwe afspeelsessie. 1140 * 1141 * Op de blob-motor (iOS Safari, geen MSE) bestaat die doorlopende tijdlijn 1142 * niet: daar is elk nummer een eigen bron. Spoelen loopt daar dus tot de rand 1143 * van het huidige nummer en stapt dan naar de buur. Grover, maar het is 1144 * eerlijker dan doen alsof de band doorloopt terwijl hij dat niet doet. 1145 */ 1146 function seekBy(seconden) { 1147 const d = Number(seconden) || 0; 1148 if (!d || !audio) return; 1149 if (useMse() && chain.length) { 1150 const eind = chain[chain.length - 1].end; 1151 const doel = Math.max(0, Math.min((audio.currentTime || 0) + d, Math.max(0, eind - 0.25))); 1152 try { audio.currentTime = doel; } catch (e) { /* buffer nog niet zover */ } 1153 updatePositionState(); 1154 return; 1155 } 1156 // Blob-motor: binnen het nummer blijven, en anders naar de buur. 1157 const duur = audio.duration || 0; 1158 const nu = audio.currentTime || 0; 1159 if (duur && nu + d >= duur) { next(); return; } 1160 if (nu + d < 0) { prev(); return; } 1161 try { audio.currentTime = Math.max(0, nu + d); } catch (e) {} 1162 } 1163 1164 /** Waar staat de teller, over het hele bandje. */ 1165 function tapeTijden() { return displayTimes(); } 1166 1094 1167 window.pcmsAudioPlayer = { 1095 setQueue, play, pause, next, prev, close, openSheet, closeSheet, 1168 setQueue, play, pause, next, prev, close, openSheet, closeSheet, seekBy, tapeTijden, 1169 isTape: () => tapeMode, 1096 1170 isPlaying: () => isPlaying, 1097 1171 currentTrack: () => queue[currentIndex] || null, … … 1113 1187 if (!queue.length) { sessionStorage.removeItem(PLAYER_STATE_KEY); return; } 1114 1188 sessionStorage.setItem(PLAYER_STATE_KEY, JSON.stringify({ 1115 queue, currentIndex, albumName, 1189 queue, currentIndex, albumName, tapeMode, 1116 1190 // In-TRACK position (the MSE timeline spans the whole chain; a restore 1117 1191 // starts a fresh chain where this track begins at 0). 1118 time: displayTimes().cur || 0,1192 time: trackTijd().cur || 0, 1119 1193 playing: !!audio.src && !audio.paused, 1120 1194 })); … … 1140 1214 queue = s.queue; 1141 1215 albumName = s.albumName || ''; 1216 tapeMode = !!s.tapeMode; 1142 1217 pendingSeek = s.time || 0; 1143 1218 const idx = Math.max(0, Math.min(s.currentIndex || 0, queue.length - 1));
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)