auto syncing lyrics, canvas replaces album art (if available), fixed layout (margins, padding, etc.), refactored some code
This commit is contained in:
1
.syncedlyrics/musixmatch_token.json
Normal file
1
.syncedlyrics/musixmatch_token.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"token": "240425a54f5df91735a14b241dcfb1e5df28f942d95b9cad8ea6a4", "expiration_time": 1714086845}
|
||||||
BIN
__pycache__/_canvas.cpython-312.pyc
Normal file
BIN
__pycache__/_canvas.cpython-312.pyc
Normal file
Binary file not shown.
57
_canvas.py
Executable file
57
_canvas.py
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
import requests
|
||||||
|
import random
|
||||||
|
from protos.canvas_pb2 import EntityCanvazRequest, EntityCanvazResponse
|
||||||
|
|
||||||
|
API_HOST = "https://spclient.wg.spotify.com"
|
||||||
|
CANVAS_ROUTE = "/canvaz-cache/v0/canvases"
|
||||||
|
TOKEN_ENDPOINT = "https://open.spotify.com/get_access_token?reason=transport"
|
||||||
|
TOKEN_RENEW_TIME = 900
|
||||||
|
|
||||||
|
TRACK_URI_PREFIX = "spotify:track:"
|
||||||
|
OAUTH_SCOPES = "playlist-read"
|
||||||
|
|
||||||
|
def get_access_token():
|
||||||
|
try:
|
||||||
|
response = requests.get(TOKEN_ENDPOINT)
|
||||||
|
data = response.json()
|
||||||
|
return data["accessToken"]
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
|
||||||
|
def get_canvas_for_track(access_token, track_id):
|
||||||
|
canvas_request = EntityCanvazRequest()
|
||||||
|
canvas_request_entities = canvas_request.entities.add()
|
||||||
|
canvas_request_entities.entity_uri = TRACK_URI_PREFIX + track_id
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = requests.post(
|
||||||
|
API_HOST + CANVAS_ROUTE,
|
||||||
|
headers={
|
||||||
|
"Accept": "application/protobuf",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"Accept-Language": "en",
|
||||||
|
"User-Agent": "Spotify/8.5.49 iOS/Version 13.3.1 (Build 17D50)",
|
||||||
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
|
"Authorization": "Bearer %s" % access_token
|
||||||
|
},
|
||||||
|
data=canvas_request.SerializeToString(),
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
raise ConnectionError
|
||||||
|
|
||||||
|
canvas_response = EntityCanvazResponse()
|
||||||
|
canvas_response.ParseFromString(resp.content)
|
||||||
|
|
||||||
|
if(len(canvas_response.canvases) == 0):
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
canvas = random.choice(canvas_response.canvases)
|
||||||
|
|
||||||
|
if canvas.url is not None:
|
||||||
|
return canvas.url
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# access_token = get_access_token()
|
||||||
|
# print(get_canvas_for_track(access_token, "1kADZJDyRUbmlLxYiqi077"))
|
||||||
2
code
2
code
@@ -1 +1 @@
|
|||||||
AQBtjZ5AgmaU073h9RsK82t8w2XMeQ_HTSbqbAyd3PNVQe2YNnkM883WOcpbDfKt4ll2xu0LoUWEMX5sEUmtPSWCgFs1k_3GFUxtUJV8VslZUvgIYBUSSbqNWrxZqRtGJ-cL_Rdq6gbBKttHkkMdnZVeO2jUtJM2zCHSYEW49o-aoRpcMkzPm66_H88O9S8hVEegS7nG4uP0AUYwe0EiW6YMvFkCVG6XJ7AJpcO97U0tP0PhRbBrx1Y5lRAequ5YaY-BC4FFHwBcA8XePKvAnuDku0sbRd1vbw6dahcRdco
|
AQDU_0NUgm9-EMYMDBYUTnBApWyYO6m4EDUExbHzjM_CcVkoGptsE69uePQ7ejw5NooRTCpQqIU7ZfOTfE5Nx8zj6amQBFRkgv7vMa5ViqCbH_hqos--D6mj-eG3jqW-sf-Oyq0vmPUaam6R0fB--ghWzM8EG8SRVQBGTnEN-OLf1PBX5I1sOS22GXrMud5BcFziAiYQxHn_GcnPXEyXigkHAsk60PFiWDUwW6fLdUKW2FtyJnnYH01al28eex1QEeqr2gg8e5ht9XGKfQej0ciFM62ESwIbpDZDi6bWdSk
|
||||||
BIN
protos/__pycache__/canvas_pb2.cpython-310.pyc
Executable file
BIN
protos/__pycache__/canvas_pb2.cpython-310.pyc
Executable file
Binary file not shown.
BIN
protos/__pycache__/canvas_pb2.cpython-312.pyc
Normal file
BIN
protos/__pycache__/canvas_pb2.cpython-312.pyc
Normal file
Binary file not shown.
37
protos/canvas_pb2.py
Executable file
37
protos/canvas_pb2.py
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: canvas.proto
|
||||||
|
"""Generated protocol buffer code."""
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf.internal import builder as _builder
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63\x61nvas.proto\x12\x17\x63om.spotify.canvazcache\"3\n\x06\x41rtist\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06\x61vatar\x18\x03 \x01(\t\"\xe6\x02\n\x14\x45ntityCanvazResponse\x12\x46\n\x08\x63\x61nvases\x18\x01 \x03(\x0b\x32\x34.com.spotify.canvazcache.EntityCanvazResponse.Canvaz\x12\x16\n\x0ettl_in_seconds\x18\x02 \x01(\x03\x1a\xed\x01\n\x06\x43\x61nvaz\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x0f\n\x07\x66ile_id\x18\x03 \x01(\t\x12+\n\x04type\x18\x04 \x01(\x0e\x32\x1d.com.spotify.canvazcache.Type\x12\x12\n\nentity_uri\x18\x05 \x01(\t\x12/\n\x06\x61rtist\x18\x06 \x01(\x0b\x32\x1f.com.spotify.canvazcache.Artist\x12\x10\n\x08\x65xplicit\x18\x07 \x01(\x08\x12\x13\n\x0buploaded_by\x18\x08 \x01(\t\x12\x0c\n\x04\x65tag\x18\t \x01(\t\x12\x12\n\ncanvas_uri\x18\x0b \x01(\t\"\x88\x01\n\x13\x45ntityCanvazRequest\x12\x45\n\x08\x65ntities\x18\x01 \x03(\x0b\x32\x33.com.spotify.canvazcache.EntityCanvazRequest.Entity\x1a*\n\x06\x45ntity\x12\x12\n\nentity_uri\x18\x01 \x01(\t\x12\x0c\n\x04\x65tag\x18\x02 \x01(\t*R\n\x04Type\x12\t\n\x05IMAGE\x10\x00\x12\t\n\x05VIDEO\x10\x01\x12\x11\n\rVIDEO_LOOPING\x10\x02\x12\x18\n\x14VIDEO_LOOPING_RANDOM\x10\x03\x12\x07\n\x03GIF\x10\x04\x42\x16\n\x12\x63om.spotify.canvazH\x02\x62\x06proto3')
|
||||||
|
|
||||||
|
_globals = globals()
|
||||||
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'canvas_pb2', _globals)
|
||||||
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
|
||||||
|
DESCRIPTOR._options = None
|
||||||
|
DESCRIPTOR._serialized_options = b'\n\022com.spotify.canvazH\002'
|
||||||
|
_globals['_TYPE']._serialized_start=594
|
||||||
|
_globals['_TYPE']._serialized_end=676
|
||||||
|
_globals['_ARTIST']._serialized_start=41
|
||||||
|
_globals['_ARTIST']._serialized_end=92
|
||||||
|
_globals['_ENTITYCANVAZRESPONSE']._serialized_start=95
|
||||||
|
_globals['_ENTITYCANVAZRESPONSE']._serialized_end=453
|
||||||
|
_globals['_ENTITYCANVAZRESPONSE_CANVAZ']._serialized_start=216
|
||||||
|
_globals['_ENTITYCANVAZRESPONSE_CANVAZ']._serialized_end=453
|
||||||
|
_globals['_ENTITYCANVAZREQUEST']._serialized_start=456
|
||||||
|
_globals['_ENTITYCANVAZREQUEST']._serialized_end=592
|
||||||
|
_globals['_ENTITYCANVAZREQUEST_ENTITY']._serialized_start=550
|
||||||
|
_globals['_ENTITYCANVAZREQUEST_ENTITY']._serialized_end=592
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
from flask import Flask, render_template, request, url_for, redirect, send_from_directory
|
from flask import Flask, render_template, request, url_for, redirect, send_from_directory
|
||||||
import time
|
|
||||||
import requests
|
import requests
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
import webbrowser
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
|
import _canvas as SpotifyCanvas
|
||||||
|
import time
|
||||||
|
import syncedlyrics
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@@ -88,6 +88,7 @@ def callback():
|
|||||||
@app.route('/appdata')
|
@app.route('/appdata')
|
||||||
def appdata():
|
def appdata():
|
||||||
global access_token
|
global access_token
|
||||||
|
stime = time.time()
|
||||||
user_headers = {
|
user_headers = {
|
||||||
"Authorization": "Bearer " + access_token,
|
"Authorization": "Bearer " + access_token,
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
@@ -96,9 +97,12 @@ def appdata():
|
|||||||
currently_playing = requests.get("https://api.spotify.com/v1/me/player/currently-playing", headers=user_headers)
|
currently_playing = requests.get("https://api.spotify.com/v1/me/player/currently-playing", headers=user_headers)
|
||||||
if currently_playing.content:
|
if currently_playing.content:
|
||||||
if currently_playing.json()["is_playing"] is True and currently_playing.json()["item"]["id"] == request.args.get('id'):
|
if currently_playing.json()["is_playing"] is True and currently_playing.json()["item"]["id"] == request.args.get('id'):
|
||||||
return { 'progress_ms': currently_playing.json()["progress_ms"]
|
print("QUICK" + str(time.time() - stime))
|
||||||
|
return { 'progress_ms': currently_playing.json()["progress_ms"],
|
||||||
}
|
}
|
||||||
elif currently_playing.json()["is_playing"] is True and currently_playing.json()["item"]["id"] != request.args.get('id'):
|
elif currently_playing.json()["is_playing"] is True and currently_playing.json()["item"]["id"] != request.args.get('id'):
|
||||||
|
|
||||||
|
print("FULL" + str(time.time() - stime))
|
||||||
return { 'id': currently_playing.json()["item"]["id"],
|
return { 'id': currently_playing.json()["item"]["id"],
|
||||||
'name': currently_playing.json()["item"]["name"],
|
'name': currently_playing.json()["item"]["name"],
|
||||||
'artist': currently_playing.json()["item"]["artists"][0]["name"],
|
'artist': currently_playing.json()["item"]["artists"][0]["name"],
|
||||||
@@ -107,20 +111,19 @@ def appdata():
|
|||||||
'is_playing': currently_playing.json()["is_playing"],
|
'is_playing': currently_playing.json()["is_playing"],
|
||||||
'progress_ms': currently_playing.json()["progress_ms"],
|
'progress_ms': currently_playing.json()["progress_ms"],
|
||||||
'duration_ms': currently_playing.json()["item"]["duration_ms"],
|
'duration_ms': currently_playing.json()["item"]["duration_ms"],
|
||||||
'is_liked': requests.get("https://api.spotify.com/v1/me/tracks/contains?ids=" + currently_playing.json()["item"]["id"], headers=user_headers).json()[0]
|
'is_liked': requests.get("https://api.spotify.com/v1/me/tracks/contains?ids=" + currently_playing.json()["item"]["id"], headers=user_headers).json()[0],
|
||||||
|
'canvas': False,
|
||||||
|
'fetchlyrics': 'fetch'
|
||||||
}
|
}
|
||||||
elif currently_playing.json()["is_playing"] is False:
|
elif currently_playing.json()["is_playing"] is False:
|
||||||
return { 'name': "Not Playing",
|
return { 'is_playing': False
|
||||||
'is_playing': False
|
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
return { 'name': "Error",
|
return { 'name': "Error",
|
||||||
'artist': "Error"
|
'artist': "Error"
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
return { 'name': "Not Playing",
|
return { 'is_playing': False
|
||||||
'image': "https://cdn.psychologytoday.com/sites/default/files/styles/article-inline-half-caption/public/field_blog_entry_images/2022-02/pause.png",
|
|
||||||
'is_playing': False
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@app.route('/control', methods=['POST'])
|
@app.route('/control', methods=['POST'])
|
||||||
@@ -157,7 +160,26 @@ def control():
|
|||||||
def icons(filename):
|
def icons(filename):
|
||||||
return send_from_directory('icons', filename)
|
return send_from_directory('icons', filename)
|
||||||
|
|
||||||
|
@app.route('/canvas')
|
||||||
|
def canvas():
|
||||||
|
print("CANVAS")
|
||||||
|
id = request.args.get('id')
|
||||||
|
try:
|
||||||
|
return { 'canvas_url': SpotifyCanvas.get_canvas_for_track(SpotifyCanvas.get_access_token(), id) }
|
||||||
|
except AttributeError:
|
||||||
|
return { 'canvas_url': None }
|
||||||
|
|
||||||
|
@app.route('/lyrics')
|
||||||
|
def lyrics():
|
||||||
|
name = request.args.get('name')
|
||||||
|
artist = request.args.get('artist')
|
||||||
|
if name and artist is not None:
|
||||||
|
full_lyrics = syncedlyrics.search("[" + name + "] [" + artist + "]")
|
||||||
|
else:
|
||||||
|
return { 'lyrics': '' }
|
||||||
|
if full_lyrics is None:
|
||||||
|
return { 'lyrics': "no lyrics" }
|
||||||
|
return { 'lyrics': full_lyrics }
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(port=8888, debug=True)
|
app.run(port=8888, debug=True)
|
||||||
@@ -21,31 +21,48 @@
|
|||||||
}
|
}
|
||||||
.song-text {
|
.song-text {
|
||||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
font-size: 20px;
|
font-size: 25px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-left: 20px;
|
margin-bottom: 5px;
|
||||||
padding-right: 20px;
|
|
||||||
}
|
}
|
||||||
.artist-text {
|
.artist-text {
|
||||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
font-size: 15px;
|
font-size: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-left: 20px;
|
margin-top: 5px;
|
||||||
padding-right: 20px;
|
|
||||||
}
|
}
|
||||||
.middle {
|
.middle {
|
||||||
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding-left: 20px;
|
}
|
||||||
padding-right: 20px;
|
.right {
|
||||||
|
height: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
width: 33%;
|
||||||
|
}
|
||||||
|
.lyrics {
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
font-size: 32px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
display: initial;
|
||||||
|
padding-top: 10%;
|
||||||
|
}
|
||||||
|
.total {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- <link href="http://127.0.0.1:8888/font" rel="stylesheet"> -->
|
<!-- <link href="http://127.0.0.1:8888/font" rel="stylesheet"> -->
|
||||||
|
<div class="total">
|
||||||
<img id="image" src="{{ data['image'] }}" alt="Song Image" type="image/jpeg" style="max-width: 300px; max-height: 300px;">
|
<img id="image" src="{{ data['image'] }}" alt="Song Image" type="image/jpeg" style="max-width: 300px; max-height: 300px;">
|
||||||
|
<video wdith="300" height="300" autoplay muted playsinline loop id="canvas_url" src="{{ data['canvas_url'] }}" type="video/mp4" style="display: none;"></video>
|
||||||
<div class="middle">
|
<div class="middle">
|
||||||
<p id="name" class="song-text">{{ data['name'] }}</p>
|
<p id="name" class="song-text">{{ data['name'] }}</p>
|
||||||
<p id="artist" class="artist-text">{{ data['artist'] }}</p>
|
<p id="artist" class="artist-text">{{ data['artist'] }}</p>
|
||||||
@@ -53,17 +70,23 @@
|
|||||||
<p id="progress_ms">{{ data['progress_ms'] }}</p>
|
<p id="progress_ms">{{ data['progress_ms'] }}</p>
|
||||||
<p id="duration_ms">{{ data['duration_ms'] }}</p> -->
|
<p id="duration_ms">{{ data['duration_ms'] }}</p> -->
|
||||||
<p>
|
<p>
|
||||||
<a><img id="previous" src="http://127.0.0.1:8888/icons/previous-black.png" style="width:96px;height:96px;"></a>
|
<a><img id="previous" src="http://127.0.0.1:8888/icons/previous-black.png" class="buttons"></a>
|
||||||
<a><img id="playpause" src="http://127.0.0.1:8888/icons/play-black.png" style="width:96px;height:96px;"></a>
|
<a><img id="playpause" src="http://127.0.0.1:8888/icons/play-black.png" class="buttons"></a>
|
||||||
<a><img id="next" src="http://127.0.0.1:8888/icons/next-black.png" style="width:96px;height:96px;"></a>
|
<a><img id="next" src="http://127.0.0.1:8888/icons/next-black.png" class="buttons"></a>
|
||||||
<a><img id="like" src="http://127.0.0.1:8888/icons/heart-black.png" style="width:96px;height:96px;"></a>
|
<a><img id="like" src="http://127.0.0.1:8888/icons/heart-black.png" class="buttons" style="display:none;"></a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<p id="lyric" class="lyrics">{{ data['lyric'] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="padding-top: 5px;">
|
||||||
<div class="progress-container">
|
<div class="progress-container">
|
||||||
<div id="progress_bar" class="progress-bar"></div>
|
<div id="progress_bar" class="progress-bar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
let id, is_playing, is_liked, duration_ms;
|
let id, is_playing, is_liked, duration_ms, canvas_url, lyrics;
|
||||||
// Function to update the values every second
|
// Function to update the values every second
|
||||||
function updateValues() {
|
function updateValues() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -77,11 +100,10 @@
|
|||||||
$('#is_playing').text(data['is_playing']);
|
$('#is_playing').text(data['is_playing']);
|
||||||
$('#progress_ms').text(data['progress_ms']);
|
$('#progress_ms').text(data['progress_ms']);
|
||||||
$('#duration_ms').text(data['duration_ms']);
|
$('#duration_ms').text(data['duration_ms']);
|
||||||
// $('#progress_min').text(Math.floor(data['progress_ms'] / (1000 * 60)) % 60);
|
|
||||||
// $('#progress_sec').text(Math.floor((data['progress_ms'] / 1000) % 60));
|
|
||||||
// $('#duration_min').text(Math.floor(data['duration_ms'] / (1000 * 60) % 60));
|
// $('#duration_min').text(Math.floor(data['duration_ms'] / (1000 * 60) % 60));
|
||||||
// $('#duration_sec').text(Math.floor(data['duration_ms'] / 1000) % 60);
|
// $('#duration_sec').text(Math.floor(data['duration_ms'] / 1000) % 60);
|
||||||
$('#is_liked').text(data['is_liked']);
|
$('#is_liked').text(data['is_liked']);
|
||||||
|
$('#canvas').attr('src', data['canvas']);
|
||||||
|
|
||||||
if (data['id'] !== undefined) {
|
if (data['id'] !== undefined) {
|
||||||
id = data['id'];
|
id = data['id'];
|
||||||
@@ -113,12 +135,62 @@
|
|||||||
// Change button to like text
|
// Change button to like text
|
||||||
document.getElementById('like').src = 'http://127.0.0.1:8888/icons/heart-black.png';
|
document.getElementById('like').src = 'http://127.0.0.1:8888/icons/heart-black.png';
|
||||||
}
|
}
|
||||||
|
if (data['canvas'] !== undefined) {
|
||||||
|
getCanvas(data['id']);
|
||||||
|
} else if (canvas_url == undefined) {
|
||||||
|
document.getElementById('canvas_url').style.display = "none";
|
||||||
|
document.getElementById('image').style.display = "";
|
||||||
|
}
|
||||||
|
getLyrics(data['name'], data['artist'], data['progress_ms'], data['fetchlyrics'])
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Update values every second
|
// Update values every second
|
||||||
setInterval(updateValues, 3000);
|
setInterval(updateValues, 1000);
|
||||||
|
|
||||||
|
// Function to run alongside the looped function if a variable is true
|
||||||
|
function getCanvas(id) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/canvas',
|
||||||
|
data: { id: id },
|
||||||
|
success: function(canvas_data) {
|
||||||
|
if (canvas_data['canvas_url'] !== undefined) {
|
||||||
|
$('#canvas_url').attr('src', canvas_data['canvas_url']);
|
||||||
|
document.getElementById('canvas_url').style.display = "";
|
||||||
|
document.getElementById('image').style.display = "none";
|
||||||
|
canvas_url = canvas_data['canvas_url'];
|
||||||
|
} else {
|
||||||
|
document.getElementById('canvas_url').style.display = "none";
|
||||||
|
document.getElementById('image').style.display = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getLyrics(name, artist, progress_ms, fetchlyrics) {
|
||||||
|
if (lyrics == undefined || fetchlyrics !== undefined && name !== undefined) {
|
||||||
|
$('#lyric').text('');
|
||||||
|
$.ajax({
|
||||||
|
url: '/lyrics',
|
||||||
|
data: {name: name, artist: artist},
|
||||||
|
success: function(lyrics_data) {
|
||||||
|
lyrics = lyrics_data['lyrics'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (lyrics == 'no lyrics') {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
progressMin = Math.floor(progress_ms / (1000 * 60)) % 60
|
||||||
|
progressSec = Math.floor((progress_ms / 1000) % 60)
|
||||||
|
const progressFormatted = `${progressMin}:${String(progressSec).padStart(2, '0')}`;
|
||||||
|
const lines = lyrics.split('\n');
|
||||||
|
for (const line of lines) {
|
||||||
|
if (line.includes(progressFormatted)) {
|
||||||
|
lyric = (line.split(']')[1])
|
||||||
|
$('#lyric').text(lyric);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// BUTTONS
|
// BUTTONS
|
||||||
$('#playpause').click(function() {
|
$('#playpause').click(function() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|||||||
5
todo.txt
5
todo.txt
@@ -10,3 +10,8 @@ provide updated song info, otherwise have it return just song progress ONLY.
|
|||||||
|
|
||||||
include color calculation, probably in python then give color value
|
include color calculation, probably in python then give color value
|
||||||
to js app, but maybe have js app do it from album art, explore which is better.
|
to js app, but maybe have js app do it from album art, explore which is better.
|
||||||
|
|
||||||
|
CANT GET LYRICS VAR TO BE ACCESSED OUTSIDE OF FUNCTION. AHHHH
|
||||||
|
|
||||||
|
MAKE album/canvas 33.3%, middle 33.3%, lyrics 33.3% to make sure nothing
|
||||||
|
moves around if the album switches to a canvas
|
||||||
Reference in New Issue
Block a user