{% extends 'base.html' %} {% block scripts %}
<link
  rel="stylesheet"
  href="{{  url_for('static', filename='screensaver.css') }}"
/>
<link
  rel="stylesheet"
  href="{{  url_for('static', filename='score.css') }}"
/>
<script>
  const isMediaPlaying = (media) =>
    !!(
      media.currentTime > 0 &&
      !media.paused &&
      !media.ended &&
      media.readyState > 2
    );

  function formatTime(seconds) {
    if (isNaN(seconds)) {
      return "00:00";
    }
    const totalSeconds = Math.floor(seconds);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const secs = totalSeconds % 60;
    const formattedMinutes = String(minutes).padStart(2, "0");
    const formattedSeconds = String(secs).padStart(2, "0");
    return `${formattedMinutes}:${formattedSeconds}`;
  }

  const isFirefox = typeof InstallTrigger !== "undefined";
  const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

  var socket = io();

  function connectSocket() {
    socket = io();
    socket.on('connect', function() {
        console.log('Socket connected');
    });
    socket.on('disconnect', function() {
        console.log('Socket disconnected');
    });
  }

  var mouseTimer = null,
    cursorVisible = true;

  var nowPlaying = {};
  var showMenu = false;
  var menuButtonVisible = false;
  var confirmationDismissed = false;
  var volume = 0.85;
  var isScoreShown = false;
  var hasBgVideo = "{{ has_bg_video }}" == 'True'

  const scoreReviews = {
	low:[
		"{{ _('Never sing again... ever.') }}", // {# MSG: Score review message #}
		"{{ _('That was a really good impression of a dying cat!') }}", // {# MSG: Score review message #}
		"{{ _('Thank God it\'s over.') }}", // {# MSG: Score review message #}
		"{{ _('Pass the mic, please!') }}", // {# MSG: Score review message #}
    "{{ _('Well, I\'m sure you\'re very good at your day job.') }}", // {# MSG: Score review message #}
  ],
	mid:[
		"{{ _('I\'ve seen better.') }}", // {# MSG: Score review message #}
		"{{ _('Ok... just ok.') }}", // {# MSG: Score review message #}
		"{{ _('Not bad for an amateur.') }}", // {# MSG: Score review message #}
		"{{ _('You put on a decent show.') }}", // {# MSG: Score review message #}
    "{{ _('That was... something.') }}", // {# MSG: Score review message #}
	],
	high:[
		"{{ _('Congratulations! That was unbelievable!') }}", // {# MSG: Score review message #}
		"{{ _('Wow, have you tried auditioning for The Voice?') }}", // {# MSG: Score review message #}
		"{{ _('Please, sing another one!') }}", // {# MSG: Score review message #}
		"{{ _('You rock! You know that?!') }}", // {# MSG: Score review message #}
		"{{ _('Woah, who let Freddie Mercury in here?') }}", // {# MSG: Score review message #}
	]
  }

  async function handleConfirmation() {
    $('#permissions-modal').removeClass('is-active');
    confirmationDismissed = true;
    if (hasBgVideo)  {
      playBGVideo(true);
    }
    playBGMusic(true);
  }

  function hideVideo() {
    $("#video-container").hide();
  }

  async function endSong(reason=null, showScore=false) {
    if (showScore && '{{ disable_score }}' == 'False') {
      isScoreShown = true;
		  await startScore("{{ url_for('static', filename='') }}");
      isScoreShown = false;
	  }
    hideVideo();
    socket.emit("end_song", reason);
  }

  function getBackgroundMusicPlayer() {
    return document.getElementById('background-music');
  }

  function getBackgroundVideoPlayer() {
    return document.getElementById('bg-video');
  }

  // A global array of the paths to mp3s for the background music playlist
  // it will be loaded from the /bg_playlist endpoint
  var bg_playlist = []

  // Gets the next song from the playlist, rotating back to the first song if at the end
  function getNextBgMusicSong() {
    let currentSong = getBackgroundMusicPlayer().getAttribute('src');
    let nextSong = bg_playlist[0];
    if (currentSong) {
      let currentIndex = bg_playlist.indexOf(currentSong);
      if (currentIndex >= 0 && currentIndex < bg_playlist.length - 1) {
        nextSong = bg_playlist[currentIndex + 1];
      }
    }
    return nextSong;
  }

  function getVideoPlayer() {
    return $("#video")[0]
  }

  // Plays or pauses the background music
  async function playBGMusic(play) {
	  let bgMusicVolume = "{{ bg_music_volume }}" *1 //hack to parse string to float;
	  if ('{{ disable_bg_music }}' == 'False') {
      let audio = getBackgroundMusicPlayer();
      if (bg_playlist.length == 0) {
        console.log('No background music playlist loaded');
        return;
      }
      if (!audio.getAttribute('src')) {
        audio.setAttribute('src', getNextBgMusicSong());
      }
      if (play == true) {
        if (isMediaPlaying(audio)) {
          return; // already playing
        }
        else {
          audio.volume = 0;
          if (audio.readyState <= 2) await audio.load(); // load the music first time
          await audio.play();
          $(audio).animate({ volume: bgMusicVolume }, 2000); // fade in 1 sec
        }
      } else {
        $(audio).animate({ volume: 0 }, 2000, () => audio.pause()); // fade out 1 sec
      }
    }
  }

  async function playBGVideo(play) {
    if ('{{ disable_bg_video }}' == 'False') {
      let bgVideo = getBackgroundVideoPlayer();
      const bgVideoContainer = $('#bg-video-container');
      if (play == true) {
        if (isMediaPlaying(bgVideo)) {
          return; // already playing
        }
        else {
          $("#bg-video").attr("src", "{{ url_for('stream.stream_bg_video') }}");
          if (bgVideo.readyState <= 2) await bgVideo.load(); // load the video first time
          bgVideo.play();
          bgVideoContainer.fadeIn(2000);
        }
      } else {
        if (isMediaPlaying(bgVideo)) {
          bgVideo.pause();
          bgVideoContainer.fadeOut(2000);
        }
      }
    }
  }

  // handle showing notifications
  function flashNotification(message, categoryClass) {
    const sn = $("#splash-notification");
    if (sn.html()) {
      console.log(sn.html());
      // dont clobber currently displayed notifications
      return;
    } else {
      sn.html(message);
      sn.addClass(categoryClass);
      sn.fadeIn();
      setTimeout(() => {
        sn.fadeOut();
        setTimeout(() => {
          // reset the notification after fade out animation
          sn.html("");
          sn.removeClass(categoryClass);
        }, 450);
      }, 3000);
    }
  }

  //handle screensaver idle loop
  var idleTime = 0;
  var screensaverTimeoutSeconds = parseInt('{{ screensaver_timeout }}') || 0;
  if (screensaverTimeoutSeconds > 0) {
    setInterval(() => {
      let screensaver = document.getElementById('screensaver');
      let video = getVideoPlayer();
      if (isMediaPlaying(video) || cursorVisible) {
        idleTime = 0; //reset idle timer on playback and mouse move
      }
      if (idleTime >= screensaverTimeoutSeconds) {
        if (screensaver.style.visibility == 'hidden') {
          screensaver.style.visibility = 'visible';
          playBGVideo(false);
          startScreensaver();
        }
        if (idleTime > screensaverTimeoutSeconds + 36000) {
          idleTime = screensaverTimeoutSeconds; //prevent overflow
        }
      }
      else { //stop screensaver
        if (screensaver.style.visibility == 'visible') {
          screensaver.style.visibility = 'hidden';
          stopScreensaver();
          if (!nowPlaying.up_next && !isMediaPlaying(video)) {
            playBGVideo(true);
          }
        }
      }
      idleTime++;
    }, 1000)
  }

  function handleNowPlaying(np) {
    console.log(np)
    nowPlaying = np;
    if (np.now_playing) {
      var nowPlayingHtml = `<span>${np.now_playing}</span> `;

      if (np.now_playing_transpose != 0) {
        nowPlayingHtml +=
          `<span class='is-size-6 has-text-success'><b>Key</b>: ${getSemitonesLabel(np.now_playing_transpose)} </span>`
      }

      $("#now-playing-song").html(nowPlayingHtml);
      $("#now-playing-singer").html(np.now_playing_user);
      $("#now-playing").fadeIn();
    } else {
      // {# MSG: Message which shows in the "Now Playing" section when there is no song currently playing #}
      $("#now-playing").fadeOut();
    }

    // Handle the Background music depending on the up_next and nowplaying status
    if (np.up_next) {
      idleTime = 0; // reset idle timer to clear screensaver
      playBGMusic(false);
      playBGVideo(false);
    } else if (!np.now_playing) {
      setTimeout(() => {
        playBGMusic(true);
        playBGVideo(true)
      }, 2000);
    }

    // render the queue details in top right
    if (np.up_next) {
      // {# MSG: Label for the next song to be played in the queue. #}
      up_next_text = "{{ _('Up next:') }}";
      // {# MSG: Label of the singer for next song to be played in the queue. (Who added it to the queue.) #}
      next_singer_text = "{{ _('Next singer:') }}";
      $("#up-next-song").html(np.up_next);
      $("#up-next-singer").html(np.next_user);
      $("#up-next").fadeIn();
    } else {
      $("#up-next").fadeOut();
    }

    const video = getVideoPlayer();

    // Start playback if a valid now_playing_url is provided
    if (
      np.now_playing_url &&
      !isMediaPlaying(video) &&
      $("#video-container").is(":hidden")
    ) {
      if (!confirmationDismissed) {
        console.log(
          'Browser is unable to play video. User did not confirm interaction prompt.'
        );
        endSong("interaction confirmation required");
      }
      $("#video-source").attr("src", np.now_playing_url);
      video.load();
      if (volume != np.volume) {
        volume = np.volume;
        video.volume = volume;
      }

      // show end time if available
      const duration = $("#duration");
      if (np.now_playing_duration) {
        duration.text(`/${formatTime(np.now_playing_duration)}`);
        duration.show();
      } else {
        duration.hide();
      }

      video.play();

      // handle timeout if video fails to play
      setTimeout(() => {
        if (!isMediaPlaying(video) && !video.paused) {
          endSong("failed to start");
        }
      }, 10000);
    }

  }

  function loadNowPlaying() {
    $.get('{{ url_for("now_playing.now_playing") }}', function (data) {
      handleNowPlaying(JSON.parse(data));
    });
  }

  // ** Post page load actions and event handlers **
  $(function () {
    $('#video-container').hide();

    if ('{{ hide_overlay }}' == 'True') {
      $('#bottom-container').hide();
      $('#top-container').hide();
    }

    //hide mouse cursor after 2 seconds of inactivity
    document.onmousemove = function () {
      if (mouseTimer) {
        window.clearTimeout(mouseTimer);
      }
      if (!cursorVisible) {
        document.body.style.cursor = 'default';
        cursorVisible = true;
      }
      if (!menuButtonVisible) {
        $("#menu a").fadeIn();
        menuButtonVisible = true;
      }
      mouseTimer = window.setTimeout(() => {
        mouseTimer = null;
        document.body.style.cursor = 'none';
        cursorVisible = false;
        $("#menu a").fadeOut();
        menuButtonVisible = false;
      }, 5000);
    };

    //Video status events for communicating state back to server
    const video = getVideoPlayer();
    video.addEventListener("play", () => {
      $("#video-container").show();
      //Report song start after a slight delay to allow video to load
      setTimeout(() => {
        socket.emit("start_song")
      }, 1200);
    });
    video.addEventListener("ended", () => {
      endSong("complete", true);
    });
    video.addEventListener("timeupdate", (e) => {
      $("#current").text(formatTime(video.currentTime));
    });

    $("#video source")[0].addEventListener("error", (e) => {
      console.log("Error while playing video.");
      console.log(e);
      endSong("error while playing");
    });

    // Load the background music playlist from server
    $.get('{{ url_for("bg_music.bg_playlist") }}', function (data) {
      if (data) bg_playlist = data;
    });

    // Add a listener to the background player to play the next song in the playlist
    const bgMusic = getBackgroundMusicPlayer();
    bgMusic.addEventListener("ended", async () => {
      bgMusic.setAttribute('src', getNextBgMusicSong());
      await bgMusic.load();
      await setTimeout(() => {}, 2500) // delay between songs
      await bgMusic.play();
    });

    //make sure we end the song if the user closes the window or leaves page
    window.addEventListener(
      'beforeunload',
      function (event) {
        if (isMediaPlaying(video)) {
          endSong("splash screen closed");
        }
      },
      true
    );

    //open menu iframe
    $('#menu a').click(function () {
      if (showMenu) {
        $('#menu-container').hide();
        $('#menu-container iframe').attr('src', '');
        showMenu = false;
      } else {
        setUserCookie();
        $("#menu-container").show();
        $("#menu-container iframe").attr("src", "/");
        showMenu = true;
      }
    });

    if (isFirefox || isSafari) {
      let modalContents = document.getElementById("permissions-modal-content");
      let warningMessage = document.createElement("p");
      warningMessage.classList.add("notification", "is-warning");
      warningMessage.innerHTML =
        "This browser is not fully supported. You may experience streaming issues unless you enable full playback buffering. Please use Chrome for best results.";
      modalContents.prepend(warningMessage);
    }

    let params = new URLSearchParams(window.location.search);
    let requireConfirmation = params.get('confirm');

    if (requireConfirmation === 'false') {
      let modal = document.getElementById('permissions-modal');
      modal.classList.remove('is-active');
      confirmationDismissed = true;
      playBGMusic(true);
      if (hasBgVideo)  {
        playBGVideo(true);
      }
    }

    socket.on('pause', () => {
      const video = getVideoPlayer();
      const currVolume = video.volume;
      if (!video.paused) {
        $(video).animate({ volume: 0 }, 1000, () => {
          video.pause();
          video.volume = currVolume;
        });
        console.log(`Pause`);
      }
    });

    socket.on('play', () => {
      const video = getVideoPlayer();
      const currVolume = video.volume;
      if (video.paused) {
        video.play();
        video.volume = 0;
        $(video).animate({ volume: currVolume }, 1000);
        console.log(`Play`);
      }
    });

    socket.on('skip', (reason) => {
      const video = getVideoPlayer();
      if (isMediaPlaying(video)) {
        const currVolume = video.volume;
        $(video).animate({ volume: 0 }, 1000, () => {
            video.pause();
            video.volume = currVolume;
            hideVideo();
          });
        console.log(`Skip: ${reason}`);
      }
    });

    socket.on('volume', (val) => {
      const video = getVideoPlayer();
      if (val == "up") {
        console.log(`Volume up`);
        video.volume = Math.min(1, video.volume + 0.1);
      } else if (val == "down") {
        console.log(`Volume down`);
        video.volume = Math.max(0, video.volume - 0.1);
      }
      else {
        console.log(`Volume: ${video.volume}`);
        video.volume = val;
      }
    });

    socket.on('restart', () => {
      console.log(`Restart`);
      const video = getVideoPlayer();
      video.currentTime = 0;
      if (video.paused) video.play()
    });

    socket.on("notification", (data) => {
      const notification = data.split("::");
      const message = notification[0];
      const categoryClass = notification.length > 1 ? notification[1] : "is-primary";
      flashNotification(message, categoryClass);
      socket.emit("clear_notification");
    });

    //for first time load of splash screen
    loadNowPlaying();

    //for socket pushed updates to now playing state
    socket.on("now_playing", np => handleNowPlaying(np));

    // reconnect socket / refresh if tab is hidden and then visible
    document.addEventListener("visibilitychange", function() {
      if (document.visibilityState === 'visible') {
        loadNowPlaying();
        if (!socket.connected) {
            console.log('Reconnecting socket...');
            connectSocket();
        }
      }
    });

  });
