Compare commits
10 Commits
7ee49b9cf6
...
347c87a154
Author | SHA1 | Date | |
---|---|---|---|
347c87a154 | |||
9128e8ce87 | |||
a9e3bfcf98 | |||
e3a1680c90 | |||
7100dcea8b | |||
a9ea1e4d2a | |||
5bcaa84bfb | |||
3cc831ba72 | |||
0627a480f3 | |||
9765756d7b |
14
spotiplayer.service
Normal file
14
spotiplayer.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Spotiplayer
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/path/to/this/repository
|
||||
ExecStart=/usr/bin/python3 -m spotiplayer_pi.main
|
||||
Restart=on-failure
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
@ -39,7 +39,7 @@ class Api:
|
||||
return self._format_req(req.json())
|
||||
|
||||
def _format_req(self, r):
|
||||
if not r["is_playing"]:
|
||||
if not r["is_playing"] or r["currently_playing_type"] != "track":
|
||||
return "not-playing"
|
||||
item, album = r["item"], r["item"]["album"]
|
||||
res = {
|
||||
|
@ -1,12 +1,11 @@
|
||||
refresh_token: "AQBGNOL-iocPZ_zxtr_sNXx4BZRaxPmg2Ea0cJGorcEu2IW2wSnLdkYDJpVDOuQQHWIQ-LjuNpBcY9PurPtdfPoT5ljXnGpso9CqX6n2alBXaYc767oKya_52qxqWPE0o7k"
|
||||
base_64: "ZTI5Mzg3NWI3YWQ5NDQzZDg1NDMxYzkwOTEyZTdiMWQ6MjlmNDEzZTJiOTRlNGU0NDlkOWRiYmU0NmM2OTY5MTY="
|
||||
|
||||
api_interval: 5 # (float) number of seconds in-between API requests
|
||||
api_interval: 3 # (float) number of seconds in-between API requests
|
||||
refresh_interval: 0.4 # (float) number of seconds in-between progress bar refreshes
|
||||
|
||||
# Set Color Theme
|
||||
color_theme:
|
||||
text: [253, 238, 216] # [R, G, B] All text components
|
||||
bar_outline: [16, 81, 86] # [R, G, B] Bar in-fill
|
||||
bar_inside: [148, 191, 136] # [R, G, B] Bar in-fill
|
||||
text: [253, 238, 216] # [R, G, B] All text components and bar outline
|
||||
bar_inside: [30, 215, 96] # [R, G, B] Bar in-fill
|
||||
background: [13, 19, 33] # [R, G, B] Background
|
||||
|
@ -7,11 +7,28 @@ import warnings
|
||||
from datetime import datetime
|
||||
import yaml
|
||||
from typing import Dict
|
||||
import subprocess
|
||||
|
||||
from spotiplayer_pi.lib import LCD_2inch
|
||||
from spotiplayer_pi.api import Api
|
||||
|
||||
|
||||
def get_cpu_temp():
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["vcgencmd", "measure_temp"], capture_output=True, text=True, check=True
|
||||
)
|
||||
temp_str = result.stdout.strip()
|
||||
temp_value = temp_str.split("=")[1].replace("'C", "")
|
||||
return float(temp_value)
|
||||
except subprocess.CalledProcessError as e:
|
||||
warnings.warn(f"Error executing vcgencmd: {e}")
|
||||
return "None"
|
||||
except (IndexError, ValueError) as e:
|
||||
warnings.warn(f"Error parsing temperature: {e}")
|
||||
return "None"
|
||||
|
||||
|
||||
def parse_config(path="spotiplayer_pi/config.yaml"):
|
||||
with open(path, "r") as file:
|
||||
data = yaml.safe_load(file)
|
||||
@ -28,7 +45,7 @@ def display_loop(api: Api, cfg: Dict):
|
||||
bg = Image.new("RGB", (d.height, d.width), (0, 0, 0))
|
||||
d.ShowImage(bg)
|
||||
|
||||
Font0 = ImageFont.truetype("Font/GothamMedium.ttf", 13)
|
||||
Font0 = ImageFont.truetype("Font/GothamBold.ttf", 14)
|
||||
Font1 = ImageFont.truetype("Font/GothamMedium.ttf", 18)
|
||||
Font1b = ImageFont.truetype("Font/GothamBold.ttf", 19)
|
||||
Font2 = ImageFont.truetype("Font/GothamMedium.ttf", 20)
|
||||
@ -52,7 +69,6 @@ def display_loop(api: Api, cfg: Dict):
|
||||
"Connect to speakers",
|
||||
font=Font2,
|
||||
fill=(255, 255, 255),
|
||||
# fill=cfg["color_theme"]["text"],
|
||||
)
|
||||
del spoti_logo, qr, draw
|
||||
|
||||
@ -78,22 +94,26 @@ def display_loop(api: Api, cfg: Dict):
|
||||
|
||||
elif data == "not-playing":
|
||||
draw = ImageDraw.Draw(not_playing_img)
|
||||
current_time = datetime.now().time()
|
||||
draw.rectangle([(00, 120), (119, 170)], fill=(0, 0, 0))
|
||||
current_time = datetime.now()
|
||||
draw.rectangle([(00, 120), (119, 190)], fill=(0, 0, 0))
|
||||
offset = 10 if current_time.hour < 9 else 0
|
||||
draw.text(
|
||||
(10 + offset, 120),
|
||||
f"{current_time.hour}:{current_time.minute:02d}",
|
||||
font=Font3,
|
||||
fill=(255, 255, 255),
|
||||
# fill=cfg["color_theme"]["text"],
|
||||
)
|
||||
draw.text(
|
||||
(20, 152),
|
||||
(25, 152),
|
||||
current_time.strftime("%a %d"),
|
||||
font=Font2,
|
||||
fill=(255, 255, 255),
|
||||
# fill=cfg["color_theme"]["text"],
|
||||
)
|
||||
draw.text(
|
||||
(20, 175),
|
||||
f"CPU: {get_cpu_temp():.2f}°",
|
||||
font=Font0,
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
if current_mode != 0:
|
||||
current_mode = 0
|
||||
@ -105,7 +125,7 @@ def display_loop(api: Api, cfg: Dict):
|
||||
current_mode = 1
|
||||
current_track = data["track"] + data["artists"][0] + data["album"]
|
||||
if current_track != last_track:
|
||||
print("updating track")
|
||||
print(f"Updating track to : {data['track']} - {data['artists'][0]}")
|
||||
last_track = current_track
|
||||
img = None
|
||||
try:
|
||||
@ -124,7 +144,7 @@ def display_loop(api: Api, cfg: Dict):
|
||||
bg.paste(img, (10, 30))
|
||||
draw = ImageDraw.Draw(bg)
|
||||
draw.text(
|
||||
(145, 33),
|
||||
(145, 34),
|
||||
"\n".join(textwrap.wrap(", ".join(data["artists"]), width=16)),
|
||||
font=Font1,
|
||||
fill=cfg["color_theme"]["text"],
|
||||
@ -137,41 +157,41 @@ def display_loop(api: Api, cfg: Dict):
|
||||
)
|
||||
|
||||
w, h = bg.size
|
||||
w -= 95
|
||||
w -= 90
|
||||
h += 4
|
||||
progress_time = min(
|
||||
data["duration_ms"],
|
||||
data["progress_ms"] + int((time.time() - last_api_call) * 1000),
|
||||
)
|
||||
progress = min(1, progress_time / data["duration_ms"])
|
||||
bar_width = int(w * progress)
|
||||
bar_width = int((w - 10) * progress)
|
||||
draw.rectangle(
|
||||
[(7, h - 23), (w + 3, h - 7)],
|
||||
# outline=cfg["color_theme"]["text"],
|
||||
outline=cfg["color_theme"]["bar_outline"],
|
||||
[(9, h - 23), (w + 3, h - 7)],
|
||||
outline=cfg["color_theme"]["text"],
|
||||
)
|
||||
|
||||
draw.rectangle(
|
||||
[(10, h - 22), (w + 2, h - 8)],
|
||||
outline=cfg["color_theme"]["text"],
|
||||
)
|
||||
draw.rectangle(
|
||||
[(8, h - 22), (w + 2, h - 8)],
|
||||
# outline=cfg["color_theme"]["text"],
|
||||
outline=cfg["color_theme"]["bar_outline"],
|
||||
[(12, h - 20), (w, h - 10)], fill=cfg["color_theme"]["background"]
|
||||
)
|
||||
draw.rectangle(
|
||||
[(10, h - 20), (w, h - 10)], fill=cfg["color_theme"]["background"]
|
||||
)
|
||||
draw.rectangle(
|
||||
[(10, h - 20), (bar_width, h - 10)],
|
||||
[(12, h - 20), (12 + bar_width, h - 10)],
|
||||
fill=cfg["color_theme"]["bar_inside"],
|
||||
)
|
||||
f_current_time = "{:02.0f}:{:02.0f}".format(
|
||||
f_current_time = "{}:{:02.0f}".format(
|
||||
*divmod(progress_time // 1000, 60)
|
||||
)
|
||||
f_total_time = "{:02d}:{:02d}".format(
|
||||
f_total_time = "{}:{:02d}".format(
|
||||
*divmod(data["duration_ms"] // 1000, 60)
|
||||
)
|
||||
draw.rectangle(
|
||||
[(231, 215), (320, 235)], fill=cfg["color_theme"]["background"]
|
||||
[(237, 218), (320, 238)], fill=cfg["color_theme"]["background"]
|
||||
)
|
||||
draw.text(
|
||||
(232, 220),
|
||||
(238, 223),
|
||||
f"{f_current_time}/{f_total_time}",
|
||||
font=Font0,
|
||||
fill=cfg["color_theme"]["text"],
|
||||
|
@ -19,7 +19,7 @@ class TestApp(unittest.TestCase):
|
||||
# Check color_theme structure
|
||||
color_theme = self.cfg["color_theme"]
|
||||
self.assertIsInstance(color_theme, dict)
|
||||
for key in ["text", "bar_outline", "bar_inside", "background"]:
|
||||
for key in ["text", "bar_inside", "background"]:
|
||||
self.assertIn(key, color_theme)
|
||||
self.assertIsInstance(color_theme[key], tuple)
|
||||
self.assertEqual(len(color_theme[key]), 3)
|
||||
|
Loading…
x
Reference in New Issue
Block a user