поправил карту бросков
This commit is contained in:
124
get_data.py
124
get_data.py
@@ -93,14 +93,41 @@ SYNO_PASSWORD = os.getenv("SYNO_PASSWORD")
|
|||||||
SYNO_PATH_VMIX = os.getenv("SYNO_PATH_VMIX")
|
SYNO_PATH_VMIX = os.getenv("SYNO_PATH_VMIX")
|
||||||
SYNO_FONT_PATH = os.getenv("SYNO_FONT_PATH")
|
SYNO_FONT_PATH = os.getenv("SYNO_FONT_PATH")
|
||||||
|
|
||||||
|
_syno_font_path = nasio.load_bio(
|
||||||
|
user=SYNO_USERNAME,
|
||||||
|
password=SYNO_PASSWORD,
|
||||||
|
nas_ip=SYNO_URL,
|
||||||
|
nas_port="443",
|
||||||
|
path=os.getenv("SYNO_FONT_PATH"),
|
||||||
|
)
|
||||||
|
if isinstance(_syno_font_path, BytesIO):
|
||||||
|
_syno_font_path = _syno_font_path.getvalue()
|
||||||
|
SYNO_FONT_PATH = _syno_font_path # bytes или None
|
||||||
|
# ---- ИКОНКА ПРОМАХА ----
|
||||||
|
_syno_miss_raw = nasio.load_bio(
|
||||||
|
user=SYNO_USERNAME,
|
||||||
|
password=SYNO_PASSWORD,
|
||||||
|
nas_ip=SYNO_URL,
|
||||||
|
nas_port="443",
|
||||||
|
path=os.getenv("SYNO_MISS"),
|
||||||
|
)
|
||||||
|
if isinstance(_syno_miss_raw, BytesIO):
|
||||||
|
_syno_miss_raw = _syno_miss_raw.getvalue()
|
||||||
|
SYNO_MISS = _syno_miss_raw # bytes или None
|
||||||
|
|
||||||
|
# ---- ИКОНКА ПОПАДАНИЯ ----
|
||||||
|
_syno_goal_raw = nasio.load_bio(
|
||||||
|
user=SYNO_USERNAME,
|
||||||
|
password=SYNO_PASSWORD,
|
||||||
|
nas_ip=SYNO_URL,
|
||||||
|
nas_port="443",
|
||||||
|
path=os.getenv("SYNO_GOAL"),
|
||||||
|
)
|
||||||
|
if isinstance(_syno_goal_raw, BytesIO):
|
||||||
|
_syno_goal_raw = _syno_goal_raw.getvalue()
|
||||||
|
SYNO_GOAL = _syno_goal_raw # bytes или None
|
||||||
|
|
||||||
SHOTMAP_SUBDIR = "shotmaps"
|
SHOTMAP_SUBDIR = "shotmaps"
|
||||||
# SHOTMAP_DIR = (
|
|
||||||
# os.path.join(SYNO_PATH_VMIX, SHOTMAP_SUBDIR)
|
|
||||||
# if SYNO_PATH_VMIX
|
|
||||||
# else os.path.join(os.getcwd(), SHOTMAP_SUBDIR)
|
|
||||||
# )
|
|
||||||
# os.makedirs(SHOTMAP_DIR, exist_ok=True)
|
|
||||||
SHOTMAP_DIR = os.path.join(os.getcwd(), "shotmaps")
|
SHOTMAP_DIR = os.path.join(os.getcwd(), "shotmaps")
|
||||||
os.makedirs(SHOTMAP_DIR, exist_ok=True)
|
os.makedirs(SHOTMAP_DIR, exist_ok=True)
|
||||||
|
|
||||||
@@ -3312,10 +3339,9 @@ async def games_online():
|
|||||||
return todays_games
|
return todays_games
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_image(points, bib, count_point):
|
def get_image(points, bib, count_point):
|
||||||
"""
|
"""
|
||||||
points: список кортежей (x, y, is_made)
|
points: список кортежей (x, y, is_made, sec, period)
|
||||||
x, y — координаты из API, где (0,0) = центр кольца
|
x, y — координаты из API, где (0,0) = центр кольца
|
||||||
is_made — True (play 2,3) или False (play 5,6)
|
is_made — True (play 2,3) или False (play 5,6)
|
||||||
bib: startNum/номер игрока
|
bib: startNum/номер игрока
|
||||||
@@ -3325,54 +3351,40 @@ def get_image(points, bib, count_point):
|
|||||||
if not points:
|
if not points:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
# # --- подложка ---
|
|
||||||
# try:
|
|
||||||
# base_image = Image.open(COURT_IMAGE_PATH).convert("RGBA")
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.warning(
|
|
||||||
# f"[shotmap] не удалось открыть COURT_IMAGE_PATH={COURT_IMAGE_PATH}: {e}"
|
|
||||||
# )
|
|
||||||
base_image = Image.new("RGBA", (1500, 2800), (0, 0, 0, 0))
|
base_image = Image.new("RGBA", (1500, 2800), (0, 0, 0, 0))
|
||||||
|
width, height = base_image.size
|
||||||
width, height = base_image.size # ожидаем 1500 x 2800
|
|
||||||
draw = ImageDraw.Draw(base_image)
|
draw = ImageDraw.Draw(base_image)
|
||||||
|
|
||||||
# === ДИАПАЗОН КООРДИНАТ ИЗ API ===
|
# === Диапазон координат ===
|
||||||
COURT_WIDTH_UNITS = 150.0 # по X
|
COURT_WIDTH_UNITS = 150.0 # по X
|
||||||
COURT_LENGTH_UNITS = 280.0 # по Y
|
COURT_LENGTH_UNITS = 280.0 # по Y
|
||||||
|
|
||||||
# масштаб: пиксели на 1 API-юнит
|
|
||||||
scale_x = height / COURT_LENGTH_UNITS
|
scale_x = height / COURT_LENGTH_UNITS
|
||||||
scale_y = width / COURT_WIDTH_UNITS
|
scale_y = width / COURT_WIDTH_UNITS
|
||||||
|
|
||||||
# === ЦЕНТР КОЛЬЦА В PILLOW-КООРДИНАТАХ (ОТ ВЕРХНЕГО ЛЕВОГО УГЛА) ===
|
|
||||||
HOOP_X_PX = 750
|
HOOP_X_PX = 750
|
||||||
HOOP_Y_PX = 157.5
|
HOOP_Y_PX = 157.5
|
||||||
|
|
||||||
def to_px(x, y):
|
def to_px(x, y):
|
||||||
"""
|
|
||||||
(0,0) из API → (HOOP_X_PX, HOOP_Y_PX) на картинке.
|
|
||||||
x > 0 — вправо, y > 0 — вниз (вглубь площадки).
|
|
||||||
Если нужно, чтобы y шёл вверх — поменяй + на -.
|
|
||||||
"""
|
|
||||||
px = int(HOOP_X_PX - x * scale_x)
|
px = int(HOOP_X_PX - x * scale_x)
|
||||||
py = int(HOOP_Y_PX + y * scale_y)
|
py = int(HOOP_Y_PX + y * scale_y)
|
||||||
return px, py
|
return px, py
|
||||||
|
|
||||||
point_radius = 10
|
point_radius = 30
|
||||||
|
|
||||||
# try:
|
# --- шрифт ---
|
||||||
nasio_font = nasio.load_bio(
|
font = ImageFont.load_default()
|
||||||
user=SYNO_USERNAME,
|
try:
|
||||||
password=SYNO_PASSWORD,
|
nasio_font = SYNO_FONT_PATH
|
||||||
nas_ip=SYNO_URL,
|
|
||||||
nas_port="443",
|
|
||||||
path=SYNO_FONT_PATH,
|
|
||||||
)
|
|
||||||
if nasio_font:
|
if nasio_font:
|
||||||
|
if isinstance(nasio_font, BytesIO):
|
||||||
|
nasio_font = nasio_font.getvalue()
|
||||||
|
if isinstance(nasio_font, (bytes, bytearray)):
|
||||||
|
font = ImageFont.truetype(BytesIO(nasio_font), 18)
|
||||||
|
else:
|
||||||
font = ImageFont.truetype(nasio_font, 18)
|
font = ImageFont.truetype(nasio_font, 18)
|
||||||
# except Exception:
|
except Exception as e:
|
||||||
# font = ImageFont.load_default()
|
logger.warning(f"[shotmap] не удалось загрузить шрифт: {e}")
|
||||||
|
|
||||||
for x_raw, y_raw, is_made, sec, period in points:
|
for x_raw, y_raw, is_made, sec, period in points:
|
||||||
try:
|
try:
|
||||||
@@ -3383,7 +3395,33 @@ def get_image(points, bib, count_point):
|
|||||||
|
|
||||||
px, py = to_px(x, y)
|
px, py = to_px(x, y)
|
||||||
|
|
||||||
# кружок
|
# --- выбираем bytes иконки ---
|
||||||
|
icon_bytes = SYNO_GOAL if is_made else SYNO_MISS
|
||||||
|
used_icon = False
|
||||||
|
|
||||||
|
if isinstance(icon_bytes, (bytes, bytearray)) and icon_bytes:
|
||||||
|
try:
|
||||||
|
buf = BytesIO(icon_bytes)
|
||||||
|
icon = Image.open(buf).convert("RGBA")
|
||||||
|
|
||||||
|
size = point_radius * 2
|
||||||
|
icon = icon.resize((size, size), Image.LANCZOS)
|
||||||
|
|
||||||
|
base_image.paste(icon, (px - point_radius, py - point_radius), icon)
|
||||||
|
used_icon = True
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
f"[shotmap] не удалось открыть иконку из bytes "
|
||||||
|
f"(is_made={is_made}, len={len(icon_bytes)}): {e}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"[shotmap] icon_bytes пустой или не bytes "
|
||||||
|
f"(is_made={is_made}, type={type(icon_bytes)})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Fallback: кружок, если картинка не нарисовалась ---
|
||||||
|
if not used_icon:
|
||||||
bbox = (
|
bbox = (
|
||||||
px - point_radius,
|
px - point_radius,
|
||||||
py - point_radius,
|
py - point_radius,
|
||||||
@@ -3393,11 +3431,15 @@ def get_image(points, bib, count_point):
|
|||||||
color = (0, 255, 0, 255) if is_made else (255, 0, 0, 255)
|
color = (0, 255, 0, 255) if is_made else (255, 0, 0, 255)
|
||||||
draw.ellipse(bbox, fill=color)
|
draw.ellipse(bbox, fill=color)
|
||||||
|
|
||||||
# подпись координат (для отладки)
|
# --- подпись Q{period} по центру ---
|
||||||
label = f"{x:.2f}; {y:.2f}"
|
|
||||||
text_x = px + point_radius + 4
|
|
||||||
text_y = py - point_radius - 4
|
|
||||||
label = f"Q{period}"
|
label = f"Q{period}"
|
||||||
|
bbox = draw.textbbox((0, 0), label, font=font)
|
||||||
|
text_w = bbox[2] - bbox[0]
|
||||||
|
text_h = bbox[3] - bbox[1]
|
||||||
|
|
||||||
|
# центрируем относительно точки (px, py)
|
||||||
|
text_x = px - text_w // 2
|
||||||
|
text_y = py - text_h // 2
|
||||||
|
|
||||||
# тень
|
# тень
|
||||||
draw.text((text_x + 1, text_y + 1), label, font=font, fill=(0, 0, 0, 255))
|
draw.text((text_x + 1, text_y + 1), label, font=font, fill=(0, 0, 0, 255))
|
||||||
|
|||||||
Reference in New Issue
Block a user