organize
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import os
|
||||
import requests
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
||||
LEAGUES = [
|
||||
("hockey", "nhl"),
|
||||
("football", "nfl"),
|
||||
("basketball", "nba"),
|
||||
("baseball", "mlb"),
|
||||
]
|
||||
|
||||
LOGO_SIZE = (16, 16)
|
||||
|
||||
os.makedirs("./assets/logos", exist_ok=True)
|
||||
|
||||
|
||||
def download_logos(sport, league):
|
||||
url = f"https://site.api.espn.com/apis/site/v2/sports/{sport}/{league}/teams"
|
||||
resp = requests.get(url, timeout=10)
|
||||
resp.raise_for_status()
|
||||
teams = resp.json().get("sports", [])[0].get("leagues", [])[0].get("teams", [])
|
||||
|
||||
for entry in teams:
|
||||
team = entry["team"]
|
||||
abbr = team["abbreviation"].upper()
|
||||
logo_url = team.get("logos", [{}])[0].get("href")
|
||||
|
||||
if not logo_url:
|
||||
print(f"No logo for {abbr}, skipping")
|
||||
continue
|
||||
if os.path.exists(os.path.join("./assets/logos", f"{league}_{abbr}.png")):
|
||||
print(f"Logo exists for {abbr}, skipping")
|
||||
continue
|
||||
|
||||
try:
|
||||
img_resp = requests.get(logo_url, timeout=10)
|
||||
img = Image.open(BytesIO(img_resp.content)).convert("RGBA")
|
||||
|
||||
# Resize to 16x16
|
||||
img = img.resize(LOGO_SIZE, Image.LANCZOS)
|
||||
|
||||
# Flatten onto black background
|
||||
background = Image.new("RGB", LOGO_SIZE, (0, 0, 0))
|
||||
background.paste(img, mask=img.split()[3])
|
||||
|
||||
out_path = os.path.join("./assets/logos", f"{league}_{abbr}.png")
|
||||
background.save(out_path)
|
||||
print(f"Saved {out_path}")
|
||||
except Exception as e:
|
||||
print(f"Error downloading {abbr}: {e}")
|
||||
|
||||
|
||||
for sport, league in LEAGUES:
|
||||
print(f"\nDownloading {league.upper()} logos...")
|
||||
download_logos(sport, league)
|
||||
|
||||
print("\nDone!")
|
||||
@@ -0,0 +1,81 @@
|
||||
import requests
|
||||
import random
|
||||
import string
|
||||
import json
|
||||
|
||||
GOVEE_API_BASE_URL = "https://openapi.api.govee.com/router/api/v1/"
|
||||
|
||||
|
||||
class GoveeApi:
|
||||
key = ""
|
||||
headers = {}
|
||||
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
self.headers = {"Govee-API-Key": key}
|
||||
|
||||
def __get_random_string(self):
|
||||
characters = string.ascii_letters + string.digits
|
||||
result_str = "".join(random.choices(characters, k=4))
|
||||
return result_str
|
||||
|
||||
def get_diy_scenes(self, sku, device):
|
||||
payload = {
|
||||
"requestId": self.__get_random_string(),
|
||||
"payload": {"sku": sku, "device": device},
|
||||
}
|
||||
|
||||
res = requests.post(
|
||||
GOVEE_API_BASE_URL + "device/diy-scenes", json=payload, headers=self.headers
|
||||
)
|
||||
res.raise_for_status()
|
||||
|
||||
print("[GOVEE] DIY scene fetch: " + json.dumps(res.json(), indent=4))
|
||||
|
||||
return res.ok
|
||||
|
||||
def set_diy_scene(self, sku, device):
|
||||
payload = {
|
||||
"requestId": self.__get_random_string(),
|
||||
"payload": {
|
||||
"sku": sku,
|
||||
"device": device,
|
||||
"capability": {
|
||||
"type": "device.capabilities.dynamic_scene",
|
||||
"instance": "diyScene",
|
||||
"value": 22757907,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res = requests.post(
|
||||
GOVEE_API_BASE_URL + "device/control", headers=self.headers, json=payload
|
||||
)
|
||||
res.raise_for_status()
|
||||
|
||||
print("[GOVEE] Set DIY scene: " + json.dumps(res.json(), indent=4))
|
||||
|
||||
return res.ok
|
||||
|
||||
def set_to_original_color(self, sku, device):
|
||||
payload = {
|
||||
"requestId": self.__get_random_string(),
|
||||
"payload": {
|
||||
"sku": sku,
|
||||
"device": device,
|
||||
"capability": {
|
||||
"type": "devices.capabilities.color_setting",
|
||||
"instance": "colorRgb",
|
||||
"value": 16711680,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res = requests.post(
|
||||
GOVEE_API_BASE_URL + "device/control", json=payload, headers=self.headers
|
||||
)
|
||||
res.raise_for_status()
|
||||
|
||||
print("[GOVEE] Set to original: " + json.dumps(res.json(), indent=4))
|
||||
|
||||
return res.ok
|
||||
@@ -0,0 +1,42 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
logo_cache = {}
|
||||
SCRIPT_DIR = Path(__file__).parent.resolve()
|
||||
ASSET_DIR = os.path.join(SCRIPT_DIR, "assets")
|
||||
LOGO_DIR = os.path.join(ASSET_DIR, "logos")
|
||||
|
||||
def draw_pil_image(canvas, img):
|
||||
for x in range(img.width):
|
||||
for y in range(img.height):
|
||||
r, g, b = img.getpixel((x, y))
|
||||
canvas.SetPixel(x, y, b, g, r) # bgr panels
|
||||
|
||||
def load_logo(league, abbr):
|
||||
key = f"{league}_{abbr}"
|
||||
if key in logo_cache:
|
||||
return logo_cache[key]
|
||||
|
||||
path = os.path.join(LOGO_DIR, f"{key}.png")
|
||||
if not os.path.exists(path):
|
||||
print(f"Logo not found: {path}")
|
||||
logo_cache[key] = None
|
||||
return None
|
||||
|
||||
try:
|
||||
img = Image.open(path).convert("RGB")
|
||||
logo_cache[key] = img
|
||||
return img
|
||||
except Exception as e:
|
||||
print(f"Error loading logo {key}: {e}")
|
||||
logo_cache[key] = None
|
||||
return None
|
||||
|
||||
def draw_logo(canvas, img, x, y):
|
||||
if img is None:
|
||||
return
|
||||
for px in range(img.width):
|
||||
for py in range(img.height):
|
||||
r, g, b = img.getpixel((px, py))
|
||||
canvas.SetPixel(x + px, y + py, r, b, g) # bgr panels
|
||||
Reference in New Issue
Block a user