An easy way to have a 24/7 audio stream of music.
1<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 2 <xsl:output method="html" 3 doctype-system="about:legacy-compat" 4 encoding="UTF-8" /> 5 <xsl:template match="/icestats"> 6 <html xmlns="http://www.w3.org/1999/xhtml"> 7 <head> 8 <meta charset="utf-8" /> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> 10 <title>Radio Rita.moe</title> 11 <link rel="icon" href="https://rita.moe/rita-icon.png" /> 12 <link rel="stylesheet" type="text/css" href="style-status.css" /> 13 <link rel="stylesheet" href="https://cdn.plyr.io/3.6.2/plyr.css" /> 14 <script src="https://cdn.plyr.io/3.6.2/plyr.polyfilled.js"></script> 15 </head> 16 <body> 17 <div class="content"> 18 <h1 id="header">Radio Rita.moe</h1> 19 <!--mount point stats--> 20 <xsl:for-each select="source"> 21 <xsl:choose> 22 <xsl:when test="listeners"> 23 <div class="roundbox" data-mount="{@mount}"> 24 <div class="mounthead"> 25 <h3 class="mount"> 26 <xsl:value-of select="server_name" /> 27 <small>(<xsl:value-of select="@mount" />)</small> 28 </h3> 29 <div class="right"> 30 <xsl:choose> 31 <xsl:when test="authenticator"> 32 <a class="auth" href="/auth.xsl">Login</a> 33 </xsl:when> 34 <xsl:otherwise> 35 <ul class="mountlist"> 36 <li> 37 <a class="play" href="{@mount}.m3u">M3U</a> 38 </li> 39 <!-- 40 <li> 41 <a class="play" href="{@mount}.xspf">XSPF</a> 42 </li> 43 <li> 44 <a class="play" href="{@mount}.vclt">VCLT</a> 45 </li> 46 --> 47 </ul> 48 </xsl:otherwise> 49 </xsl:choose> 50 </div> 51 </div> 52 <div class="mountcont"> 53 <xsl:if test="server_type"> 54 <div class="audioplayer"> 55 <audio controls="controls" preload="none"> 56 <source src="{@mount}" type="{server_type}" /> 57 </audio> 58 </div> 59 </xsl:if> 60 <div class="playing"> 61 <xsl:if test="artist"> 62 <xsl:value-of select="artist" /> 63 - 64 </xsl:if> 65 <xsl:value-of select="title" /> 66 </div> 67 <div class="search"> 68 <a href="/" onclick="ss('{@mount}'); return false;">(search youtube)</a> 69 </div> 70 </div> 71 </div> 72 </xsl:when> 73 <xsl:otherwise> 74 <h3> 75 <xsl:value-of select="@mount" /> 76 - Not Connected 77 </h3> 78 </xsl:otherwise> 79 </xsl:choose> 80 </xsl:for-each> 81 <div id="footer"> 82 Powered by <a href="https://www.icecast.org">Icecast</a> 83 and <a href="https://www.liquidsoap.info">Liquidsoap</a>. 84 </div> 85 </div> 86 <script type="text/javascript"> 87<![CDATA[ 88 function ss (mount) { 89 let title = document.querySelector('[data-mount="' + mount + '"] .playing').innerHTML 90 let se = document.querySelector('[data-mount="' + mount + '"] .search a') 91 se.innerHTML = 'Please wait...' 92 fetch('https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&safeSearch=none&type=video&videoCategoryId=10&key=AIzaSyB0PbGfWP_AwEXx7_DypkJiB0qIjHxedi0&q=' + encodeURIComponent(title)) 93 .then(r => r.json()) 94 .then(j => { 95 se.innerHTML = '(search youtube)' 96 if (j.items.length > 0) { 97 window.open('https://www.youtube.com/watch?v=' + j.items[0].id.videoId, '_blank') 98 } 99 }) 100 } 101 102 function s () { 103 document.querySelectorAll('div[data-mount]').forEach(e => { 104 fetch('https://radio.rita.moe/status-json.xsl?mount=' + e.dataset.mount) 105 .then(r => r.json()) 106 .then(j => { 107 setTimeout(_ => { 108 e.querySelector('.playing').innerHTML = j.icestats.source.title 109 }, 5000) 110 }) 111 }) 112 } 113 114 setInterval(s, 3000) 115 116 document.querySelectorAll('audio').forEach(e => { 117 new Plyr(e, { 118 controls: ['play', 'current-time', 'mute', 'volume'], 119 invertTime: false, 120 toggleInvert: false 121 }) 122 }) 123]]> 124 </script> 125 </body> 126 </html> 127 </xsl:template> 128</xsl:stylesheet> 129