diff --git a/public/.htaccess b/public/.htaccess index 75af33bf9034953eaf23befe76359f3c2db2787c..a79cf040fd088ff9b786ac7fd6ea58411ba6ac4b 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 0000000000000000000000000000000000000000..c9cb32d2356f52c74e033d290ffd773aa4aabd9c --- /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 eefad3edb46ce9828932ce0ff71607744b96b9d0..222bb7b5ff095e87a7119d6ffe2d4851ee0ef081 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 7f9d2b256cb6e6a71340c8494af532075b56e398..327f8505cc3aa0871e6aee18dfb9ca58cff4143b 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 0000000000000000000000000000000000000000..fc4a6cb8672c77f06ff48c331a9411bc69bc247e --- /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 0000000000000000000000000000000000000000..9d6989d9b6abb9e6fc34f43724c9fd608a32c82f --- /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 cf03e1051f1db292037c9f8cd9d22bd5c7693953..19daa64d496a7e360be2d728647ec73ae5b7cc08 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 7d30e6484565028a35fe29618456ff6272a25010..2c7a75da32b6d5d30cb15aba8df4ec8a6d0124c8 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>