TypeError: null is not an object (evaluating 'buttons.playPause.classList')

I got this error when I run the code, the bottom is inactive which I am unable to play anything. HERE ARE THE ERRORS

  1. this.playing = (new Set(buttons.playPause.classList).has(‘on’));

  2. const controls = new Controls();

'use strict';

/**
 * A music player ... cause why not.
 * Hotkeys:
 *   a - previous
 *   d / n - next
 *   s / p - play / pause
 *   e / r - repeat
 *   q - shuffle
 *
 * @author Holly Springsteen
 */

const colors = {
  aqua: {
    25: '#A7DCCD',
    50: '#5FBFA4',
    80: '#2F7561',
  },
  metal: {
    5: '#F3F3F1',
    20: '#CFD0C8',
    50: '#868975',
    80: '#36372F',
    90: '#272822',
  },
};

// Control button elements
const buttons = {
  shuffle: document.querySelector('#controls .shuffle'),
  previous: document.querySelector('#controls .previous'),
  playPause: document.querySelector('#controls .play-pause'),
  next: document.querySelector('#controls .next'),
  repeat: document.querySelector('#controls .repeat'),
};

// Range & Time elements
const songCurrentTime = document.querySelector('.song-current-time');
const songLength = document.querySelector('.song-length');
const trackingSlider = document.querySelector('.tracking-slider');
const volumeSlider = document.querySelector('.volume-slider');

// Art
const artPlayer = document.querySelector('#art .player');
const playerArt = document.querySelector('#art .player img');
const wideArt = document.querySelector('#art .wide img');

// Playlist
const playlistBody = document.querySelector('#playlist tbody');
let playlistPlay = document.querySelectorAll('#playlist .play-pause');
let listItems = document.querySelectorAll('#playlist tbdoy tr');

// Audio Element
const audio = document.getElementById('player');

// Base route for archive url
const archiveBase = 'http://archive.org/download/';

/**
 * A base list of songs and the meta data for them.
 *
{
  title: '',
  artist: '',
  duration: 0,
  album: {
    title: '',
    art: {
      square: '',
      wide: '',
    },
  },
  url: `${archiveBase}`,
},
 */
