Improve 8bcDump

Improve the interface of the public 8bitcollective archive on brkbrkbrk.com.

当前为 2017-03-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Improve 8bcDump
  3. // @namespace Improve8bcDump
  4. // @description Improve the interface of the public 8bitcollective archive on brkbrkbrk.com.
  5. // @include http://brkbrkbrk.com/8bcdump/
  6. // @include https://brkbrkbrk.com/8bcdump/
  7. // @include http://www.brkbrkbrk.com/8bcdump/
  8. // @include https://www.brkbrkbrk.com/8bcdump/
  9. // @version 0.4.0
  10. // @grant none
  11. // @author Jack Willis
  12. // @license MIT; https://opensource.org/licenses/MIT
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. console.log('Improve8bcDump v0.4.0 is active.');
  17.  
  18. // Fix a wrong attribute on the page's external stylesheet.
  19. var stylesheet = document.querySelector('link[type="text/stylesheet"]');
  20. stylesheet.setAttribute('type', 'text/css');
  21.  
  22. // Styles for the last played list
  23. var newStyles = document.createElement('style');
  24. newStyles.textContent += '.lastPlayed li:first-child { font-weight: bold; }';
  25. newStyles.textContent += '.lastPlayed li:first-child:after { content: " (playing)" }';
  26. newStyles.textContent += '.lastPlayed { margin: 1em; padding: 2em; border: 1px solid black; }';
  27. document.body.appendChild(newStyles);
  28. // Create a stack for the last played songs.
  29. // The stack is realized in an <ol>, contained in parentElement.
  30.  
  31. var getSongLinkByIndex = function(index) {
  32. return document.getElementById(index).querySelector('a');
  33. };
  34. function LastPlayedList(maxLength, parentElement) {
  35. // Create a heading for the last played list
  36. var heading = document.createElement('h2');
  37. heading.textContent = 'Last played';
  38. parentElement.appendChild(heading);
  39. // Create the list itself
  40. var list = document.createElement('ol');
  41. list.classList.add('lastPlayed');
  42. parentElement.appendChild(list);
  43. // Push songs through the stack
  44. this.push = function(songNode) {
  45. var nodes = list.childNodes;
  46. if (nodes.length == maxLength) {
  47. list.removeChild(nodes[nodes.length - 1]);
  48. }
  49. list.insertBefore(songNode, nodes[0]);
  50. };
  51.  
  52. this.currentSongInfo = function() {
  53. return list.childNodes[0].querySelector('span').innerHTML;
  54. };
  55. }
  56. // Create a list near the top of the page to hold the last 20 songs
  57. var lastPlayedDiv = document.createElement('div');
  58. document.body.insertBefore(lastPlayedDiv, document.querySelector('h1 + p'));
  59.  
  60. var lastPlayedList = new LastPlayedList(20, lastPlayedDiv);
  61. // The song's information should be added to the last played list.
  62. // Overriding the existing updateID3 method
  63.  
  64. var isBlank = function(str) {
  65. return !str || /^\s*$/.test(str);
  66. };
  67.  
  68. window.updateID3 = function(id3) {
  69. console.log(id3);
  70. var songLi = document.createElement('li');
  71. var songInfo = document.createElement('span');
  72.  
  73. var title = isBlank(id3.title) ? 'Unknown' : ('"' + id3.title + '"');
  74. var artist = isBlank(id3.artist) ? 'Unknown' : id3.artist;
  75.  
  76. var album;
  77. if (isBlank(id3.album)) {
  78. album = 'Unknown';
  79. }
  80. else {
  81. var em = document.createElement('em');
  82. em.textContent = id3.album;
  83. album = em.outerHTML;
  84. }
  85.  
  86. var songInfoHTML = title + ' by ' + artist + ' on ' + album + '. ';
  87.  
  88. songInfo.innerHTML = songInfoHTML;
  89. window.liID3.innerHTML = songInfoHTML;
  90.  
  91. var originalSongLink = getSongLinkByIndex(window.index);
  92.  
  93. // Create a song link to put in the last played list
  94.  
  95. var secondarySongLink = document.createElement('a');
  96. secondarySongLink.href = originalSongLink.href;
  97. secondarySongLink.textContent = '(' + originalSongLink.textContent + ')';
  98.  
  99. secondarySongLink.onclick = function(e) {
  100. e.preventDefault();
  101. originalSongLink.click();
  102. };
  103.  
  104. songLi.appendChild(songInfo);
  105. songLi.appendChild(secondarySongLink);
  106.  
  107. lastPlayedList.push(songLi);
  108. };
  109.  
  110. // Make sure the player information is the same as on the list due to timing issues
  111. setInterval(function() {
  112. window.liID3.innerHTML = lastPlayedList.currentSongInfo();
  113. }, 250);
  114.  
  115. // Add more buttons to the player interface
  116.  
  117. // The <audio> element
  118. var audio = window.tP.el;
  119.  
  120. var tPControls = document.querySelector('ul.tpControls');
  121.  
  122. var ffLi = document.createElement('li');
  123. ffLi.classList.add('ff');
  124.  
  125. // The player control buttons use Font Awesome icons
  126. var fastForwardButton = document.createElement('i');
  127. fastForwardButton.classList.add('fa', 'fa-fast-forward');
  128.  
  129. ffLi.style.marginLeft = '0.25em';
  130.  
  131. ffLi.appendChild(fastForwardButton);
  132. tPControls.appendChild(ffLi);
  133.  
  134. // Shuffle button uses a checkbox
  135. var shuffleLi = document.createElement('li');
  136. shuffleLi.classList.add('shuffle');
  137.  
  138. var shuffleButton = document.createElement('input');
  139. shuffleButton.setAttribute('type', 'checkbox');
  140.  
  141. var shuffleText = document.createTextNode('Shuffle?');
  142. shuffleLi.style.marginLeft = '1em';
  143.  
  144. shuffleLi.appendChild(shuffleText);
  145. shuffleLi.appendChild(shuffleButton);
  146. tPControls.appendChild(shuffleLi);
  147.  
  148. // The fast forward button triggers the 'ended' event on the audio player.
  149. fastForwardButton.addEventListener('click', function() {
  150. audio.dispatchEvent(new CustomEvent('ended'));
  151. });
  152.  
  153. audio.addEventListener('ended', function() {
  154. // Manually triggering a click event on the next song fixes an issue with updating the ID3 information.
  155. // This is a hack -- since Javascript doesn't provide an interface for removing the old event listeners,
  156. // I'll just wait 50ms to ensure mine runs last.
  157. // At this point, window.index has already been incremented, so currentSongLinkEl() will point to an unplayed song.
  158. setTimeout(function() {
  159. var nextSongIndex = shuffleButton.checked ? Math.floor(Math.random() * window.archiveAs.length) : window.index;
  160. getSongLinkByIndex(nextSongIndex).click();
  161. }, 50);
  162. });
  163. }());