Changeset d727e92 in Klonkt for src/services


Ignore:
Timestamp:
06/20/2026 05:37:42 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
a66f691
Parents:
183875b
Message:

feat(audio): tracks without audio (link-only) — list with open-in links, no upload

You can now add a "Track without audio" in Admin → Audio (button) — only
title/artist + the Spotify/YouTube/SoundCloud links, no file. Such tracks
appear in albums & playlists (and standalone track embeds) in the list
with the open-in icons but WITHOUT a play button, and stay outside the
playback queue (which matches on URL). Lookups (posts album/single +
PlaylistService) no longer filter out fileless tracks. New route POST
/admin/audio/create-link. buster audio.css?v=9.

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

Location:
src/services
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/services/AudioEmbedService.js

    r183875b rd727e92  
    270270    return html.replace(/\[\[track:([A-Za-z0-9_-]+)\]\]/g, (match, id) => {
    271271      const t = trackLookup(id);
    272       if (!t || !t.url) return match;
     272      if (!t) return match;
     273      const titleH0 = this.escape(t.title || 'Untitled');
     274      const artistH0 = this.escape(t.artist || '');
     275      const creditBits0 = [this.escape(t.credit || ''), this.escape(t.license || '')].filter(Boolean).join(' · ');
     276      // Link-only track (geen audiobestand): geen afspeelknop, wel info + open-in.
     277      if (!t.url) {
     278        return `<div class="post-audio-track post-audio-track--static" id="track-${id}">
     279  <span class="pat-noplay" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg></span>
     280  <div class="pat-info">
     281    <div class="pat-title">${titleH0}</div>
     282    ${artistH0 ? `<div class="pat-artist">${artistH0}</div>` : ''}
     283    ${creditBits0 ? `<div class="pat-credit">${creditBits0}</div>` : ''}
     284  </div>
     285  ${this.openInLinks(t)}
     286</div>`;
     287      }
    273288      const trackJson = JSON.stringify({
    274289        id,
     
    318333      // Stable DOM id for this rendering — used as data-pcms-album-id on tracks
    319334      const albumDomId = 'album-' + Math.random().toString(36).slice(2, 10);
    320       const albumJson = JSON.stringify(album.tracks)
     335      // Alleen afspeelbare tracks (met url) in de queue; link-only tracks staan
     336      // wel in de lijst maar niet in de afspeel-JSON.
     337      const albumJson = JSON.stringify(album.tracks.filter((t) => t.url))
    321338        .replace(/&/g, '&amp;').replace(/'/g, '&#39;').replace(/</g, '&lt;');
    322339      const titleH = this.escape(album.title || name);
     
    327344        const tTitle = this.escape(t.title || ('Track ' + (i + 1)));
    328345        const tArtist = this.escape(t.artist || '');
     346        // Link-only track: geen afspeelknop, wel nummer + info + open-in.
     347        if (!t.url) {
     348          return `    <li class="post-audio-track post-audio-track--static"${t.id ? ` id="track-${t.id}"` : ''}>
     349      <span class="pat-track-num">${i + 1}.</span>
     350      <div class="pat-info">
     351        <div class="pat-title">${tTitle}</div>
     352        ${tArtist && tArtist !== artistH ? `<div class="pat-artist">${tArtist}</div>` : ''}
     353      </div>
     354      ${this.openInLinks(t)}
     355    </li>`;
     356        }
    329357        const tUrl = this.escape(t.url);
    330358        return `    <li class="post-audio-track"${t.id ? ` id="track-${t.id}" data-pcms-track-id="${t.id}"` : ''} data-pcms-track-url="${tUrl}" data-pcms-album-id="${albumDomId}">
     
    404432      // Audio-player.js reads data-pcms-album for queue. Same shape as
    405433      // embedAlbumShortcodes — keep both in sync.
    406       const tracksData = pl.tracks.map(t => ({
     434      // Alleen afspeelbare tracks in de queue; link-only tracks staan wel in de
     435      // lijst maar niet in de afspeel-JSON.
     436      const tracksData = pl.tracks.filter(t => t.url).map(t => ({
    407437        id:     t.id,
    408438        url:    t.url,
     
    426456      }
    427457      const metaLine = this.escape(metaParts.join(' · '));
    428       const firstUrl = this.escape(pl.tracks[0].url);
     458      const firstUrl = this.escape((pl.tracks.find(t => t.url) || {}).url || '');
    429459
    430460      // Track items — playlist-kind shows per-track cover thumbs, album-kind shows numbers
     
    445475          : `<span class="pat-num">${i + 1}</span>`;
    446476
     477        // Link-only track: geen klikbare afspeel-rij (statische div), wel open-in.
     478        if (!t.url) {
     479          return `    <li class="post-album-track-compact post-album-track-compact--static"${t.id ? ` id="track-${t.id}"` : ''}>
     480      <div class="pat-row pat-static">
     481        ${leader}
     482        <span class="pat-meta">
     483          <span class="pat-title">${tTitleH}</span>
     484          ${showArtist ? `<span class="pat-artist">${tArtistH}</span>` : ''}
     485        </span>
     486        ${durHtml}
     487      </div>
     488      ${this.openInLinks(t)}
     489    </li>`;
     490        }
    447491        const trackBase = String(t.url).split('?')[0];
    448492        return `    <li class="post-album-track-compact"${t.id ? ` id="track-${t.id}" data-pcms-track-id="${t.id}"` : ''}>
  • src/services/PlaylistService.js

    r183875b rd727e92  
    104104
    105105    const mappedTracks = tracks
    106       .filter(t => t.filename)  // skip orphaned references
     106      // Link-only tracks (geen media-bestand) blijven in de lijst staan met url ''.
    107107      .map(t => ({
    108108        id: t.id,
     
    114114        link_youtube: t.link_youtube || '',
    115115        link_soundcloud: t.link_soundcloud || '',
    116         url: urlFor ? urlFor(t.filename) : null,
     116        url: (t.filename && urlFor) ? urlFor(t.filename) : '',
    117117      }));
    118118    // Geen eigen cover? Val terug op de eerste track-cover, zodat de kaart niet leeg is.
Note: See TracChangeset for help on using the changeset viewer.