- Timestamp:
- 09/30/2026 08:08:44 AM (4 hours ago)
- Branches:
- main
- Children:
- 76bd53c
- Parents:
- 19e28ce
- Location:
- src
- Files:
-
- 4 edited
-
routes/admin-audio.js (modified) (3 diffs)
-
services/i18n.js (modified) (3 diffs)
-
services/music/index.js (modified) (1 diff)
-
views/pages/admin-audio.ejs (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/admin-audio.js
r19e28ce rca260d1 24 24 import { mediaDir } from '../config/paths.js'; 25 25 import * as ActivityPubService from '../services/ActivityPubService.js'; 26 import { postsEmbeddingTrack } from '../services/music/index.js'; 27 import { t as i18nT, resolveLang } from '../services/i18n.js'; 26 28 27 29 const __dirname = path.dirname(fileURLToPath(import.meta.url)); … … 96 98 const rows = db.prepare(` 97 99 SELECT t.id, t.title, t.artist, t.album, t.duration, t.cover_url, 98 t.position, t.created_at, t.downloadable, m.filename, m.size, m.mime_type 100 t.position, t.created_at, t.downloadable, t.fedi_open, t.media_id, 101 m.filename, m.size, m.mime_type 99 102 FROM audio_tracks t 100 103 LEFT JOIN media m ON m.id = t.media_id … … 290 293 }); 291 294 295 /** 296 * Een track openbaar op de fediverse zetten, vanuit de mediamanager (Robin, 297 * 30-9: "Fedi open audio ook per track aan kunnen zetten"). 298 * 299 * Tot nu toe kon dat alleen per POST, met het vinkje in de editor, dat elke 300 * track in die post opende. De vlag zelf was altijd al per track 301 * (audio_tracks.fedi_open): hij opent het BESTAND en maakt er een echte 302 * Audio-bijlage van. Dit is dezelfde vlag, met een eigen knop. 303 * 304 * EENRICHTINGS, net als in de editor. Een bestand dat al gefedereerd is, staat 305 * op andere servers; het hier weer afschermen zou schijnveiligheid zijn. Er is 306 * dus geen weg terug, en die bouwen we ook niet. 307 * 308 * EN DE POSTS GAAN OPNIEUW DE DEUR UIT. Het vinkje in de editor werkt zichtbaar 309 * omdat het opslaan van de post een Update stuurt, met de audio erin. Een knop 310 * die alleen de vlag zet, laat elke post die al verstuurd is zonder speler 311 * staan tot iemand hem bewerkt. Dus hier dezelfde Update, voor elke 312 * gepubliceerde post waar de track in staat -- rechtstreeks, via een playlist of 313 * via zijn album. De bibliotheek (Funkwhale) hoeft niets: die wordt opgehaald, 314 * en een open track staat er meteen in. 315 * 316 * Alleen een track met een eigen BESTAND: een track die alleen een link is heeft 317 * niets om te openen. 318 * 319 * `deliver` is er voor de toetsen; de route gebruikt de echte deliverUpdate. 320 */ 321 export function openTrackOnFediverse(site, trackId, { deliver = (s, p) => ActivityPubService.deliverUpdate(s, p) } = {}) { 322 const t = db.prepare('SELECT id, media_id, fedi_open FROM audio_tracks WHERE id = ? AND site_id = ?').get(trackId, site.id); 323 if (!t) return { ok: false, reason: 'not_found' }; 324 if (!t.media_id) return { ok: false, reason: 'no_file' }; 325 if (t.fedi_open) return { ok: true, changed: false, updated: 0 }; 326 db.prepare('UPDATE audio_tracks SET fedi_open = 1 WHERE id = ? AND site_id = ?').run(trackId, site.id); 327 const postIds = postsEmbeddingTrack(site.id, trackId); 328 for (const id of postIds) { 329 const post = db.prepare('SELECT * FROM posts WHERE id = ? AND site_id = ?').get(id, site.id); 330 if (!post) continue; 331 // Op de achtergrond: een trage volger houdt de knop niet vast. 332 Promise.resolve() 333 .then(() => deliver(site, post)) 334 .catch((e) => console.warn('[admin-audio] Update na openen mislukt:', post.id, e.message)); 335 } 336 return { ok: true, changed: true, updated: postIds.length }; 337 } 338 339 router.post('/:id/fedi-open', requireGod, (req, res) => { 340 const site = res.locals.site; 341 if (!site) return res.status(404).send('Site required'); 342 const lang = resolveLang(req, { userLang: req.session?.user?.lang }); 343 const r = openTrackOnFediverse(site, req.params.id); 344 if (!r.ok) { 345 const msg = r.reason === 'no_file' ? i18nT(lang, 'aaud.fedi_no_file') : 'Not found'; 346 return res.redirect('/admin/audio?error=' + encodeURIComponent(msg)); 347 } 348 res.redirect('/admin/audio?success=' + encodeURIComponent(i18nT(lang, 'aaud.fedi_opened', { n: r.updated }))); 349 }); 350 292 351 router.post('/:id/delete', requireGod, (req, res) => { 293 352 const site = res.locals.site; -
src/services/i18n.js
r19e28ce rca260d1 400 400 'aaud.delete': 'Verwijderen', 401 401 'aaud.delete_confirm': 'Track verwijderen?', 402 'aaud. dl_on': 'Download-voor-email staat AAN — klik om uit te zetten',402 'aaud.fedi_open_btn': 'Openbaar delen op de fediverse', 'aaud.fedi_open_on': 'Openbaar gedeeld op de fediverse. Dat is permanent.', 'aaud.fedi_open_confirm': 'Deze track openbaar delen op de fediverse? Hij wordt speelbaar in apps en het bestand is te downloaden. Posts met deze track gaan opnieuw naar je volgers. Dit is permanent en niet terug te draaien.', 'aaud.fedi_opened': 'Openbaar gedeeld op de fediverse. Posts opnieuw verstuurd: {n}.', 'aaud.fedi_no_file': 'Deze track heeft geen eigen bestand, alleen een link. Er valt niets te openen.', 'aaud.dl_on': 'Download-voor-email staat AAN — klik om uit te zetten', 403 403 'aaud.dl_off': 'Download-voor-email staat uit — klik om aan te zetten', 404 404 'aaud.fedi_on': 'Op de fediverse gedeeld (speelt overal inline, bestand downloadbaar) — klik om uit te zetten', … … 1410 1410 'aaud.delete': 'Delete', 1411 1411 'aaud.delete_confirm': 'Delete track?', 1412 'aaud. dl_on': 'Download-for-email is ON — click to turn off',1412 'aaud.fedi_open_btn': 'Share openly on the fediverse', 'aaud.fedi_open_on': 'Shared openly on the fediverse. This is permanent.', 'aaud.fedi_open_confirm': 'Share this track openly on the fediverse? It becomes playable in apps and the file can be downloaded. Posts with this track are sent to your followers again. This is permanent and cannot be undone.', 'aaud.fedi_opened': 'Shared openly on the fediverse. Posts sent again: {n}.', 'aaud.fedi_no_file': 'This track has no file of its own, only a link. There is nothing to open.', 'aaud.dl_on': 'Download-for-email is ON — click to turn off', 1413 1413 'aaud.dl_off': 'Download-for-email is off — click to turn on', 1414 1414 'aaud.fedi_on': 'Shared on the fediverse (plays inline everywhere, file downloadable) — click to turn off', … … 2419 2419 'aaud.delete': 'Löschen', 2420 2420 'aaud.delete_confirm': 'Track löschen?', 2421 'aaud. dl_on': 'Download-für-E-Mail ist AN — zum Ausschalten klicken',2421 'aaud.fedi_open_btn': 'Offen im Fediverse teilen', 'aaud.fedi_open_on': 'Offen im Fediverse geteilt. Das ist dauerhaft.', 'aaud.fedi_open_confirm': 'Diesen Track offen im Fediverse teilen? Er wird in Apps abspielbar und die Datei kann heruntergeladen werden. Beiträge mit diesem Track werden erneut an deine Follower gesendet. Das ist dauerhaft und kann nicht rückgängig gemacht werden.', 'aaud.fedi_opened': 'Offen im Fediverse geteilt. Erneut gesendete Beiträge: {n}.', 'aaud.fedi_no_file': 'Dieser Track hat keine eigene Datei, nur einen Link. Es gibt nichts zu öffnen.', 'aaud.dl_on': 'Download-für-E-Mail ist AN — zum Ausschalten klicken', 2422 2422 'aaud.dl_off': 'Download-für-E-Mail ist aus — zum Einschalten klicken', 2423 2423 'aaud.fedi_on': 'Im Fediverse geteilt (spielt überall inline, Datei herunterladbar) — zum Ausschalten klicken', -
src/services/music/index.js
r19e28ce rca260d1 134 134 for (const r of rijen) if (!uit.has(r.tid)) uit.set(r.tid, { id: r.post_id, slug: r.post_slug }); 135 135 return uit; 136 } 137 138 /** 139 * Elke GEPUBLICEERDE post waar deze track in staat, op welke manier ook: 140 * rechtstreeks ([[track:id]]), via een playlist of via zijn albumnaam. 141 * 142 * Voor iets anders dan trackHostPosts, dat per track EEN post kiest voor de 143 * bibliotheek. Opent de mediamanager een track (shaer, 30-9), dan moeten ALLE 144 * posts met die track opnieuw de deur uit, anders krijgt een volger de speler 145 * pas bij de volgende bewerking van die post. 146 * 147 * Alleen posts van deze site: playlists.id is een globale sleutel, en het 148 * filter hoort op de post en de track, niet op de playlist (zie de 149 * tenancy-toets bij setAudioFediOpen). 150 */ 151 export function postsEmbeddingTrack(siteId, trackId) { 152 const t = db.prepare('SELECT id, album FROM audio_tracks WHERE id = ? AND site_id = ?').get(trackId, siteId); 153 if (!t) return []; 154 const rows = db.prepare(` 155 SELECT p.id FROM posts p 156 WHERE p.site_id = ? AND p.status = 'published' 157 AND p.content LIKE '%[[track:' || ? || ']]%' 158 UNION 159 SELECT p.id FROM playlist_tracks pt 160 JOIN posts p ON p.site_id = ? AND p.status = 'published' 161 AND p.content LIKE '%[[playlist:' || pt.playlist_id || ']]%' 162 WHERE pt.track_id = ? 163 UNION 164 SELECT p.id FROM posts p 165 WHERE p.site_id = ? AND p.status = 'published' 166 AND ? IS NOT NULL AND ? <> '' 167 AND p.content LIKE '%[[album:' || ? || ']]%' 168 `).all(siteId, t.id, siteId, t.id, siteId, t.album, t.album, t.album); 169 return rows.map((r) => r.id); 136 170 } 137 171 -
src/views/pages/admin-audio.ejs
r19e28ce rca260d1 91 91 var _aaudCopy = t('aaud.copy_click'); 92 92 var _aaudDelConfirm = t('aaud.delete_confirm'); 93 var _aaudFediBtn = t('aaud.fedi_open_btn'); 94 var _aaudFediOn = t('aaud.fedi_open_on'); 95 var _aaudFediConfirm = t('aaud.fedi_open_confirm'); 93 96 %> 94 97 <ul class="ax-list"> … … 125 128 aria-label="<%= t.downloadable ? _aaudDlOn : _aaudDlOff %>" title="<%= t.downloadable ? _aaudDlOn : _aaudDlOff %>" 126 129 style="<%= t.downloadable ? 'color:var(--accent,#6b8f71)' : 'opacity:.5' %>">⬇</button> 130 <% } %> 131 <%# Openbaar op de fediverse, per track (Robin, 30-9). EENRICHTINGS, net 132 als het vinkje in de post-editor: open is een slotje en geen knop meer, 133 want een bestand dat al verspreid is haal je niet terug. Alleen bij een 134 track met een eigen bestand; een link heeft niets om te openen. Een 135 formulier en geen fetch: werkt zonder JS, en data-confirm vraagt het 136 eerst (shell.ejs). %> 137 <% if (t.media_id) { %> 138 <% if (t.fedi_open) { %> 139 <span class="ax-icon-btn ax-fedi-on" role="img" aria-label="<%= _aaudFediOn %>" title="<%= _aaudFediOn %>"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span> 140 <% } else { %> 141 <form action="/admin/audio/<%= t.id %>/fedi-open" method="post" data-confirm="<%= _aaudFediConfirm %>" class="ax-track-fedi"> 142 <button type="submit" class="ax-icon-btn ax-fedi-off" aria-label="<%= _aaudFediBtn %>" title="<%= _aaudFediBtn %>"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></button> 143 </form> 144 <% } %> 127 145 <% } %> 128 146 <form action="/admin/audio/<%= t.id %>/delete" method="post" data-confirm="<%= _aaudDelConfirm %>" class="ax-track-delete"> … … 247 265 } 248 266 .ax-file-name[data-empty] { color: var(--ink-muted, var(--ink-soft)); } 267 /* Openbaar op de fediverse: dicht is gedimd, net als een uitgezette download; 268 open is de accentkleur en geen knop meer, want terug kan niet. */ 269 .ax-track-fedi { display: inline; } 270 .ax-fedi-off { opacity: .5; } 271 .ax-fedi-off:hover, .ax-fedi-off:focus-visible { opacity: 1; } 272 .ax-fedi-on { color: var(--accent, #6b8f71); cursor: default; } 249 273 250 274 .ax-form-actions {
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)