NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Bill Wurtz audio player // @version 1.0.1 // @grant none // @include https://billwurtz.com/songs.html // @include https://billwurtz.com/videos.html // @include https://billwurtz.com/expert.html // @copyright 2019-2020, ptrharmonic (https://openuserjs.org/users/ptrharmonic) // @license MIT // @downloadURL https://openuserjs.org/install/ptrharmonic/Bill_Wurtz_audio_player.min.user.js // @updateURL https://openuserjs.org/meta/ptrharmonic/Bill_Wurtz_audio_player.meta.js // ==/UserScript== // Init vars let table; let audio_container; let controls; let hiddenSongsButton; let mode = 0; // 1: Songs, 2: Video, 3: Expert // Init styles let styles = document.createElement("style"); styles.type = 'text/css'; let head = document.getElementsByTagName('head')[0]; head.appendChild(styles); styles.innerHTML = "video, iframe { max-width: calc(100vw - 30px); max-height: 100vh; width: 100%}"; // Determine which page loaded and setup accordingly let path = window.location.pathname; switch (path) { case "/songs.html": generalSetup(songsSetup); break; case "/videos.html": generalSetup(videosSetup); break; case "/expert.html": generalSetup(expertSetup); break; default: break; } function songsSetup() { table = document.getElementsByTagName('table')[1]; table.parentNode.appendChild(audio_container); table.parentNode.appendChild(controls); } function videosSetup() { table = document.getElementsByTagName('table')[0]; table.parentNode.insertBefore(audio_container, table); table.parentNode.appendChild(controls); } function expertSetup() { table = document.getElementsByTagName('table')[2]; table.parentNode.insertBefore(audio_container, table); table.parentNode.appendChild(controls); } function generalSetup(setupFunc) { audio_container = document.createElement('div'); audio_container.id = "audio-container"; controls = document.createElement('div'); setupFunc(); } let hiddenSongs = false; function linkSongCallbacks() { // Link up the callbacks for link clicks for (var i = 0, row; row = table.rows[i]; i++) { //iterate through rows //rows would be accessed using the "row" variable assigned in the for loop let link_cell = row.cells[1]; // If row has a second cell... if (link_cell) { if (link_cell.children.length) { // Get the <a> under it and link the callback let link = link_cell.children[0]; if (link.tagName == "A") { link.dataset.row_number = i; link.onclick = onClick; } } } } } function createControls() { hiddenSongsButton = document.createElement("button"); hiddenSongsButton.textContent = "Enable Hidden Content"; hiddenSongsButton.onclick = enableHiddenSongs; console.log(hiddenSongsButton); controls.appendChild(hiddenSongsButton); } function enableHiddenSongs() { // Link up the callbacks for link clicks let tbody = table.children[0]; function filterNone() { return NodeFilter.FILTER_ACCEPT; } let nodeIterator = document.createNodeIterator(tbody, NodeFilter.SHOW_ALL, filterNone); let i = 0; let row; let lastRow; while (row = nodeIterator.nextNode()) { if (row.nodeType == Node.COMMENT_NODE) { let text = row.textContent; text = text.replaceAll("<tr", "<tr style='background: yellow;'"); lastRow.insertAdjacentHTML('afterend', text); } else if (row.nodeType == Node.ELEMENT_NODE) { if (row.tagName == "TR") { lastRow = row; } } i++; } linkSongCallbacks(); hiddenSongsButton.remove(); } // Callback for when a song link is clicked to start playing it function onClick(event) { event.preventDefault(); audio_container.innerHTML = ''; play(table, parseInt(this.dataset.row_number)); } function startPlayingAudio(link, row_number) { // Remake audio player element audio_container.innerHTML = '<audio controls autoplay><source src=' + link + ' type="audio/mp3"></audio>'; let audio_player = audio_container.children[0]; // When the player ends, play the next newest song audio_player.onended = function () { // Song ended, play next one play(table, row_number - 1); }; let source = audio_player.children[0]; source.onerror = function() { // Song can't be loaded (like happy birthday.mp3), just go to the next one play(table, row_number - 1); }; audio_player.play(); } function startPlayingVideo(link, row_number) { // Remake audio player element audio_container.innerHTML = '<video controls autoplay><source src=' + link + ' type="video/mp4"></video>'; let audio_player = audio_container.children[0]; // When the player ends, play the next newest song audio_player.onended = function () { // Song ended, play next one play(table, row_number - 1); }; source = audio_player.children[0]; source.onerror = function() { // Song can't be loaded (like happy birthday.mp3), just go to the next one play(table, row_number - 1); }; audio_player.play(); } function startPlayingOther(link, row_number) { // Fix http:// links to get past mixed content blocking // Remake audio player element audio_container.innerHTML = '<iframe src="' + link.replace("http://", "https://") + '"></iframe><button>Next</button>'; let button = audio_container.children[1]; // When the player ends, play the next newest song button.onclick = function () { // Song ended, play next one play(table, row_number - 1); }; } function play(table, row_number) { console.log('starting playback', row_number); if (table.rows.length < row_number - 1) { return; } let row = table.rows[row_number]; //iterate through rows //rows would be accessed using the "row" variable assigned in the for loop let link_cell = row.cells[1]; if (link_cell) { let link = link_cell.children[0].attributes['href'].nodeValue; if (link.slice(link.length - 3) == "mp3") { startPlayingAudio(link, row_number); } else if (link.slice(link.length - 3) == "mp4") { startPlayingVideo(link, row_number); } else { startPlayingOther(link, row_number); } } else { play(table, row_number - 1); } } linkSongCallbacks(); createControls();