const songList = [
  {
    title: 'Lost On You',
    artist: 'LP',
    duration: 268,
    album: {
      title: 'Lost On You',
      art: {
        square: 'https://images.genius.com/bacae5471acb7b1a4ef445c92e049848.1000x1000x1.jpg',
        wide: 'https://i.ytimg.com/vi/boeuk8N_Gsw/maxresdefault.jpg',
      },
    },
    url: `${archiveBase}/LostOnYou_201610/Lost On You.mp3`,
  },
  {
    title: 'Bad Liar',
    artist: 'Selena Gomez',
    duration: 215,
    album: {
      title: 'Bad Liar',
      art: {
        square: 'http://coverlandia.net/sites/default/files/styles/music_artwork_page/public/artworks/music/231861497612215.jpg?itok=oX-DueHT',
        wide: 'http://www.idolator.com/wp-content/uploads/sites/10/2017/05/selena-gomez-bad-liar-single-cover.jpg',
      },
    },
    url: `${archiveBase}/01BadLiar/01 Bad Liar.mp3`,
  },
  {
    title: 'Shape of You',
    artist: 'Ed Sheeran',
    duration: 233,
    album: {
      title: '÷ (Divide)',
      art: {
        square: 'http://streamd.hitparade.ch/cdimages/ed_sheeran-%C3%B7_[divide]_a_1.jpg',
        wide: 'http://cdn2.hercampus.com/maxresdefault_0_34.jpg',
      },
    },
    url: `${archiveBase}/EdSheeranShapeOfYouOfficialLyricVideo.imack.co/Ed_Sheeran_-_Shape_Of_You_Official_Lyric_Video.imack_.co_.mp3`,
  },
  {
    title: 'Ride',
    artist: 'Twentry One Pilots',
    duration: 215,
    album: {
      title: 'Blurryface',
      art: {
        square: 'https://images-na.ssl-images-amazon.com/images/I/71Vl-qLrVtL._SL1203_.jpg',
        wide: 'https://garagemusicnews.files.wordpress.com/2015/05/gngxf0f.png',
      },
    },
    url: `${archiveBase}/Twenty_one_pilots_ride_/twenty_one_pilots_ride_(NaitiMP3.ru).mp3`,
  },
  {
    title: 'Set Fire to the Rain',
    artist: 'Adele',
    duration: 242,
    album: {
      title: '21',
      art: {
        square: 'http://fontmeme.com/images/21-by-Adele.jpg',
        wide: 'http://4.bp.blogspot.com/-TwEpqLGkEm0/T37Yb8-Fq4I/AAAAAAAAEBQ/aje5H832afw/s1600/adele+21+(1).jpg',
      },
    },
    url: `${archiveBase}/azeplaylist/Adele%20-%20Set%20Fire%20to%20the%20Rain%20Lyrics.mp3`,
  },
  {
    title: 'Girl on Fire',
    artist: 'Alicia Keys',
    duration: 225,
    album: {
      title: 'Girl on Fire',
      art: {
        square: 'http://hiphop-n-more.com/wp-content/uploads/2012/08/alicia-keys-girl-on-fire-single.jpg',
        wide: 'http://staticpopopics.popopics.com/uploads/original/alicia_keys_girl_on_fire-wallpaper-1920x1200.jpg',
      },
    },
    url: `${archiveBase}/azeplaylist/Alicia%20Keys%20-%20Girl%20On%20Fire%20%28Lyrics%29.mp3`,
  },
  {
    title: 'Swing, Swing',
    artist: 'The All American Rejects',
    duration: 233,
    album: {
      title: 'The All-American Rejects',
      art: {
        square: 'https://upload.wikimedia.org/wikipedia/en/a/a6/AAR-AAR.JPG',
        wide: 'http://s10.postimg.org/qjki5zf1l/The_All_American_Rejects_the_all_american_reject.jpg',
      },
    },
    url: `${archiveBase}/azeplaylist/All%20American%20Rejects%20-%20Swing%20Swing.mp3`,
  },
  {
    title: 'Jamie All Over',
    artist: 'Mayday Parade',
    duration: 216,
    album: {
      title: 'A Lesson in Romantics',
      art: {
        square: 'https://upload.wikimedia.org/wikipedia/en/5/53/Mpalircover.jpg',
        wide: 'http://fc08.deviantart.net/fs71/i/2012/347/3/b/a_lesson_in_romantics_1600x900_hd_wallpaper_by_cheapthrillsglmrklls-d5nypir.jpg',
      },
    },
    url: `${archiveBase}/azeplaylist/Mayday%20Parade%20-%20Jamie%20All%20Over.mp3`,
  },
  {
    title: 'Titanium',
    artist: 'David Guetta ft. Sia',
    duration: 245,
    album: {
      title: 'Nothing but the Beat',
      art: {
        square: 'http://4.bp.blogspot.com/-HJ1iG3uzVn8/TgSLn6uwRXI/AAAAAAAAAJg/qkaGRP4Lg2Q/s1600/David-Guetta-Nothing-But-The-Beat-Official-Album-Cover.jpg',
        wide: 'https://kssunews.files.wordpress.com/2011/08/davidguetta.jpg',
      },
    },
    url: `${archiveBase}/azeplaylist/David%20Guetta%20feat.%20Sia%20-%20Titanium.mp3`,
  },
];

/**
 * Based on the class list for a given element toggle the class(es) received.
 * Can accept both string with classes separated by spaces and an array of classes.
 *
 * @param {} element The dom element for which to toggle classes.
 * @param {string|string[]} classes The classes to be toggled on or off.
 */
