From cf59dbeaf754ee8c93f72f66aa8d3b8028a2e274 Mon Sep 17 00:00:00 2001 From: novatorem Date: Sat, 15 Aug 2020 22:22:39 -0400 Subject: [PATCH] Dynamic readme --- .gitignore | 5 ++ README.md | 5 ++ SetUp.md | 44 ++++++++++++ api/requirements.txt | 3 + api/spotify-playing.py | 120 +++++++++++++++++++++++++++++++++ api/templates/preview.html | 106 +++++++++++++++++++++++++++++ api/templates/spotify.html.j2 | 122 ++++++++++++++++++++++++++++++++++ 7 files changed, 405 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 SetUp.md create mode 100644 api/requirements.txt create mode 100644 api/spotify-playing.py create mode 100644 api/templates/preview.html create mode 100644 api/templates/spotify.html.j2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..634f63e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +venv +__pycache__ +.cache* +env +.env \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b51624c --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +Aphelion | Perihelion +:-------------------------:|------- +                                                                                              [![Spotify](https://novatorem.vercel.app/api/spotify-playing)](https://open.spotify.com/user/omnitenebris)
|
Software Developer currently working on cool projects at [Cast](https://blacktrax.cast-soft.com/showcase/). Everything here is under the MIT License, [info here](https://choosealicense.com/licenses/mit/)!

[![Website](https://img.shields.io/badge/website-dev-2a8?style=flat-square&logo=safari&logoColor=white)](https://novac.dev) [![E-Mail](https://img.shields.io/badge/email-reveal-369?style=flat-square&logo=gmail&logoColor=white)](https://mailhide.io/e/5ck1H)
[![Spotify](https://img.shields.io/badge/spotify-omni-1DB954?style=flat-square&logo=spotify&logoColor=white)](https://open.spotify.com/user/omnitenebris) [![Visits](https://badges.pufler.dev/visits/novatorem/novatorem?logo=GitHub&label=github%20visits&color=blue&logoColor=white&style=flat-square)](https://github.com/novatorem)

+ +[//]: <> (The ` ` is to have Aphelion take up more space) diff --git a/SetUp.md b/SetUp.md new file mode 100644 index 0000000..182a394 --- /dev/null +++ b/SetUp.md @@ -0,0 +1,44 @@ +# Set Up Guide + +## Spotify + +* Create a [Spotify Application](https://developer.spotify.com/dashboard/applications) +* Put aside: + * `Client ID` + * `Client Secret` +* Click on **Edit Settings** +* In **Redirect URIs**: + * Add `http://localhost/callback/` + +## Refresh Token + +* Navigate to the following URL: + +``` +https://accounts.spotify.com/authorize?client_id={SPOTIFY_CLIENT_ID}&response_type=code&scope=user-read-currently-playing,user-read-recently-played&redirect_uri=http://localhost/callback/ +``` + +* After logging in, save the {CODE} portion of: `http://localhost/callback/?code={CODE}` + +* Create a string combining `{SPOTIFY_CLIENT_ID}:{SPOTIFY_CLIENT_SECRET}` (e.g. `5n7o4v5a3t7o5r2e3m1:5a8n7d3r4e2w5n8o2v3a7c5`) and encode into [Base64](https://www.base64encode.org/). + +* Then run a [curl command](https://httpie.org/run) in the form of: +```sh +curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: Basic {BASE64}" -d "grant_type=authorization_code&redirect_uri=http://localhost/callback/&code={CODE}" https://accounts.spotify.com/api/token +``` + +* Save the Refresh token + +## Vercel + +* Register on [Vercel](https://vercel.com/) + +* Create project linked to your github repo + +* Add System Variables: + * `https://vercel.com///settings/environment-variables` + * `SPOTIFY_REFRESH_TOKEN` + * `SPOTIFY_CLIENT_ID` + * `SPOTIFY_SECRET_ID` + +* Deploy! diff --git a/api/requirements.txt b/api/requirements.txt new file mode 100644 index 0000000..4b21b4d --- /dev/null +++ b/api/requirements.txt @@ -0,0 +1,3 @@ +flask==1.1.2 +requests==2.24.0 +python-dotenv==0.14.0 \ No newline at end of file diff --git a/api/spotify-playing.py b/api/spotify-playing.py new file mode 100644 index 0000000..fd98229 --- /dev/null +++ b/api/spotify-playing.py @@ -0,0 +1,120 @@ +from flask import Flask, Response, jsonify, render_template +from base64 import b64encode + +from dotenv import load_dotenv, find_dotenv +load_dotenv(find_dotenv()) + +import requests +import json +import os +import random + +SPOTIFY_CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID") +SPOTIFY_SECRET_ID = os.getenv("SPOTIFY_SECRET_ID") +SPOTIFY_REFRESH_TOKEN = os.getenv("SPOTIFY_REFRESH_TOKEN") + +# scope user-read-currently-playing/user-read-recently-played +SPOTIFY_URL_REFRESH_TOKEN = "https://accounts.spotify.com/api/token" +SPOTIFY_URL_NOW_PLAYING = "https://api.spotify.com/v1/me/player/currently-playing" +SPOTIFY_URL_RECENTLY_PLAY = "https://api.spotify.com/v1/me/player/recently-played?limit=10" + + +app = Flask(__name__) + + +def getAuth(): + return b64encode(f"{SPOTIFY_CLIENT_ID}:{SPOTIFY_SECRET_ID}".encode()).decode("ascii") + + +def refreshToken(): + data = { + "grant_type": "refresh_token", + "refresh_token": SPOTIFY_REFRESH_TOKEN, + } + + headers = {"Authorization": "Basic {}".format(getAuth())} + + response = requests.post(SPOTIFY_URL_REFRESH_TOKEN, data=data, headers=headers) + return response.json()["access_token"] + +def recentlyPlayed(): + token = refreshToken() + headers = {"Authorization": f"Bearer {token}"} + response = requests.get(SPOTIFY_URL_RECENTLY_PLAY, headers=headers) + + if response.status_code == 204: + return {} + + return response.json() + +def nowPlaying(): + + token = refreshToken() + + headers = {"Authorization": f"Bearer {token}"} + + response = requests.get(SPOTIFY_URL_NOW_PLAYING, headers=headers) + + if response.status_code == 204: + return {} + + return response.json() + +def barGen(barCount): + barCSS = "" + left = 1 + for i in range(1, barCount + 1): + anim = random.randint(1000, 1350) + barCSS += ".bar:nth-child({}) {{ left: {}px; animation-duration: {}ms; }}".format( + i, left, anim + ) + left += 4 + + return barCSS + +def loadImageB64(url): + resposne = requests.get(url) + return b64encode(resposne.content).decode("ascii") + +def makeSVG(data): + barCount = 85 + contentBar = "".join(["
" for i in range(barCount)]) + barCSS = barGen(barCount) + + if data == {}: + content_bar = "" + recent_plays = recentlyPlayed() + size_recent_play = len(recent_plays["items"]) + idx = random.randint(0, size_recent_play - 1) + item = recent_plays["items"][idx]["track"] + else: + item = data["item"] + + img = loadImageB64(item["album"]["images"][1]["url"]) + artistName = item["artists"][0]["name"].replace("&", "&") + songName = item["name"].replace("&", "&") + + dataDict = { + "content_bar": contentBar, + "css_bar": barCSS, + "artist_name": artistName, + "song_name": songName, + "img": img, + } + + return render_template("spotify.html.j2", **dataDict) + +@app.route("/", defaults={"path": ""}) +@app.route("/") +def catch_all(path): + + data = nowPlaying() + svg = makeSVG(data) + + resp = Response(svg, mimetype="image/svg+xml") + resp.headers["Cache-Control"] = "s-maxage=1" + + return resp + +if __name__ == "__main__": + app.run(debug=True) diff --git a/api/templates/preview.html b/api/templates/preview.html new file mode 100644 index 0000000..fdb35fc --- /dev/null +++ b/api/templates/preview.html @@ -0,0 +1,106 @@ +
+ +
+ +
+ +
+
+ +
+
Artist
+
Song
+
+
+
+ + +
\ No newline at end of file diff --git a/api/templates/spotify.html.j2 b/api/templates/spotify.html.j2 new file mode 100644 index 0000000..c96c466 --- /dev/null +++ b/api/templates/spotify.html.j2 @@ -0,0 +1,122 @@ + + +
+ + + {% if song_name %} + +
+ +
+ +
+
+ +
+
{{song_name}}
+
{{artist_name}}
+
+ {{content_bar|safe}} +
+
+ + {% else %} +
Nothing playing on Spotify
+ {% endif %} +
+ +
+
+
\ No newline at end of file