From f5ca31adf901347271f42e9c68db7faf4be3c15d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Thu, 4 Aug 2022 19:29:30 +0200
Subject: [PATCH] Add "now playing" page

---
 public/.htaccess         |  1 +
 public/access.inc.php    | 63 ++++++++++++++++++++++++++++++++++++++++
 public/css/styles.css    | 18 +++++++++++-
 public/index.php         | 63 ++--------------------------------------
 public/js/now-playing.js | 57 ++++++++++++++++++++++++++++++++++++
 public/playing.php       | 23 +++++++++++++++
 spotify/spotify.php      |  1 +
 template.php             | 25 ++++++++++++----
 8 files changed, 183 insertions(+), 68 deletions(-)
 create mode 100644 public/access.inc.php
 create mode 100644 public/js/now-playing.js
 create mode 100644 public/playing.php

diff --git a/public/.htaccess b/public/.htaccess
index 75af33b..a79cf04 100644
--- a/public/.htaccess
+++ b/public/.htaccess
@@ -1,3 +1,4 @@
 RewriteEngine On
 RewriteRule ^playlist-generator index.php [L,QSA]
 RewriteRule ^view-playlist-([^./]+)$ index.php?show-playlist=1&id=$1 [L,QSA]
+RewriteRule ^now-playing playing.php [L,QSA]
diff --git a/public/access.inc.php b/public/access.inc.php
new file mode 100644
index 0000000..c9cb32d
--- /dev/null
+++ b/public/access.inc.php
@@ -0,0 +1,63 @@
+<?php
+
+// increase timeout limit
+set_time_limit(60);
+
+require '../spotify/spotify.php';
+require '../spotify/lib.php';
+
+if (isset($_GET['logout'])) {
+    $_SESSION['accessToken'] = '';
+    $_SESSION['refreshToken'] = '';
+}
+
+$_SESSION['accessToken'] = isset($_SESSION['accessToken']) ? $_SESSION['accessToken'] : '';
+$_SESSION['refreshToken'] = isset($_SESSION['refreshToken']) ? $_SESSION['refreshToken'] : '';
+
+if (!$_SESSION['accessToken']) {
+    header('Location: auth.php');
+    die();
+}
+
+$session = new SpotifyWebAPI\Session($CLIENT_ID, $CLIENT_SECRET, $REDIRECT_URI);
+
+// Use previously requested tokens fetched from session
+if ($_SESSION['accessToken']) {
+    $session->setAccessToken($_SESSION['accessToken']);
+    $session->setRefreshToken($_SESSION['refreshToken']);
+} else {
+    // Or request a new access token
+    $session->refreshAccessToken($_SESSION['refreshToken']);
+}
+
+$options = [
+    'scope' => $SPOTIFY_REQUIRED_SCOPES,
+    'auto_refresh' => true,
+];
+
+$api = new SpotifyWebAPI\SpotifyWebAPI($options, $session);
+
+// Save new tokens, they might have been updated
+$_SESSION['accessToken'] = $session->getAccessToken();
+$_SESSION['refreshToken'] = $session->getRefreshToken();
+
+// ################################################################
+
+$user = [
+    'id' => '',
+    'image_url' => '',
+    'display_name' => '',
+    'profile_url' => '',
+];
+try {
+    $me = $api->me();
+
+    $user = [
+        'id' => $me->id,
+        'image_url' => \count($me->images) ? $me->images[0]->url : '',
+        'display_name' => $me->display_name,
+        'profile_url' => $me->external_urls->spotify,
+    ];
+} catch (Exception $ex) {
+	error_log($ex->getMessage());
+}
diff --git a/public/css/styles.css b/public/css/styles.css
index eefad3e..222bb7b 100644
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -11,10 +11,26 @@
     max-width: 1rem;
 }
 