function toggleClasses(element, classes) {
  const currentClasses = new Set(element.classList);
  // Separate string formatted classes into an array or accept array param
  const newClasses = (_.isString(classes)) ? classes.split(' ') : classes;

  for (const className of newClasses) {
    if (currentClasses.has(className)) {
      element.classList.remove(className);
    } else {
      element.classList.add(className);
    }
  }
}

/**
 * Toggle a boolean value.
 *
 * @param {boolean} boolean The boolean value to be toggled true or false.
 * @return {boolean} Returns the opposite boolean value to the received.
 */
function toggleBoolean(boolean) {
  return (!boolean);
}

/**
 * Convert seconds into a usable format for time.
 *
 * @param {number|string} seconds The amount of seconds to convert.
 * @return {string} Returns a time formatted string (--:--:--).
 */
function secondsToHms(seconds) {
  const time = {
    hours: String(Math.floor(Number(seconds) / 3600)),
    minutes: String(Math.floor(Number(seconds) % 3600 / 60)),
    seconds: String(Math.floor(Number(seconds) % 3600 % 60)),
  };

  if (time.hours && time.hours < 10) {
    time.hours = `0${time.hours}`;
  }
  if (time.minutes && time.minutes < 10) {
    time.minutes = `0${time.minutes}`;
  }
  if (time.seconds && time.seconds < 10) {
    time.seconds = `0${time.seconds}`;
  }

  if (time.hours !== '00') {
    return `${time.hours}:${time.minutes}:${time.seconds}`;
  } else {
    return `${time.minutes}:${time.seconds}`;
  }
}

/**
 * The base setup for any given audio player.
 */
class Player {
  constructor() {
    this.playing = (new Set(buttons.playPause.classList).has('on'));   (**FIRST ERROR**) :roll_eyes: :roll_eyes: :point_left:
    this.shuffle = (new Set(buttons.shuffle.classList).has('on'));
    this.repeat = (new Set(buttons.repeat.classList).has('on'));

    this.songIndex = 0;
    this.previousSong = songList.length - 1;

    this.song = songList[this.songIndex];

    this.randomOrder = new Set();
    this.randomIndex = 0;

    this.volume = 0.8;
  }

  /**
   * Update the meta data for the current song.
   *
   * @param {number} songIndex Optional param to force set the index of the song.
   */
  updateSong(songIndex) {
    this.previousSong = this.songIndex;
    this.songIndex = songIndex || this.songIndex;
    this.song = songList[this.songIndex];
    const song = this.song;

    audio.src = song.url;
    trackingSlider.value = 0;
    this.updateSongRangeValues();
    songLength.innerHTML = secondsToHms(song.duration);
    trackingSlider.max = song.duration;

    playerArt.src = song.album.art.square;
    wideArt.src = song.album.art.wide;

    document.querySelector(`tr[data-index="${this.previousSong}"]`).classList.remove('playing');
    toggleClasses(document.querySelector(`tr[data-index="${this.songIndex}"]`), 'playing');
  }

  /**
   * Play the audio.
   */
  play() {
    audio.play();
  }

  /**
   * Pause the audio.
   */
  pause() {
    audio.pause();
  }

  /**
   * Seek in the audio, update the time based on range value selected.
   */
  seek() {
    audio.currentTime = Number(trackingSlider.value);
    songCurrentTime.innerHTML = secondsToHms(audio.currentTime);
  }

  /**
   * Update the range values based on the current time in the song.
   */
  updateSongRangeValues() {
    const value = (trackingSlider.value / this.song.duration) * 100;
    const buffer = 0;

    songCurrentTime.innerHTML = secondsToHms(trackingSlider.value);

    trackingSlider.style.background = `linear-gradient(to right, ${colors.aqua[50]} 0%, ${colors.aqua[50]} ${value}%, ${colors.metal[50]} ${value}%, ${colors.metal[50]} ${buffer}%, ${colors.metal[80]} ${buffer}%, ${colors.metal[80]} 100%)`;
  }

