Dynamic readme

This commit is contained in:
novatorem
2020-08-15 22:22:39 -04:00
commit cf59dbeaf7
7 changed files with 405 additions and 0 deletions

3
api/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
flask==1.1.2
requests==2.24.0
python-dotenv==0.14.0

120
api/spotify-playing.py Normal file
View File

@@ -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(["<div class='bar'></div>" 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("&", "&amp;")
songName = item["name"].replace("&", "&amp;")
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("/<path:path>")
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)

106
api/templates/preview.html Normal file
View File

@@ -0,0 +1,106 @@
<div xmlns="http://www.w3.org/1999/xhtml" class="container">
<style>
div {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
}
.main {
display: flex;
}
.art {
float: left;
width: 33.33%;
}
.container {
background-color: #121212;
border-radius: 10px;
padding: 10px 10px
}
.playing {
font-weight: bold;
color: #53b14f;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.not-play {
color: #ff1616;
}
.artist {
font-weight: bold;
font-size: 24px;
color: #fff;
text-align: left;
margin-top: 5px;
}
.song {
font-size: 20px;
color: #b3b3b3;
text-align: left;
margin-top: 15px;
margin-bottom: 15px;
}
.logo {
margin-left: 5px;
margin-top: 5px;
}
.cover {
border-radius: 5px;
margin-top: 9px;
}
#bars {
height: 30px;
margin: -20px 0 0 0px;
position: absolute;
width: 40px;
}
.bar {
background: #53b14f;
bottom: 1px;
height: 3px;
position: absolute;
width: 3px;
animation: sound 0ms -800ms linear infinite alternate;
}
@keyframes sound {
0% {
opacity: .35;
height: 3px;
}
100% {
opacity: 1;
height: 28px;
}
}
</style>
<div class="main">
<a class="art" href="{}" target="_BLANK">
<center>
<img src="data:image/png;base64, {{img}}" width="200" height="200" class="cover" />
</center>
</a>
<div class="text">
<div class="artist">Artist</div>
<div class="song">Song</div>
<div id="bars"></div>
</div>
</div>
</div>

View File

@@ -0,0 +1,122 @@
<svg width="480" height="133" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<foreignObject width="480" height="133">
<div xmlns="http://www.w3.org/1999/xhtml" class="container">
<style>
div {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
}
.main {
display: flex;
}
.container {
border-radius: 5px;
padding: 10px 10px 10px 0px;
}
.playing {
font-weight: bold;
color: #53b14f;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.not-play {
color: #ff1616;
}
.art {
float: left;
width: 27%;
margin-left: -5px;
}
.text {
width: 71%;
}
.song {
font-size: 24px;
color: #666;
text-align: center;
margin-top: 3px;
}
.artist {
font-size: 20px;
color: #b3b3b3;
text-align: center;
margin-bottom: 5px;
}
.logo {
margin-left: 5px;
margin-top: 5px;
}
.cover {
border-radius: 5px;
height: 100px;
width: 100px;
}
#bars {
height: 30px;
bottom: 23px;
margin: -20px 0 0 0px;
position: absolute;
width: 40px;
}
.bar {
background: #1DB954cc;
bottom: 1px;
height: 3px;
position: absolute;
width: 3px;
animation: sound 0ms -800ms linear infinite alternate;
}
@keyframes sound {
0% {
opacity: .35;
height: 3px;
}
100% {
opacity: 1;
height: 15px;
}
}
{{css_bar|safe}}
</style>
{% if song_name %}
<div class="main">
<a class="art" href="{}" target="_BLANK">
<center>
<img src="data:image/png;base64, {{img}}" class="cover" />
</center>
</a>
<div class="text">
<div class="song">{{song_name}}</div>
<div class="artist">{{artist_name}}</div>
<div id="bars">
{{content_bar|safe}}
</div>
</div>
{% else %}
<div class="playing not-play">Nothing playing on Spotify</div>
{% endif %}
</div>
</div>
</foreignObject>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB