broadcast2html.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // https://gist.github.com/pjdietz/e0545332e2fc67a9a460
  2. function rfc3339(d) {
  3. function pad(n) {
  4. return n < 10 ? "0" + n : n;
  5. }
  6. function timezoneOffset(offset) {
  7. if (offset === 0) {
  8. return "Z";
  9. }
  10. let sign = (offset > 0) ? "-" : "+";
  11. offset = Math.abs(offset);
  12. return sign + pad(Math.floor(offset / 60)) + ":" + pad(offset % 60);
  13. }
  14. return d.getFullYear() + "-" +
  15. pad(d.getMonth() + 1) + "-" +
  16. pad(d.getDate()) + "T" +
  17. pad(d.getHours()) + ":" +
  18. pad(d.getMinutes()) + ":" +
  19. pad(d.getSeconds()) +
  20. timezoneOffset(d.getTimezoneOffset());
  21. }
  22. function human_datetime(dat) {
  23. let weekdaynames = [ "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" ];
  24. let monthnames = [ "Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez" ];
  25. function pad(n) {
  26. return n < 10 ? "0" + n : n;
  27. }
  28. var ret = '';
  29. ret += weekdaynames[dat.getDay()] + ", ";
  30. ret += dat.getDate() + ". ";
  31. ret += monthnames[dat.getMonth()] + " ";
  32. ret += dat.getFullYear() + " ";
  33. ret += pad(dat.getHours()) + ":";
  34. ret += pad(dat.getMinutes());
  35. return ret;
  36. }
  37. function url_norm(url) {
  38. let n = url.replace(/\/[^/]+\/\.\.\//, '/');
  39. return n == url
  40. ? url
  41. : url_norm(n);
  42. }
  43. function amend_podcasts (ok, xhr, p) {
  44. if (! ok) {
  45. return;
  46. }
  47. let hrefs = xhr.responseText.trim().split(/\s+/m);
  48. if (hrefs.length < 1)
  49. return;
  50. let base = p.ownerDocument.location;
  51. let assets = "../../../../../assets";
  52. var html = "";
  53. for(let i = 0; i < hrefs.length; i++) {
  54. let href = hrefs[i];
  55. let feed = url_norm(base + "/../" + href + ".rss");
  56. let lbl = href.replace('../../../../../podcasts/', '');
  57. html += "<a href='" + href + "'>" + lbl + "</a> ";
  58. html += "<a href='" + feed + "' rel='alternate' type='application/rss+xml'><img height='16' alt='feed' src='" + assets + "/Feed-icon.svg'/></a> ";
  59. html += "<a href='https://validator.w3.org/feed/check.cgi?url=" + feed + "'><img height='16' alt='Valid RSS Badge' src='" + assets + "/valid-rss-rogers.png'/></a> ";
  60. html += "<br class='br'/> ";
  61. }
  62. p.innerHTML = html;
  63. }
  64. function amend_canonical_url(url) {
  65. {
  66. let col = document.getElementsByClassName("canonical-url");
  67. for (let i = 0; i < col.length; i++) {
  68. col[i].innerText = url;
  69. }
  70. }
  71. {
  72. let col = document.getElementsByClassName("base-url");
  73. for (let i = 0; i < col.length; i++) {
  74. col[i].innerText = url + '/../../../../../..';
  75. }
  76. }
  77. }
  78. function id(_id) {
  79. return document.getElementById(_id);
  80. }
  81. function amend_back_forth_hrefs (timestart, timeend) {
  82. function href(t0, m) {
  83. return '../../../now?t=' + rfc3339(new Date(t0.getTime() + m * 60 * 1000));
  84. }
  85. id('prevP1W' ).href = href(timestart, -60 * 24 * 7);
  86. id('prevP1D' ).href = href(timestart, -60 * 24);
  87. id('prevPT1M').href = href(timestart, -1);
  88. id('nextPT1M').href = href(timeend, 1);
  89. id('nextP1D' ).href = href(timestart, 60 * 24);
  90. id('nextP1W' ).href = href(timestart, 60 * 24 * 7);
  91. }
  92. window.addEventListener('DOMContentLoaded', (event) => {
  93. let timestart = new Date(id('dtstart').dataset.rfc3339);
  94. let timeend = new Date(id('dtend' ).dataset.rfc3339);
  95. let now = new Date();
  96. id('dtstart').innerText = human_datetime(timestart);
  97. amend_back_forth_hrefs(timestart, timeend);
  98. amend_canonical_url(window.location.href);
  99. {
  100. var clz = 'is_past';
  101. if( now < timestart )
  102. clz = 'is_future';
  103. else if( now < timeend )
  104. clz = 'is_current';
  105. document.getElementsByTagName('html')[0].classList.add(clz);
  106. }
  107. {
  108. let xhr = new XMLHttpRequest();
  109. xhr.onreadystatechange = function () {
  110. if (xhr.readyState !== 4) return;
  111. amend_podcasts(xhr.status >= 200 && xhr.status < 300, xhr, id('podcasts'));
  112. };
  113. xhr.open('GET', document.location.href.replace('.xml', '.podcasts'));
  114. xhr.send();
  115. }
  116. function finishAlldayCurrentEntry(a) {
  117. // a.removeClass('is_past').addClass('is_current').append( jQuery('<span/>').text('jetzt') );
  118. a.classList.remove('is_past');
  119. a.classList.add('is_current');
  120. let span = document.createElement('span');
  121. span.textContent = 'jetzt';
  122. a.appendChild(span);
  123. }
  124. console.log('add other broadcasts of the day (same station)');
  125. let xhr2 = new XMLHttpRequest();
  126. xhr2.onload = function() {
  127. // console.log('GET ' + xhr2.responseURL + ' ' + xhr2.status);
  128. if (xhr2.status < 200 || xhr2.status >= 400)
  129. return;
  130. let parent = document.getElementById('allday');
  131. parent.removeChild(parent.firstChild);
  132. var hasRecording = false;
  133. var pastBC = null;
  134. let allA = new DOMParser().parseFromString(xhr2.responseText, 'text/html').getElementsByTagName('a');
  135. for(let i = 0; i < allA.length; i++) {
  136. let src = allA[i];
  137. let href = src.getAttribute('href');
  138. let me = document.createElement('a');
  139. me.textContent = src.textContent;
  140. let li = document.createElement('li');
  141. li.appendChild(me);
  142. // console.log(i + ' ' + href);
  143. if( '../' === href ) // ignore parent link
  144. continue;
  145. if( hasRecording ) // previous entry was a .podcasts recording marker
  146. me.classList.add('has_podcast');
  147. if( hasRecording = href.endsWith('.podcasts') ) // remember and swallow .podcasts
  148. continue;
  149. let txt = me.textContent.replace(/\.xml$/i, '');
  150. let ma = txt.match(/^(\d{2})(\d{2})$/);
  151. if( false && ma ) {
  152. let t0 = dtstart.hours(ma[1]).minutes(ma[2]).seconds(0); // assumes same day
  153. me.getAttribute('title', t0.format());
  154. me.textContent = t0.format('HH:mm') + ' ' + ma[3];
  155. // set past/current/future class
  156. if( now < t0 ) {
  157. if(pastBC) {
  158. finishAlldayCurrentEntry(pastBC);
  159. pastBC = null;
  160. }
  161. me.classList.add('is_future');
  162. } else {
  163. pastBC = me;
  164. me.classList.add('is_past');
  165. }
  166. } else {
  167. me.textContent = txt; // index usually.
  168. }
  169. me.setAttribute('href', href );
  170. parent.appendChild(li);
  171. }
  172. if( pastBC && now < dtstart.hours(24).minutes(0).seconds(0) )
  173. finishAlldayCurrentEntry(pastBC)
  174. parent.setAttribute('style', 'display:block');
  175. }
  176. xhr2.open('GET', '.');
  177. xhr2.send();
  178. });