  /**
   * Adjust the volume.
   */
  adjustVolume() {
    const {value} = volumeSlider;
    const buffer = 0;

    audio.volume = value;

    volumeSlider.style.background = `linear-gradient(to right, ${colors.aqua[80]} 0%, ${colors.aqua[80]} ${value * 100}%, ${colors.metal[50]} ${value * 100}%, ${colors.metal[50]} ${buffer}%, ${colors.metal[80]} ${buffer}%, ${colors.metal[80]} 100%)`;
  }
}

/**
 * The setup for any set of controls for the player.
 */
class Controls extends Player {
  /**
   * Play or pause the current list item.
   */
  playPause() {
    this.playing = toggleBoolean(this.playing);
    toggleClasses(buttons.playPause, 'on fa-play fa-pause');
    toggleClasses(artPlayer, 'playing');

    const currentClasses = new Set(buttons.playPause.classList);

    if (currentClasses.has('on')) {
      this.play();
    } else {
      this.pause();
    }
  }

  /**
   * Go to the next item in the list.
   */
  next() {
    this.previousSong = this.songIndex;
    let playNext = true;

    toggleClasses(document.querySelector(`tr[data-index="${this.songIndex}"]`), 'playing');

    if (this.shuffle) {
      this.randomIndex++;

      if (this.randomIndex >= this.randomOrder.size) {
        this.randomIndex = 0;

        playNext = (this.repeat);
      }

      this.songIndex = Array.from(this.randomOrder)[this.randomIndex];
    } else {
      this.songIndex++;

      if (this.songIndex >= songList.length) {
        this.songIndex = 0;

        playNext = (this.repeat);
      }
    }

    this.updateSong();

    if (this.playing) {
      if (playNext) {
        this.play();
      } else {
        this.playPause();
      }
    }
  }

  /**
   * Go to the previous item in the list.
   */
  previous() {
    toggleClasses(document.querySelector(`tr[data-index="${this.songIndex}"]`), 'playing');

    if (this.shuffle) {
      if (this.randomIndex === 0) {
        this.randomIndex = this.randomOrder.size;
      }
      this.randomIndex--;

      this.songIndex = Array.from(this.randomOrder)[this.randomIndex];
    } else {
      if (this.songIndex === 0) {
        this.songIndex = songList.length;
      }
      this.songIndex--;
    }

    this.updateSong();

    if (this.playing) {
      this.play();
    }
  }

  /**
   * Shuffle the list, play in a random order.
   */
  toggleShuffle() {
    this.shuffle = toggleBoolean(this.shuffle);
    toggleClasses(buttons.shuffle, 'on');
    const currentClasses = new Set(buttons.shuffle.classList);

    if (currentClasses.has('on')) {
      this.randomOrder = new Set();
      this.randomIndex = 0;

      let randomIndex = this.songIndex;

      for (let index = 0; index < songList.length; index++) {
        // While loop to ensure that the index being added to the random order is unique, else changes the index value
        while (this.randomOrder.has(randomIndex)) {
          randomIndex = Math.floor(Math.random() * songList.length);
        }

        this.randomOrder.add(randomIndex);
      }
    }
  }

  /**
   * Repeat/loop the list that is currently playing.
   */
  toggleRepeat() {
    this.repeat = toggleBoolean(this.repeat);
    toggleClasses(buttons.repeat, 'on');
  }
}


// Instantiate the controls
const controls = new Controls();

// Add event listeners for the buttons
buttons.playPause.addEventListener('click', () => {
  controls.playPause();
});
buttons.next.addEventListener('click', () => {
  controls.next();
});
buttons.previous.addEventListener('click', () => {
  controls.previous();
});
buttons.shuffle.addEventListener('click', () => {
  controls.toggleShuffle();
});
buttons.repeat.addEventListener('click', () => {
  controls.toggleRepeat();
});