</script>
{% endblock %} {% block body %}

<div id="top-container" class="overlay">
  <div
    id="now-playing"
    class="has-text-warning stroke is-size-4 has-text-right"
    style="display: none"
  >
    <p
      id="now-playing-song"
      class="has-text-white"
      style="margin-bottom: 5px"
    ></p>
    <div class="has-text-success">
      <span class="timestamp is-size-6">
        <span id="current">00:00</span><span id="duration">/00:00</span></span></span
      >&nbsp;&nbsp;<i class="icon icon-mic-1" title="Current singer"></i>&nbsp;
      <span id="now-playing-singer"></span>
    </div>
  </div>
</div>

<div id="logo-container">
  <div>
    <img class="logo" src="{{ url_for('images.logo') }}" width="500px" alt="logo" />
  </div>
</div>

<div id="ap-container">
  <div class="is-size-6 stroke">
    <div id="hostap">
      {% for line in hostap_info %}{{ line }}<br />{% endfor %}
    </div>
  </div>
</div>

<div id="bottom-container" class="overlay">
  {% if not hide_url %}
  <div id="qr-code">
    <img
      src="{{ url_for('images.qrcode') }}"
      width="100px"
      style="image-rendering: pixelated"
      alt="qrcode"
    />
    <div class="is-size-6 stroke">
      <div>&nbsp;{{ url }}</div>
    </div>
  </div>
  {% endif %}
  <div></div>
  <div
    id="up-next"
    class="has-text-warning is-size-5 stroke has-text-right"
    style="display: none"
  >
    <b class="has-text-white"
      >{# MSG: Label for the next song to be played in the queue. #} {% trans
      %}Up next:{% endtrans %}
    </b>
    <span id="up-next-song"></span>
    <div class="has-text-success">
      <b class="has-text-white"
        >{# MSG: Label for the next singer in the queue. #}
        {% trans %}Next singer:{% endtrans %} </b
      >&nbsp;<i class="icon icon-mic-1" title="Next singer"></i
      ><span id="up-next-singer"></span>
    </div>
  </div>
</div>

<div id="video-container" class="video-container">
  <video id="video" disableRemotePlayback>
    <source id="video-source" type="video/mp4" src="" />
  </video>
</div>

<div id="bg-video-container" class="video-container">
  <video id="bg-video" disableRemotePlayback muted loop style="object-fit: cover">
    <source id="video-source" type="video/mp4" src="" />
  </video>
</div>

<div id="score" style="display: none">
	<div id="your-score-text">
    {# MSG: The title of the score screen, telling the user their singing score #}
		{% trans %}Your Score{% endtrans %}
	</div>
	<div id="score-number-text">
	</div>
	<div id="score-review-text">
	</div>
	<canvas id="fireworks"></canvas>
</div>

<div id="permissions-modal" class="modal is-active">
  <div class="modal-background"></div>
  <div class="modal-content" id="permissions-modal-content">
    <p>
      {# MSG: Prompt for interaction in order to enable video autoplay. #} {%
      trans %}Due to limititations with browser permissions, you must interact
      with the page once before it allows autoplay of videos. Pikaraoke will not
      play otherwise. Click the button below to
      <a onClick="handleConfirmation()">confirm</a> .{% endtrans %}
    </p>
    <div class="has-text-centered">
      <button
        id="permissions-button"
        class="button is-success"
        style="margin-top: 10px"
        onClick="handleConfirmation()"
      >
        {# MSG: Button to confirm to enable video autoplay. #} {% trans
        %}Confirm{% endtrans %}
      </button>
    </div>
  </div>
</div>

<div id="menu">
  <a
    role="button"
    class="navbar-burger"
    aria-label="menu"
    aria-expanded="false"
    data-target="navbarBasicExample"
    style="display: block; width: 20px; height: 30px"
  >
    <span aria-hidden="true"></span>
    <span aria-hidden="true"></span>
    <span aria-hidden="true"></span>
  </a>
</div>
<div id="menu-container" class="">
  <iframe src="/"></iframe>
</div>

<!-- Notification code -->
<div
  id="splash-notification"
  class="notification overlay"
  style="display: none"
></div>

<!-- Screensaver code -->
 <div class="fw-fh-container">
  <div id="screensaver" style="visibility: hidden">
    <div id="dvd">
      {% if not hide_url %}
      <div>
        <div style="text-align: right">
          <img src="{{ url_for('images.qrcode') }}" width="30%" height="30%" />
        </div>
        <div>{{ hostap_info[0] }}<br />{{ url }}</div>
      </div>
      {% endif %}
    </div>
  </div>
</div>

<audio id="background-music">
  <source src="" type="audio/mpeg">
</audio>

<audio id="score-drums">
	<source
	  src="{{  url_for('static', filename='sounds/score-drums.mp3') }}"
	  type="audio/mp3"
	/>
</audio>

<script src="{{  url_for('static', filename='screensaver.js') }}"></script>
<script src="{{  url_for('static', filename='fireworks.js') }}"></script>
<script src="{{  url_for('static', filename='score.js') }}"></script>

<style>
  html {
    overflow-y: hidden;
  }
  body {
    background-color: black;
  }
  #top-container,
  #ap-container,
  #bottom-container {
    position: absolute;
    z-index: 1;
    padding: 10px 20px;
  }
  #top-container {
    top: 0px;
    right: 0px;
    max-width: 75%;
  }
  #ap-container {
    top: 0px;
    left: 0px;
    max-width: 50%;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
  }
  #bottom-container {
    bottom: 0px;
    left: 0px;
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
  }
  #qr-code {
    max-width: 25%;
  }
  #up-next {
    max-width: 75%;
  }
  .video-container {
    position: absolute;
    z-index: 2;
    top: 0;
    width: 100vw;
    height: 100vh;
    background-color: black;
    display: flex;
    align-items: center;
  }
  #bg-video-container {
    z-index: 0;
    width: 100vw;
    height: 100vh;
  }
  video {
    height: 100%;
    width: 100%;
    object-fit: contain;
  }
  body {
    background-color: black;
  }
  .fw-fh-container {
    height: 100vh;
    width: 100vw;
  }
  #logo-container {
    position: absolute;
    z-index: 1;
    display: flex;
    width: 100vw;
    height: 100vh;
    align-items: center;
    justify-content: center;
  }
  #menu {
    position: absolute;
    z-index: 5;
    top: 10px;
    left: 20px;
  }
  #menu-container {
    position: absolute;
    z-index: 3;
    top: 40px;
    left: 20px;
    display: none;
    overflow: hidden;
  }
  #menu-container iframe {
    width: 600px;
    height: 75vh;
  }
  .visible {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.5s linear;
  }
  .hidden {
    visibility: hidden;
    opacity: 0;
    transition: visibility 0s 0.5s, opacity 0.5s linear;
  }
  .overlay {
    z-index: 3 !important;
  }
  .stroke {
    text-shadow: 2px 0.75px black;
  }
  .timestamp {
    font-family: monospace;
  }
  #splash-notification {
    position: absolute;
    top: 15px;
    left: 50px;
    z-index: 6;
    padding: 5px 10px;
    max-width: 450px;
  }
</style>

{% endblock %}
