ptrharmonic / Bill Wurtz audio player

// ==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();