audio.onended = () => {
  // Once a song is over play next song.
  controls.next();
};
audio.ontimeupdate = () => {
  trackingSlider.value = audio.currentTime;
  controls.updateSongRangeValues();
};

// Update the range values on change or moving the scrubber.
trackingSlider.addEventListener('change', () => {
  controls.updateSongRangeValues();
  controls.seek();
});
trackingSlider.addEventListener('mousemove', () => {
  controls.updateSongRangeValues();
});

volumeSlider.addEventListener('change', () => {
  controls.adjustVolume();
});
volumeSlider.addEventListener('mousemove', () => {
  controls.adjustVolume();
});

// That's right ... hotkeys!
document.onkeypress = (event) => {
  switch (event.keyCode) {
    // a - previous
    case 97: {
      controls.previous();
      break;
    }
    // d / n - next
    case 100:
    case 110: {
      controls.next();
      break;
    }
    // s / p - play / pause
    case 115:
    case 112: {
      controls.playPause();
      break;
    }
    // e / r - repeat
    case 101:
    case 114: {
      controls.toggleRepeat();
      break;
    }
    // q - shuffle
    case 113: {
      controls.toggleShuffle();
      break;
    }
  }
};


/**
 * Build the playlist from the give array of songs.
 */
function buildPlaylist() {
  // Add the songs to the dom
  let html = '';
  songList.forEach((song, index) => {
    html += `
<tr data-index="${index}">
  <td class="play-pause"><img src="${song.album.art.square}"></td>
  <td>${song.title}</td>
  <td>${song.artist}</td>
  <td>${song.album.title}</td>
  <td>${secondsToHms(song.duration)}</td>
</tr>
`;
  });
  playlistBody.innerHTML = html;

  // Update the list items
  listItems = document.querySelectorAll('#playlist tbody tr');
  playlistPlay = document.querySelectorAll('#playlist .play-pause');

  // Add event listeners to the list items
  for (const listItem of listItems) {
    listItem.addEventListener('click', (event) => {
      const songIndex = event.target.parentElement.dataset.index;
      controls.updateSong(songIndex);

      if (controls.playing) {
        controls.play();
      }
    });

    listItem.addEventListener('dblclick', (event) => {
      event.preventDefault();
      event.stopPropagation();

      if (!controls.playing) {
        controls.playPause();
      }
    });
  }
  
  for (const playlistPlayButton of playlistPlay) {
    playlistPlayButton.addEventListener('click', (event) => {
      if (!controls.playing) {
        controls.playPause();
      }
    });
  }
}


// Initiate the setup.
window.onload = () => {
  buildPlaylist();
  controls.updateSong();
  controls.adjustVolume();
};


<div class="key">
<section id="art">
  <div class="player">
    <img>
  </div>
  <div class="wide">
    <img>
  </div>
</section>

<section id="playlist">
  <table id="playlist" class="no-select">
    <thead>
      <th>&nbsp;</th>
      <th>Title</th>
      <th>Artist</th>
      <th>Album</th>
      <th><span class="fa fa-clock-o"></span></th>
    </thead>
    <tbody></tbody>
  </table>
</section>

<footer id="interactions">
  <div class="tracking-wrap">
    <span class="song-current-time">--:--</span>
    <input class="tracking-slider range" type="range" min="0" value="0" step="1">
    <span class="song-length">--:--</span>
  </div>

  <div class="controls-bar">
    <section id="controls">
      <span class="fa fa-random shuffle"></span>
      <span class="fa fa-fast-backward previous"></span>
      <span class="fa fa-play play-pause"></span>
      <span class="fa fa-fast-forward next"></span>
      <span class="fa fa-repeat repeat on"></span>
    </section>

    <div id="volume">
      <span class="fa fa-volume-down"></span>
      <input class="volume-slider range" type="range" max="1" min="0" step="0.01" value="0.8">
      <span class="fa fa-volume-up"></span>
    </div>
  </div>
</footer>

<audio id="player"></audio>
</div>