-.spotify-image>img {
+.spotify-image > img {
     border: solid 1px #888;
     text-align: center;
     max-height: 1rem;
     max-width: 1rem;
     margin: auto;
 }
+
+.now-playing {
+    background-color: black;
+    color: white;
+}
+.now-playing-cover {
+    padding: 2em;
+}
+.now-playing-title {
+    padding-top: 4em;
+    font-size: 400%;
+    font-weight: bolder;
+}
+.now-playing-artists {
+    font-size: 200%;
+}
diff --git a/public/index.php b/public/index.php
index 7f9d2b2..327f850 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1,66 +1,6 @@
 <?php
 
-// increase timeout limit
-set_time_limit(60);
-
-require '../spotify/spotify.php';
-require '../spotify/lib.php';
-
-if (isset($_GET['logout'])) {
-    $_SESSION['accessToken'] = '';
-    $_SESSION['refreshToken'] = '';
-}
-
-$_SESSION['accessToken'] = isset($_SESSION['accessToken']) ? $_SESSION['accessToken'] : '';
-$_SESSION['refreshToken'] = isset($_SESSION['refreshToken']) ? $_SESSION['refreshToken'] : '';
-
-if (!$_SESSION['accessToken']) {
-    header('Location: auth.php');
-    die();
-}
-
-$session = new SpotifyWebAPI\Session($CLIENT_ID, $CLIENT_SECRET, $REDIRECT_URI);
-
-// Use previously requested tokens fetched from session
-if ($_SESSION['accessToken']) {
-    $session->setAccessToken($_SESSION['accessToken']);
-    $session->setRefreshToken($_SESSION['refreshToken']);
-} else {
-    // Or request a new access token
-    $session->refreshAccessToken($_SESSION['refreshToken']);
-}
-
-$options = [
-    'scope' => $SPOTIFY_REQUIRED_SCOPES,
-    'auto_refresh' => true,
-];
-
-$api = new SpotifyWebAPI\SpotifyWebAPI($options, $session);
-
-// Save new tokens, they might have been updated
-$_SESSION['accessToken'] = $session->getAccessToken();
-$_SESSION['refreshToken'] = $session->getRefreshToken();
-
-// ################################################################
-
-$user = [
-    'id' => '',
-    'image_url' => '',
-    'display_name' => '',
-    'profile_url' => '',
-];
-try {
-    $me = $api->me();
-
-    $user = [
-        'id' => $me->id,
-        'image_url' => \count($me->images) ? $me->images[0]->url : '',
-        'display_name' => $me->display_name,
-        'profile_url' => $me->external_urls->spotify,
-    ];
-} catch (Exception $ex) {
-	error_log($ex->getMessage());
-}
+require 'access.inc.php';
 
 $topArtistsCount = 40;
 $playlistsCount = 24;
@@ -74,6 +14,7 @@ $templateData = [
   'topArtists' => [],
   'playlist' => null,
 
+  'page' => 'playlist-generator',
   'infos' => [],
   'errors' => [],
 ];
diff --git a/public/js/now-playing.js b/public/js/now-playing.js
new file mode 100644
index 0000000..fc4a6cb
--- /dev/null
+++ b/public/js/now-playing.js
@@ -0,0 +1,57 @@
+function updateNowPlaying() {
+    var apiUrl = "now-playing?api";
+
+    var newContent = fetch(apiUrl)
+        .then(function (response) {
+            return response.json();
+        })
+        .then(function (data) {
+            var nowPlayingBlock = document.getElementById("now-playing");
+            newContent = buildNowPlayingBlock(data);
+            nowPlayingBlock.innerHTML = newContent;
+        })
+        .catch(function (err) {
+            console.warn("Something went wrong.", err);
+            newContent =
+                '<div class="alert alert-warning">Error fetching API data.<br/>You may need to logout and refresh page.</div>';
+            var nowPlayingBlock = document.getElementById("now-playing");
+            nowPlayingBlock.innerHTML = newContent;
+        });
+}
+
+function buildNowPlayingBlock(apiResponse) {
+    var html = `
+  <div class="container-fluid now-playing">
+    <div class="row">
+      <div class="col">
+        <div class="now-playing-cover"><img src="COVER_URL" class="img-fluid"></div>
+      </div>
+      <div class="col">
+        <div class="now-playing-title">TITLE</div>
+        <div class="now-playing-artists">ARTISTS</div>
+      </div>
+    </div>
+  </div>`;
+
+    var nowPlayingData = apiResponse["playing"];
+
+    if (!nowPlayingData) {
+        return '<div class="alert alert-info">No currently playing track...</div>';
+    }
+
+    var item = nowPlayingData["item"];
+    var album = item["album"];
+    var artists = album["artists"];
+
+    var artistNames = artists.map((artist) => artist["name"]).join(", ");
+    var trackName = item["name"];
+    var coverUrl = album["images"][0]["url"];
+
+    html = html.replace("TITLE", trackName);
+    html = html.replace("ARTISTS", artistNames);
+    html = html.replace("COVER_URL",  coverUrl);
+
+    return html;
+}
+
+setInterval(updateNowPlaying, 2000);
diff --git a/public/playing.php b/public/playing.php
new file mode 100644
index 0000000..9d6989d
--- /dev/null
+++ b/public/playing.php
@@ -0,0 +1,23 @@
+<?php
+
+require 'access.inc.php';
+
+$templateData = [
+    'user' => $user,
+
+    'page' => 'now-playing',
+    'infos' => [],
+    'errors' => [],
+];
+
+$callFromApi = isset($_GET['api']);
+if ($callFromApi) {
+    $nowPlaying = $api->getMyCurrentTrack();
+
+    $data = [
+        'playing' => $nowPlaying,
+    ];
+    echo json_encode($data);
+} else {
+    require '../template.php';
+}
diff --git a/spotify/spotify.php b/spotify/spotify.php
index cf03e10..19daa64 100644
--- a/spotify/spotify.php
+++ b/spotify/spotify.php
@@ -16,4 +16,5 @@ $SPOTIFY_REQUIRED_SCOPES = [
     'playlist-modify-public',
     'user-read-private',
     'user-top-read',
+    'user-read-currently-playing',
 ];
diff --git a/template.php b/template.php
index 7d30e64..2c7a75d 100644
--- a/template.php
+++ b/template.php
@@ -29,17 +29,23 @@
       <div class="collapse navbar-collapse" id="navbarNav">
         <ul class="navbar-nav">
           <li class="nav-item">
-            <a class="nav-link" href="<?php echo $templateData['user']['profile_url']; ?>">Profile</a>
+            <a class="nav-link<?php echo ($templateData['page'] === 'playlist-generator') ? ' active' : ''; ?>" href="/playlist-generator">🔀 Playlist generator</a>
           </li>
           <li class="nav-item">
-            <a class="nav-link" href="?logout">Logout</a>
+            <a class="nav-link<?php echo ($templateData['page'] === 'now-playing') ? ' active' : ''; ?>" href="/now-playing">🎧 Now playing</a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="<?php echo $templateData['user']['profile_url']; ?>">👤 Profile</a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="?logout">🚪 Logout</a>
           </li>
         </ul>
       </div>
     </div>
   </nav>
 
-  <div class="container-fluid mb-5">
+  <div class="container-fluid mb-5 mt-2">
 
     <?php if (count($templateData['errors'])) { ?>
       <?php foreach ($templateData['errors'] as $message) { ?>
@@ -53,7 +59,7 @@
       <?php } ?>
     <?php } ?>
 
-    <?php if (count($templateData['topArtists'])) { ?>
+    <?php if (array_key_exists('topArtists', $templateData) && count($templateData['topArtists'])) { ?>
       <form class="clearfix mt-2">
         <div class="row">
           <div class="col-md-12">
@@ -155,7 +161,7 @@
       </form>
     <?php } ?>
 
-    <?php if (count($templateData['playlists'])) { ?>
+    <?php if (array_key_exists('playlists', $templateData) && count($templateData['playlists'])) { ?>
       <form class="clearfix">
         <legend>Generate playlist from tracks in existing playlist:</legend>
         <ul class="list-unstyled row row-cols-md-2 row-cols-1">
@@ -214,7 +220,7 @@
       </form>
     <?php } ?>
 
-    <?php if ($templateData['playlist'] && count($templateData['playlist'])) { ?>
+    <?php if (array_key_exists('playlist', $templateData) && count($templateData['playlist'])) { ?>
       <div class="alert alert-info">
         <ul>
           <?php foreach ($templateData['playlist']['artists'] as $artist) { ?>
@@ -224,6 +230,13 @@
       </div>
     <?php } ?>
 
+    <?php if ($templateData['page'] === 'now-playing') { ?>
+      <div id="now-playing">
+        ⏳
+      </div>
+      <script src="js/now-playing.js"></script>
+    <?php } ?>
+
   </div>
 
   <script src="js/bootstrap.min.js"></script>
-- 
GitLab