Index: src/services/music/index.js
===================================================================
--- src/services/music/index.js	(revision 1d1fdc97939238a96492ef7adccedc1b08f51985)
+++ src/services/music/index.js	(revision ca260d13a940f7563a540fad1f1945ef28e9160c)
@@ -134,4 +134,38 @@
   for (const r of rijen) if (!uit.has(r.tid)) uit.set(r.tid, { id: r.post_id, slug: r.post_slug });
   return uit;
+}
+
+/**
+ * Elke GEPUBLICEERDE post waar deze track in staat, op welke manier ook:
+ * rechtstreeks ([[track:id]]), via een playlist of via zijn albumnaam.
+ *
+ * Voor iets anders dan trackHostPosts, dat per track EEN post kiest voor de
+ * bibliotheek. Opent de mediamanager een track (shaer, 30-9), dan moeten ALLE
+ * posts met die track opnieuw de deur uit, anders krijgt een volger de speler
+ * pas bij de volgende bewerking van die post.
+ *
+ * Alleen posts van deze site: playlists.id is een globale sleutel, en het
+ * filter hoort op de post en de track, niet op de playlist (zie de
+ * tenancy-toets bij setAudioFediOpen).
+ */
+export function postsEmbeddingTrack(siteId, trackId) {
+  const t = db.prepare('SELECT id, album FROM audio_tracks WHERE id = ? AND site_id = ?').get(trackId, siteId);
+  if (!t) return [];
+  const rows = db.prepare(`
+    SELECT p.id FROM posts p
+     WHERE p.site_id = ? AND p.status = 'published'
+       AND p.content LIKE '%[[track:' || ? || ']]%'
+    UNION
+    SELECT p.id FROM playlist_tracks pt
+      JOIN posts p ON p.site_id = ? AND p.status = 'published'
+                  AND p.content LIKE '%[[playlist:' || pt.playlist_id || ']]%'
+     WHERE pt.track_id = ?
+    UNION
+    SELECT p.id FROM posts p
+     WHERE p.site_id = ? AND p.status = 'published'
+       AND ? IS NOT NULL AND ? <> ''
+       AND p.content LIKE '%[[album:' || ? || ']]%'
+  `).all(siteId, t.id, siteId, t.id, siteId, t.album, t.album, t.album);
+  return rows.map((r) => r.id);
 }
 
