diff --git a/NathanWoodburn.bsdesign b/NathanWoodburn.bsdesign index 4a43a7f..1cb8339 100644 Binary files a/NathanWoodburn.bsdesign and b/NathanWoodburn.bsdesign differ diff --git a/blueprints/spotify.py b/blueprints/spotify.py index 8236891..48e326f 100644 --- a/blueprints/spotify.py +++ b/blueprints/spotify.py @@ -1,5 +1,5 @@ -from flask import redirect, request, Blueprint, url_for -from tools import json_response +from flask import redirect, render_template, request, Blueprint, url_for +from tools import json_response, isCLI import os import requests import time @@ -105,7 +105,11 @@ def callback(): def currently_playing(): """Public endpoint showing your current track.""" track = get_playing_spotify_track() - return json_response(request, {"spotify": track}, 200) + if isCLI(request): + return json_response(request, {"spotify": track}, 200) + + # Render a simple HTML page for browsers + return render_template("spotify.html", track=track) def get_playing_spotify_track(): @@ -117,7 +121,6 @@ def get_playing_spotify_track(): headers = {"Authorization": f"Bearer {token}"} response = requests.get(SPOTIFY_CURRENTLY_PLAYING_URL, headers=headers) if response.status_code == 204: - # return {"error": "Nothing is currently playing."} return get_last_spotify_track() elif response.status_code != 200: return {"error": "Spotify API error", "status": response.status_code} @@ -125,7 +128,6 @@ def get_playing_spotify_track(): data = response.json() if not data.get("item"): return {"error": "Nothing is currently playing."} - track = { "song_name": data["item"]["name"], "artist": ", ".join([artist["name"] for artist in data["item"]["artists"]]), @@ -134,6 +136,8 @@ def get_playing_spotify_track(): "is_playing": data["is_playing"], "progress_ms": data.get("progress_ms", 0), "duration_ms": data["item"].get("duration_ms", 1), + "url": data["item"]["external_urls"]["spotify"], + "id": data["item"]["id"], } return track @@ -160,6 +164,18 @@ def get_last_spotify_track(): "artist": ", ".join([artist["name"] for artist in last_track_info["artists"]]), "album_name": last_track_info["album"]["name"], "album_art": last_track_info["album"]["images"][0]["url"], + "is_playing": False, + "progress_ms": 0, + "duration_ms": last_track_info.get("duration_ms", 1), "played_at": data["items"][0]["played_at"], + "url": last_track_info["external_urls"]["spotify"], + "id": last_track_info["id"], } return track + + +@app.route("/last") +def last_played(): + """Public endpoint showing your last played track.""" + track = get_last_spotify_track() + return json_response(request, {"spotify": track}, 200) diff --git a/templates/assets/css/styles.min.css b/templates/assets/css/styles.min.css index 1d73a33..a6b2c86 100644 --- a/templates/assets/css/styles.min.css +++ b/templates/assets/css/styles.min.css @@ -1 +1 @@ -:root,[data-bs-theme=light]{--bs-primary:#6E0E9C;--bs-primary-rgb:110,14,156;--bs-primary-text-emphasis:#2C063E;--bs-primary-bg-subtle:#E2CFEB;--bs-primary-border-subtle:#C59FD7;--bs-link-color:#6E0E9C;--bs-link-color-rgb:110,14,156;--bs-link-hover-color:#a41685;--bs-link-hover-color-rgb:164,22,133}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#6E0E9C;--bs-btn-border-color:#6E0E9C;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5E0C85;--bs-btn-hover-border-color:#580B7D;--bs-btn-focus-shadow-rgb:233,219,240;--bs-btn-active-color:#fff;--bs-btn-active-bg:#580B7D;--bs-btn-active-border-color:#530B75;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6E0E9C;--bs-btn-disabled-border-color:#6E0E9C}.btn-outline-primary{--bs-btn-color:#6E0E9C;--bs-btn-border-color:#6E0E9C;--bs-btn-focus-shadow-rgb:110,14,156;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6E0E9C;--bs-btn-hover-border-color:#6E0E9C;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6E0E9C;--bs-btn-active-border-color:#6E0E9C;--bs-btn-disabled-color:#6E0E9C;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6E0E9C} \ No newline at end of file +:root,[data-bs-theme=light]{--bs-primary:#6E0E9C;--bs-primary-rgb:110,14,156;--bs-primary-text-emphasis:#2C063E;--bs-primary-bg-subtle:#E2CFEB;--bs-primary-border-subtle:#C59FD7;--bs-link-color:#6E0E9C;--bs-link-color-rgb:110,14,156;--bs-link-hover-color:#a41685;--bs-link-hover-color-rgb:164,22,133}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#6E0E9C;--bs-btn-border-color:#6E0E9C;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5E0C85;--bs-btn-hover-border-color:#580B7D;--bs-btn-focus-shadow-rgb:233,219,240;--bs-btn-active-color:#fff;--bs-btn-active-bg:#580B7D;--bs-btn-active-border-color:#530B75;--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6E0E9C;--bs-btn-disabled-border-color:#6E0E9C}.btn-outline-primary{--bs-btn-color:#6E0E9C;--bs-btn-border-color:#6E0E9C;--bs-btn-focus-shadow-rgb:110,14,156;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6E0E9C;--bs-btn-hover-border-color:#6E0E9C;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6E0E9C;--bs-btn-active-border-color:#6E0E9C;--bs-btn-disabled-color:#6E0E9C;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6E0E9C}.no-title{text-transform:none!important}.spotify-icon{cursor:pointer} \ No newline at end of file diff --git a/templates/assets/js/spotify.min.js b/templates/assets/js/spotify.min.js new file mode 100644 index 0000000..4c2fb58 --- /dev/null +++ b/templates/assets/js/spotify.min.js @@ -0,0 +1 @@ +let progressInterval=null,progressSpeed=0,lastUpdateTime=Date.now(),currentProgress=0,targetProgress=0,trackDuration=0,currentTrackId=null,trackurl=null;async function updateSpotifyWidget(){try{const e=await fetch("/api/v1/playing");if(!e.ok)return;const n=await e.json();if(n.error||n.message){if(document.getElementById("spotify-song").textContent)return;return document.getElementById("spotify-album-art").src="/assets/img/external/spotify.png",document.getElementById("spotify-album-art").style.cursor="default",document.getElementById("spotify-song").textContent="Not Playing",document.getElementById("spotify-artist").textContent="",document.getElementById("spotify-album").textContent="",document.getElementById("spotify-icon-playing").style.display="none",document.getElementById("spotify-icon-paused").style.display="none",document.getElementById("spotify-icon-stopped").style.display="inline",updateProgressBar(0,1),clearInterval(progressInterval),progressInterval=null,currentProgress=0,currentTrackId=null,void(trackurl=null)}const r=n.spotify;var t=!1;document.getElementById("spotify-song").textContent||(t=!0);const o=r.song_name+r.artist;null!==currentTrackId&¤tTrackId!==o&&(currentProgress=0,document.getElementById("spotify-progress").style.transition="none",document.getElementById("spotify-progress").style.width="0%",document.getElementById("spotify-progress").offsetHeight,document.getElementById("spotify-progress").style.transition="width 0.1s linear"),currentTrackId=o,trackurl=r.url,document.getElementById("spotify-album-art").src=r.album_art,document.getElementById("spotify-album-art").style.cursor="pointer",document.getElementById("spotify-song").textContent=r.song_name,document.getElementById("spotify-artist").textContent=r.artist,document.getElementById("spotify-album").textContent=r.album_name,r.is_playing?(currentProgress=r.progress_ms,trackDuration=r.duration_ms,lastUpdateTime=Date.now(),updateProgressBar(r.progress_ms,r.duration_ms),progressInterval&&clearInterval(progressInterval),progressInterval=setInterval(animateProgressBar,10),document.getElementById("spotify-icon-playing").style.display="inline",document.getElementById("spotify-icon-paused").style.display="none",document.getElementById("spotify-icon-stopped").style.display="none"):(updateProgressBar(r.progress_ms,r.duration_ms),clearInterval(progressInterval),progressInterval=null,currentProgress=r.progress_ms,trackDuration=r.duration_ms,document.getElementById("spotify-icon-playing").style.display="none",document.getElementById("spotify-icon-paused").style.display="inline",document.getElementById("spotify-icon-stopped").style.display="none"),t&&updateVisibility()}catch(t){console.error("Failed to fetch Spotify data",t)}}function updateProgressBar(t,e){if(0===e)return;const n=t/e*100,r=document.getElementById("spotify-progress");r.style.width=n+"%",r.setAttribute("aria-valuenow",t),r.setAttribute("aria-valuemax",e),r.setAttribute("aria-valuemin",0)}function animateProgressBar(){if(!trackDuration)return;const t=Date.now(),e=t-lastUpdateTime;if(lastUpdateTime=t,currentProgress+=e,currentProgress>trackDuration)return clearInterval(progressInterval),void updateSpotifyWidget();updateProgressBar(currentProgress,trackDuration)}updateSpotifyWidget(),setInterval(updateSpotifyWidget,5e3),document.getElementById("spotify-album-art").onclick=()=>{trackurl&&window.open(trackurl,"_blank")},document.getElementById("spotify-icon-playing").onclick=()=>{trackurl&&window.open(trackurl,"_blank")},document.getElementById("spotify-icon-paused").onclick=()=>{trackurl&&window.open(trackurl,"_blank")},document.getElementById("spotify-icon-stopped").onclick=()=>{trackurl&&window.open(trackurl,"_blank")}; \ No newline at end of file diff --git a/templates/spotify.html b/templates/spotify.html new file mode 100644 index 0000000..e85d8dc --- /dev/null +++ b/templates/spotify.html @@ -0,0 +1,103 @@ + + + + + + + Currently Listening | Nathan.Woodburn/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+

Spotify

+
+
+
+
+
+
+
+
+
Album Art
+
+
+ +
+

{{ track.song_name }}

+

{{ track.artist }}

+

{{ track.album_name }}

+
+
+
+
+
+ + + + + + + + + \ No newline at end of file