Changeset bbf9d1a in Klonkt for src/views/pages/admin-audio.ejs
- Timestamp:
- 06/21/2026 02:32:39 PM (3 months ago)
- Branches:
- main
- Children:
- 4885eab
- Parents:
- 929d98d
- File:
-
- 1 edited
-
src/views/pages/admin-audio.ejs (modified) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/views/pages/admin-audio.ejs
r929d98d rbbf9d1a 4 4 <header class="ax-header"> 5 5 <div> 6 <h1> Audio tracks</h1>7 <p class="ax-tagline"> Site-level MP3s. Gebruik <code>[[track:<id>]]</code> in een post om een play-knop in te voegen.</p>6 <h1><%= t('aaud.title') %></h1> 7 <p class="ax-tagline"><%= t('aaud.tagline_pre') %> <code>[[track:<id>]]</code> <%= t('aaud.tagline_post') %></p> 8 8 </div> 9 9 </header> … … 14 14 <%# ── UPLOAD ──────────────────────────────────────────────── %> 15 15 <section class="ax-card"> 16 <div class="ax-card-title"> Upload</div>16 <div class="ax-card-title"><%= t('aaud.upload') %></div> 17 17 18 18 <%# Bulk drag-drop zone. Multiple files at once, transcoded sequentially. … … 25 25 <div class="ax-row ax-row-2"> 26 26 <label class="ax-field"> 27 <span> Artiest <small>(toegepast op alle bestanden)</small></span>28 <input type="text" id="batch-artist" placeholder=" Optioneel">27 <span><%= t('aaud.artist') %> <small><%= t('aaud.applied_all') %></small></span> 28 <input type="text" id="batch-artist" placeholder="<%= t('aaud.optional') %>"> 29 29 </label> 30 30 <label class="ax-field"> 31 <span> Album <small>(toegepast op alle bestanden)</small></span>32 <input type="text" id="batch-album" placeholder=" Optioneel">31 <span><%= t('aaud.album') %> <small><%= t('aaud.applied_all') %></small></span> 32 <input type="text" id="batch-album" placeholder="<%= t('aaud.optional') %>"> 33 33 </label> 34 34 </div> 35 35 <label class="ax-field ax-file"> 36 <span> Cover <small>(optioneel, toegepast op alle bestanden — jpg/png/webp/gif, max 5 MB)</small></span>36 <span><%= t('aaud.cover') %> <small><%= t('aaud.cover_hint') %></small></span> 37 37 <span class="ax-file-control"> 38 <span class="ax-btn ax-btn-secondary ax-file-btn">🖼 Kies cover</span>39 <span class="ax-file-name" data-empty> Geen bestand gekozen</span>38 <span class="ax-btn ax-btn-secondary ax-file-btn">🖼 <%= t('aaud.choose_cover') %></span> 39 <span class="ax-file-name" data-empty><%= t('aaud.no_file') %></span> 40 40 <input type="file" id="batch-cover" accept="image/jpeg,image/png,image/webp,image/gif"> 41 41 </span> … … 45 45 <label class="ax-dropzone" id="audio-dropzone" tabindex="0"> 46 46 <span class="ax-dropzone-icon">🎵</span> 47 <strong class="ax-dropzone-title"> Sleep audio hierheen</strong>48 <span class="ax-dropzone-sub"> of klik om bestanden te kiezen<br><small>mp3, m4a, ogg, opus, flac · max <%= maxBytesMb %> MB · wav max <%= maxWavMb %> MB</small></span>47 <strong class="ax-dropzone-title"><%= t('aaud.drag_here') %></strong> 48 <span class="ax-dropzone-sub"><%= t('aaud.or_click') %><br><small>mp3, m4a, ogg, opus, flac · max <%= maxBytesMb %> MB · wav max <%= maxWavMb %> MB</small></span> 49 49 <input type="file" id="audio-files" accept="audio/*" multiple> 50 50 </label> … … 54 54 55 55 <div class="ax-form-actions" id="upload-actions" hidden> 56 <button type="button" class="ax-btn ax-btn-primary" id="start-upload-btn">⬆ Start upload</button>57 <button type="button" class="ax-btn" id="clear-queue-btn"> Wis lijst</button>56 <button type="button" class="ax-btn ax-btn-primary" id="start-upload-btn">⬆ <%= t('aaud.start_upload') %></button> 57 <button type="button" class="ax-btn" id="clear-queue-btn"><%= t('aaud.clear_list') %></button> 58 58 </div> 59 59 </div> … … 63 63 <section class="ax-card"> 64 64 <div class="ax-card-title" style="display:flex;align-items:center;gap:.5rem"> 65 Tracks<span class="ax-count"><%= tracks.length %></span>65 <%= t('aaud.tracks') %> <span class="ax-count"><%= tracks.length %></span> 66 66 <button type="button" class="ax-btn ax-btn-secondary" id="add-link-track-btn" 67 style="margin-left:auto;font-size:.85rem" title=" Een track zonder audiobestand — alleen titel + open-in links">68 + Track zonder audio67 style="margin-left:auto;font-size:.85rem" title="<%= t('aaud.add_link_track_title') %>"> 68 + <%= t('aaud.add_link_track') %> 69 69 </button> 70 70 </div> … … 73 73 <div class="ax-empty"> 74 74 <div class="ax-empty-icon">♫</div> 75 <p> Nog geen tracks. Upload er een hierboven.</p>75 <p><%= t('aaud.no_tracks') %></p> 76 76 </div> 77 77 <% } else { %> 78 <% 79 // Pre-fetch loop labels — `t` is shadowed by the loop var below. 80 var _aaudUntitled = t('aaud.untitled'); 81 var _aaudPlay = t('aaud.play'); 82 var _aaudEdit = t('aaud.edit'); 83 var _aaudDlOn = t('aaud.dl_on'); 84 var _aaudDlOff = t('aaud.dl_off'); 85 var _aaudDelete = t('aaud.delete'); 86 var _aaudCopy = t('aaud.copy_click'); 87 var _aaudDelConfirm = t('aaud.delete_confirm'); 88 %> 78 89 <ul class="ax-list"> 79 90 <% tracks.forEach(function(t) { %> … … 86 97 87 98 <div class="ax-track-meta"> 88 <div class="ax-track-title" data-cell="title"><%= t.title || '(zonder titel)'%></div>99 <div class="ax-track-title" data-cell="title"><%= t.title || _aaudUntitled %></div> 89 100 <div class="ax-track-sub"> 90 101 <span data-cell="artist"><%= t.artist || '—' %></span> … … 92 103 <span class="ax-track-sep">·</span><span><%= t.size ? Math.round(t.size/1024) + ' KB' : '—' %></span> 93 104 </div> 94 <code class="ax-embed" data-copy="[[track:<%= t.id %>]]" title=" Klik om te kopiëren">[[track:<%= t.id %>]]</code>105 <code class="ax-embed" data-copy="[[track:<%= t.id %>]]" title="<%= _aaudCopy %>">[[track:<%= t.id %>]]</code> 95 106 </div> 96 107 … … 100 111 data-stream-url="<%= t.stream_url %>" 101 112 data-track-id="<%= t.id %>" 102 aria-label=" Afspelen" title="Afspelen">113 aria-label="<%= _aaudPlay %>" title="<%= _aaudPlay %>"> 103 114 <span class="ax-track-play-icon" aria-hidden="true">▶</span> 104 115 </button> 105 116 <% } %> 106 <button type="button" class="ax-icon-btn" data-track-edit data-id="<%= t.id %>" aria-label=" Bewerken" title="Bewerken">✎</button>117 <button type="button" class="ax-icon-btn" data-track-edit data-id="<%= t.id %>" aria-label="<%= _aaudEdit %>" title="<%= _aaudEdit %>">✎</button> 107 118 <% if (typeof premiumUnlocked === 'undefined' || premiumUnlocked) { %> 108 119 <button type="button" class="ax-icon-btn" data-track-dl data-id="<%= t.id %>" data-on="<%= t.downloadable ? '1' : '0' %>" 109 aria-label=" Download-voor-email" title="<%= t.downloadable ? 'Download-voor-email staat AAN — klik om uit te zetten' : 'Download-voor-email staat uit — klik om aan te zetten'%>"120 aria-label="<%= t.downloadable ? _aaudDlOn : _aaudDlOff %>" title="<%= t.downloadable ? _aaudDlOn : _aaudDlOff %>" 110 121 style="<%= t.downloadable ? 'color:var(--accent,#6b8f71)' : 'opacity:.5' %>">⬇</button> 111 122 <% } %> 112 <form action="/admin/audio/<%= t.id %>/delete" method="post" onsubmit="return confirm(' Track verwijderen?')" class="ax-track-delete">113 <button type="submit" class="ax-icon-btn ax-icon-btn-danger" aria-label=" Verwijderen" title="Verwijderen">🗑</button>123 <form action="/admin/audio/<%= t.id %>/delete" method="post" onsubmit="return confirm('<%= _aaudDelConfirm %>')" class="ax-track-delete"> 124 <button type="submit" class="ax-icon-btn ax-icon-btn-danger" aria-label="<%= _aaudDelete %>" title="<%= _aaudDelete %>">🗑</button> 114 125 </form> 115 126 </div> … … 122 133 <% if ((typeof premiumUnlocked === 'undefined' || premiumUnlocked) && typeof embedUrl !== 'undefined') { %> 123 134 <section class="ax-section" style="margin-top:1.5rem"> 124 <h2 style="margin:0 0 .4rem">🔊 Embedbare speler</h2>125 <p style="opacity:.75;font-size:.9rem;margin:0 0 .6rem"> Plak deze code op je eigen website/blog om je muziek met deze speler in te sluiten:</p>135 <h2 style="margin:0 0 .4rem">🔊 <%= t('aaud.embed_player') %></h2> 136 <p style="opacity:.75;font-size:.9rem;margin:0 0 .6rem"><%= t('aaud.embed_hint') %></p> 126 137 <textarea readonly rows="3" onclick="this.select()" style="width:100%;font-family:monospace;font-size:12px;padding:10px;border-radius:8px;border:1px solid var(--rule);background:var(--paper-2);color:inherit;"><iframe src="<%= embedUrl %>" width="100%" height="420" frameborder="0" loading="lazy" style="border-radius:12px"></iframe></textarea> 127 <p style="margin:.6rem 0 0"><a class="btn" href="<%= embedUrl %>" target="_blank">▶ Speler-voorbeeld openen</a></p>138 <p style="margin:.6rem 0 0"><a class="btn" href="<%= embedUrl %>" target="_blank">▶ <%= t('aaud.preview_player') %></a></p> 128 139 </section> 129 140 <% } %> … … 573 584 nameEl.removeAttribute('data-empty'); 574 585 } else { 575 nameEl.textContent = ' Geen bestand gekozen';586 nameEl.textContent = '<%= t('aaud.no_file') %>'; 576 587 nameEl.setAttribute('data-empty', ''); 577 588 } … … 592 603 if (icon) icon.textContent = playing ? '⏸' : '▶'; 593 604 btn.classList.toggle('is-playing', playing); 594 btn.setAttribute('aria-label', playing ? ' Pauzeren' : 'Afspelen');605 btn.setAttribute('aria-label', playing ? '<%= t('aaud.pause') %>' : '<%= t('aaud.play') %>'); 595 606 } 596 607 … … 695 706 function setItemStatus(item, status, label) { 696 707 const labels = { 697 queued: ' Wachten',698 uploading: ' Uploaden…',699 transcoding: ' Converteren…',700 done: '✓ Klaar',701 error: '✗ Fout',708 queued: '<%= t('aaud.st_queued') %>', 709 uploading: '<%= t('aaud.st_uploading') %>', 710 transcoding: '<%= t('aaud.st_transcoding') %>', 711 done: '✓ <%= t('aaud.st_done') %>', 712 error: '✗ <%= t('aaud.st_error') %>', 702 713 }; 703 714 item.status = status; … … 726 737 li.innerHTML = 727 738 '<div class="ax-queue-name"></div>' + 728 '<span class="ax-queue-status ax-queue-status--queued"> Wachten</span>';739 '<span class="ax-queue-status ax-queue-status--queued"><%= t('aaud.st_queued') %></span>'; 729 740 // Use textContent to avoid HTML-injection if a filename contains markup. 730 741 li.querySelector('.ax-queue-name').textContent = file.name; … … 813 824 } catch (err) { 814 825 console.error('upload failed for', item.file.name, err); 815 setItemStatus(item, 'error', '✗ ' + (err.message || ' Mislukt'));826 setItemStatus(item, 'error', '✗ ' + (err.message || '<%= t('aaud.failed') %>')); 816 827 } 817 828 } … … 864 875 let data; 865 876 try { data = await res.json(); } 866 catch (_) { throw new Error(' Onverwacht serverantwoord(' + res.status + ')'); }877 catch (_) { throw new Error('<%= t('aaud.err_unexpected') %> (' + res.status + ')'); } 867 878 868 879 if (!res.ok || !data.ok) { … … 870 881 } 871 882 872 setItemStatus(item, 'done', '✓ ' + (data.title || ' Klaar'));883 setItemStatus(item, 'done', '✓ ' + (data.title || '<%= t('aaud.st_done') %>')); 873 884 } catch (err) { 874 885 clearTimeout(transcodeHint); … … 885 896 el.classList.add('is-copied'); 886 897 const original = el.textContent; 887 el.textContent = '✓ gekopieerd';898 el.textContent = '✓ <%= t('aaud.copied') %>'; 888 899 setTimeout(() => { 889 900 el.classList.remove('is-copied'); … … 903 914 method: 'POST', credentials: 'same-origin', 904 915 headers: { 'Content-Type': 'application/json' }, 905 body: JSON.stringify({ title: ' Nieuwe track' }),916 body: JSON.stringify({ title: '<%= t('aaud.new_track') %>' }), 906 917 }); 907 918 const j = await r.json(); 908 if (!r.ok || !j.ok) throw new Error(j.error || ' Aanmaken mislukt');919 if (!r.ok || !j.ok) throw new Error(j.error || '<%= t('aaud.create_failed') %>'); 909 920 if (typeof window.openTrackEditor !== 'function') { location.reload(); return; } 910 921 window.openTrackEditor({ id: j.id, onSaved: () => location.reload() }); 911 922 } catch (err) { 912 alert(' Track aanmaken mislukt: ' + err.message);923 alert('<%= t('aaud.create_failed') %>: ' + err.message); 913 924 } finally { 914 925 addLinkBtn.disabled = false; … … 923 934 btn.addEventListener('click', () => { 924 935 if (typeof window.openTrackEditor !== 'function') { 925 alert(' Track editor niet geladen');936 alert('<%= t('aaud.editor_not_loaded') %>'); 926 937 return; 927 938 } … … 936 947 const artistEl = row.querySelector('[data-cell="artist"]'); 937 948 const albumEl = row.querySelector('[data-cell="album"]'); 938 if (titleEl) titleEl.textContent = track.title || ' (zonder titel)';949 if (titleEl) titleEl.textContent = track.title || '<%= t('aaud.untitled') %>'; 939 950 if (artistEl) artistEl.textContent = track.artist || '—'; 940 951 if (albumEl) { … … 984 995 btn.style.opacity = want ? '1' : '.5'; 985 996 btn.title = want 986 ? ' Download-voor-email staat AAN — klik om uit te zetten'987 : ' Download-voor-email staat uit — klik om aan te zetten';997 ? '<%= t('aaud.dl_on') %>' 998 : '<%= t('aaud.dl_off') %>'; 988 999 } catch (e) { 989 alert(' Kon niet wijzigen: ' + (e.message || e));1000 alert('<%= t('aaud.change_failed') %>: ' + (e.message || e)); 990 1001 } finally { 991 1002 btn.disabled = false;
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)