import tkinter as tk import requests import threading import time import os import random from io import BytesIO from PIL import Image, ImageTk SERVER_URL = "http://localhost:8080/endpoint" CYCLE_INTERVAL_MS = 10000 # Změna produktu každých 10 sekund SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) KATALOG_DIR = os.path.join(SCRIPT_DIR, "katalog") if not os.path.exists(KATALOG_DIR): KATALOG_DIR = os.path.join(SCRIPT_DIR, "documents", "katalog") class FullscreenJarmarkDisplay: def __init__(self, root): self.root = root self.root.title("RP + 1602 Display Jarmark") self.root.attributes("-fullscreen", True) self.root.bind("", lambda e: self.root.destroy()) self.canvas = tk.Canvas(root, width=1920, height=1080, bg="#0d031b", highlightthickness=0) self.canvas.pack(fill=tk.BOTH, expand=True) self.load_background() # Název produktu nahoře self.title_text_id = self.canvas.create_text(960, 120, text="", fill="white", font=("Impact", 75, "bold")) # Obrázek produktu uprostřed self.prod_image_id = self.canvas.create_image(920, 510, anchor="center") # --- DESIGN CENOVKY (Vpravo) --- # 1. Podkladový badge/karta pro cenu self.price_bg_id = self.canvas.create_rectangle(1380, 450, 1840, 570, fill="#150826", outline="#9d4edd", width=3) # 2. Stín ceny (3D efekt) self.price_shadow_id = self.canvas.create_text(1613, 513, text="", fill="#000000", font=("Trebuchet MS", 62, "bold"), anchor="center") # 3. Hlavní text ceny (Zářivě zlatá) self.price_text_id = self.canvas.create_text(1610, 510, text="", fill="#FFD700", font=("Trebuchet MS", 62, "bold"), anchor="center") # Spodní lišta přehrávače self.canvas.create_rectangle(0, 910, 1920, 1080, fill="#000000", outline="") self.cover_img_id = self.canvas.create_image(80, 995, anchor="center") self.spotify_title_id = self.canvas.create_text(160, 955, text="Načítám...", fill="white", font=("Arial", 22, "bold"), anchor="w") self.spotify_subtitle_id = self.canvas.create_text(160, 990, text="Hudobné video • Čekám na Spotify", fill="#bbbbbb", font=("Arial", 16), anchor="w") self.time_curr_id = self.canvas.create_text(160, 1040, text="0:00", fill="#aaaaaa", font=("Arial", 14), anchor="w") self.time_total_id = self.canvas.create_text(1860, 1040, text="0:00", fill="#aaaaaa", font=("Arial", 14), anchor="e") self.pbar_bg = self.canvas.create_line(220, 1040, 1800, 1040, fill="#444444", width=5) self.pbar_fg = self.canvas.create_line(220, 1040, 220, 1040, fill="#ffffff", width=5) self.running = True self.current_img_url = None self.photo_cover = None self.current_prod_photo = None self.catalog_items = [] self.current_catalog_index = 0 self.load_catalog() self.cycle_product() threading.Thread(target=self.poll_data, daemon=True).start() def load_background(self): bg_candidates = [ "backgroung.png", "background.png", "background.jpg", "backgroung.jpg" ] bg_path = None for filename in bg_candidates: full_path = os.path.join(SCRIPT_DIR, filename) if os.path.exists(full_path): bg_path = full_path break if bg_path: try: bg_img = Image.open(bg_path).convert("RGBA").resize((1920, 1080), Image.Resampling.LANCZOS) self.bg_photo = ImageTk.PhotoImage(bg_img) self.canvas.create_image(0, 0, image=self.bg_photo, anchor="nw") except Exception as e: print(f"Chyba při načítání pozadí {bg_path}: {e}") else: colors = ["#2b0845", "#410b66", "#581287", "#731aa8", "#8b24ca"] random.seed(42) for _ in range(40): x = random.randint(0, 1920) y = random.randint(0, 1080) r = random.randint(40, 150) c = random.choice(colors) self.canvas.create_oval(x-r, y-r, x+r, y+r, fill=c, outline="") def load_catalog(self): global KATALOG_DIR if not os.path.exists(KATALOG_DIR): KATALOG_DIR = os.path.join(SCRIPT_DIR, "katalog") if not os.path.exists(KATALOG_DIR): KATALOG_DIR = os.path.join(SCRIPT_DIR, "documents", "katalog") self.catalog_items = [] if not os.path.exists(KATALOG_DIR): print(f"Adresář 'katalog' neexistuje na cestě: {KATALOG_DIR}") return for folder_name in sorted(os.listdir(KATALOG_DIR)): folder_path = os.path.join(KATALOG_DIR, folder_name) if os.path.isdir(folder_path): info_path = os.path.join(folder_path, "info.txt") image_path = os.path.join(folder_path, "image.png") title = folder_name price = "" if os.path.exists(info_path): try: with open(info_path, "r", encoding="utf-8") as f: lines = [line.strip() for line in f.readlines() if line.strip()] if len(lines) >= 1: title = lines[0] if len(lines) >= 2: price = lines[1] except Exception as e: print(f"Chyba při čtení {info_path}: {e}") self.catalog_items.append({ "title": title, "price": price, "image_path": image_path if os.path.exists(image_path) else None }) def cycle_product(self): if self.current_catalog_index == 0: self.load_catalog() if self.catalog_items: self.current_catalog_index %= len(self.catalog_items) item = self.catalog_items[self.current_catalog_index] self.canvas.itemconfig(self.title_text_id, text=item["title"]) # Nastavení ceny i stínu ceny price_val = item["price"] self.canvas.itemconfig(self.price_text_id, text=price_val) self.canvas.itemconfig(self.price_shadow_id, text=price_val) # Pokud cenovka nemá text, schováme podkladový obdélník if price_val: self.canvas.itemconfig(self.price_bg_id, state="normal") else: self.canvas.itemconfig(self.price_bg_id, state="hidden") if item["image_path"]: try: raw_img = Image.open(item["image_path"]).convert("RGBA") raw_img.thumbnail((700, 460), Image.Resampling.LANCZOS) self.current_prod_photo = ImageTk.PhotoImage(raw_img) self.canvas.itemconfig(self.prod_image_id, image=self.current_prod_photo) except Exception as e: print(f"Chyba při načítání obrázku {item['image_path']}: {e}") self.canvas.itemconfig(self.prod_image_id, image="") else: self.canvas.itemconfig(self.prod_image_id, image="") self.current_catalog_index = (self.current_catalog_index + 1) % len(self.catalog_items) self.root.after(CYCLE_INTERVAL_MS, self.cycle_product) def poll_data(self): while self.running: try: res = requests.get(SERVER_URL, timeout=1) if res.status_code == 200: data = res.json() artist = data.get("artist", "Neznámý interpret") title = data.get("title", "Čekám na skladbu") progress = data.get("progressTime", "0:00/0:00") img_url = data.get("coverImg", None) self.root.after(0, self.update_gui, artist, title, progress, img_url) except Exception: pass time.sleep(0.8) def parse_time_to_seconds(self, time_str): try: parts = time_str.split(':') return int(parts[0]) * 60 + int(parts[1]) except Exception: return 0 def update_gui(self, artist, title, progress, img_url): self.canvas.itemconfig(self.spotify_title_id, text=title) self.canvas.itemconfig(self.spotify_subtitle_id, text=f"Hudobné video • {artist}") if "/" in progress: curr, dur = progress.split("/") self.canvas.itemconfig(self.time_curr_id, text=curr) self.canvas.itemconfig(self.time_total_id, text=dur) c_sec = self.parse_time_to_seconds(curr) d_sec = self.parse_time_to_seconds(dur) percent = (c_sec / d_sec) if d_sec > 0 else 0 start_x = 220 max_w = 1800 - start_x fill_x = start_x + int(max_w * percent) self.canvas.coords(self.pbar_fg, start_x, 1040, fill_x, 1040) if img_url and img_url != self.current_img_url: self.current_img_url = img_url threading.Thread(target=self.download_cover, args=(img_url,), daemon=True).start() def download_cover(self, url): try: res = requests.get(url, timeout=3) if res.status_code == 200: raw_img = Image.open(BytesIO(res.content)).convert("RGBA") raw_img = raw_img.resize((100, 100), Image.Resampling.LANCZOS) self.photo_cover = ImageTk.PhotoImage(raw_img) self.root.after(0, lambda: self.canvas.itemconfig(self.cover_img_id, image=self.photo_cover)) except Exception: pass if __name__ == "__main__": root = tk.Tk() app = FullscreenJarmarkDisplay(root) root.mainloop()