{{TITLE}}
+{{ARTIST}}
+
+ CIRCLE WITH A DOT
+
+
+ Music release one-page generator
++ Relibre is a simple, free and open source landing page generator that is an alternative to services such as + HyperFollow. Relibre has one job — giving the artist the ability to generate a single HTML file to + self-host with their own methods. +
+ +Fill the form → Generate HTML → you get a single [release_name].html to share as your landing page for your new music release.
{{ARTIST}}
+$1')
+ .replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,'$1');
+ const lines = html.split(/\r?\n/);
+ let out = '', inOl=false, inUl=false;
+ for(const line of lines){
+ if(/^\s*\d+\.\s+/.test(line)){ if(!inOl){out+=''+line+'
'; + } + if(inOl) out+=''; if(inUl) out+=''; + return out; + } + + function fileToDataURL(file){ + return new Promise((resolve,reject)=>{ + const fr = new FileReader(); + fr.onload = () => resolve(fr.result); + fr.onerror = reject; + fr.readAsDataURL(file); + }); + } + + const LABELS = { + applemusic: 'Apple Music', + amazonmusic: 'Amazon Music', + soundcloud: 'SoundCloud', + tidal: 'Tidal', + tiktok: 'TikTok', + 'diaspora*': 'diaspora*', + x: 'X' + }; + + function pretty(k){ + return LABELS[k] || k.charAt(0).toUpperCase() + k.slice(1); + } + + function escapeHtml(s){ return (s||'').replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c])); } + + // Map normalized key -> icon key + function getServiceIcon(key){ + const map = { + spotify:'spotify', applemusic:'apple', bandcamp:'bandcamp', + soundcloud:'soundcloud', tidal:'tidal', + mastodon:'mastodon', pixelfed:'pixelfed', peertube:'peertube', lemmy:'lemmy', owncast:'owncast', + bluesky:'bluesky', facebook:'facebook', instagram:'instagram', twitter:'x', threads:'threads', tiktok:'tiktok', + email:'email', youtube:'youtube', reddit:'reddit', website:'website', blog:'blog', + friendica:'friendica', 'diaspora*':'diaspora', x:'x' + }; + const iconKey = map[key] || 'website'; + return ICONS[iconKey] || ''; + } + + // Normalize a display label to a lookup key (e.g., "Apple Music" -> "applemusic") + function labelToKey(label){ + return String(label || '').toLowerCase().replace(/[^a-z0-9]+/g,''); + } + + function renderButtonsGrid(title, buttons, id){ + if(!buttons.length) return ''; + const items = buttons.map(b => { + const key = labelToKey(b.label); + const icon = getServiceIcon(key); + const img = icon ? `