Aktualizovat spotify_widget.py
This commit is contained in:
@@ -1,14 +1,53 @@
|
|||||||
import tkinter as tk
|
|
||||||
import requests
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
|
import datetime
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
import requests
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from PIL import Image, ImageTk
|
import tkinter as tk
|
||||||
|
from PIL import Image, ImageTk, ImageDraw
|
||||||
|
import pythoncom
|
||||||
|
|
||||||
|
# Pokus o automatickou instalaci pycaw, pokud chybí
|
||||||
|
try:
|
||||||
|
from pycaw.pycaw import AudioUtilities
|
||||||
|
HAS_PYCAW = True
|
||||||
|
except ImportError:
|
||||||
|
print("📦 Instaluji potřebnou knihovnu 'pycaw' pro okamžité ztlumení Windows...")
|
||||||
|
try:
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "pycaw", "comtypes"],
|
||||||
|
creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0))
|
||||||
|
from pycaw.pycaw import AudioUtilities
|
||||||
|
HAS_PYCAW = True
|
||||||
|
print("✅ Knihovna pycaw byla úspěšně nainstalována!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Automatická instalace pycaw se nezdařila: {e}")
|
||||||
|
HAS_PYCAW = False
|
||||||
|
|
||||||
|
# Pokus o import winsound (standardně na Windows)
|
||||||
|
try:
|
||||||
|
import winsound
|
||||||
|
HAS_WINSOUND = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_WINSOUND = False
|
||||||
|
|
||||||
|
# Pokus o import pygame
|
||||||
|
try:
|
||||||
|
import pygame
|
||||||
|
pygame.mixer.init()
|
||||||
|
HAS_PYGAME = True
|
||||||
|
except Exception:
|
||||||
|
HAS_PYGAME = False
|
||||||
|
|
||||||
SERVER_URL = "http://localhost:8080/endpoint"
|
SERVER_URL = "http://localhost:8080/endpoint"
|
||||||
CYCLE_INTERVAL_MS = 10000 # Změna produktu každých 10 sekund
|
CYCLE_INTERVAL_MS = 10000 # Doba zobrazení produktu (10 sekund)
|
||||||
|
FRAME_INTERVAL_MS = 120 # Rychlost 3D rotace fotek (120 ms)
|
||||||
|
PARTICLE_COUNT = 60 # Počet bokeh částic
|
||||||
|
|
||||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
@@ -16,94 +55,403 @@ KATALOG_DIR = os.path.join(SCRIPT_DIR, "katalog")
|
|||||||
if not os.path.exists(KATALOG_DIR):
|
if not os.path.exists(KATALOG_DIR):
|
||||||
KATALOG_DIR = os.path.join(SCRIPT_DIR, "documents", "katalog")
|
KATALOG_DIR = os.path.join(SCRIPT_DIR, "documents", "katalog")
|
||||||
|
|
||||||
|
# Složka se zvuky pro reklamy
|
||||||
|
SOUNDS_DIR = os.path.join(SCRIPT_DIR, "zvuky_reklama")
|
||||||
|
if not os.path.exists(SOUNDS_DIR):
|
||||||
|
os.makedirs(SOUNDS_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def natural_sort_key(s):
|
||||||
|
""" Řazení souborů podle čísel (image1, image2, ..., image10) """
|
||||||
|
return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s)]
|
||||||
|
|
||||||
|
|
||||||
|
def set_spotify_mute(mute=True):
|
||||||
|
""" Bleskově ztlumí VŠECHNY aplikace ve Windows kromě samotného Pythonu """
|
||||||
|
pythoncom.CoInitialize()
|
||||||
|
if HAS_PYCAW:
|
||||||
|
try:
|
||||||
|
sessions = AudioUtilities.GetAllSessions()
|
||||||
|
for session in sessions:
|
||||||
|
try:
|
||||||
|
pname = session.Process.name().lower() if session.Process else ""
|
||||||
|
if not any(keep in pname for keep in ["python", "wmplayer"]):
|
||||||
|
volume = session.SimpleAudioVolume
|
||||||
|
volume.SetMute(1 if mute else 0, None)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Pycaw chyba: {e}")
|
||||||
|
|
||||||
|
nircmd_path = os.path.join(SCRIPT_DIR, "nircmd.exe")
|
||||||
|
if os.path.exists(nircmd_path):
|
||||||
|
try:
|
||||||
|
val = "1" if mute else "0"
|
||||||
|
for proc in ["spotify.exe", "chrome.exe", "msedge.exe", "brave.exe", "firefox.exe", "opera.exe"]:
|
||||||
|
subprocess.run(
|
||||||
|
[nircmd_path, "muteappvolume", proc, val],
|
||||||
|
creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"NirCmd chyba: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
class AdvancedParticle:
|
||||||
|
""" Třída pro vícevrstvé animované bokeh částice """
|
||||||
|
def __init__(self, w=1920, h=1080):
|
||||||
|
self.w = w
|
||||||
|
self.h = h
|
||||||
|
self.reset(random_y=True)
|
||||||
|
|
||||||
|
def reset(self, random_y=False):
|
||||||
|
self.x = random.uniform(0, self.w)
|
||||||
|
self.y = random.uniform(0, self.h) if random_y else self.h + random.uniform(20, 80)
|
||||||
|
|
||||||
|
self.p_type = random.choice(['bokeh_large', 'bokeh_medium', 'spark'])
|
||||||
|
|
||||||
|
if self.p_type == 'bokeh_large':
|
||||||
|
self.base_radius = random.uniform(40, 90)
|
||||||
|
self.speed_y = random.uniform(0.2, 0.6)
|
||||||
|
self.sway_amp = random.uniform(1.0, 3.0)
|
||||||
|
self.sway_freq = random.uniform(0.005, 0.015)
|
||||||
|
self.color_outer = random.choice(["#2a0845", "#3c096c", "#1e0034", "#480ca8", "#38040e"])
|
||||||
|
self.color_inner = random.choice(["#5a189a", "#7b2cbf", "#9d4edd", "#7209b7", "#9e2a2b"])
|
||||||
|
elif self.p_type == 'bokeh_medium':
|
||||||
|
self.base_radius = random.uniform(18, 38)
|
||||||
|
self.speed_y = random.uniform(0.5, 1.2)
|
||||||
|
self.sway_amp = random.uniform(1.5, 4.0)
|
||||||
|
self.sway_freq = random.uniform(0.01, 0.025)
|
||||||
|
self.color_outer = random.choice(["#5a189a", "#7209b7", "#b5179e", "#480ca8"])
|
||||||
|
self.color_inner = random.choice(["#e0aaff", "#f72585", "#c77dff", "#ffb703"])
|
||||||
|
else: # spark
|
||||||
|
self.base_radius = random.uniform(2, 5)
|
||||||
|
self.speed_y = random.uniform(0.8, 2.2)
|
||||||
|
self.sway_amp = random.uniform(0.5, 2.0)
|
||||||
|
self.sway_freq = random.uniform(0.02, 0.05)
|
||||||
|
self.color_outer = "#ffffff"
|
||||||
|
self.color_inner = random.choice(["#ffffff", "#ffee83", "#4cc9f0", "#ffb703"])
|
||||||
|
|
||||||
|
self.radius = self.base_radius
|
||||||
|
self.pulse_phase = random.uniform(0, 2 * math.pi)
|
||||||
|
self.pulse_speed = random.uniform(0.015, 0.04)
|
||||||
|
self.phase = random.uniform(0, 2 * math.pi)
|
||||||
|
|
||||||
|
def update(self, w, h):
|
||||||
|
self.w = w
|
||||||
|
self.h = h
|
||||||
|
self.y -= self.speed_y
|
||||||
|
self.phase += self.sway_freq
|
||||||
|
self.x += math.sin(self.phase) * self.sway_amp
|
||||||
|
|
||||||
|
self.pulse_phase += self.pulse_speed
|
||||||
|
pulse_factor = 1.0 + 0.22 * math.sin(self.pulse_phase)
|
||||||
|
self.radius = self.base_radius * pulse_factor
|
||||||
|
|
||||||
|
if self.y < -self.radius * 2 or self.x < -self.radius or self.x > self.w + self.radius:
|
||||||
|
self.reset(random_y=False)
|
||||||
|
|
||||||
|
|
||||||
class FullscreenJarmarkDisplay:
|
class FullscreenJarmarkDisplay:
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("RP + 1602 Display Jarmark")
|
self.root.title("Jarmark Display Kiosk")
|
||||||
|
|
||||||
self.root.attributes("-fullscreen", True)
|
self.root.attributes("-fullscreen", True)
|
||||||
self.root.bind("<Escape>", lambda e: self.root.destroy())
|
|
||||||
|
|
||||||
self.canvas = tk.Canvas(root, width=1920, height=1080, bg="#0d031b", highlightthickness=0)
|
self.w = 1920
|
||||||
|
self.h = 1080
|
||||||
|
|
||||||
|
# Klávesové zkratky
|
||||||
|
self.root.bind("<Escape>", lambda e: self.root.destroy())
|
||||||
|
self.root.bind("<Right>", lambda e: self.next_product())
|
||||||
|
self.root.bind("<Left>", lambda e: self.prev_product())
|
||||||
|
self.root.bind("<space>", lambda e: self.toggle_pause())
|
||||||
|
self.root.bind("<r>", lambda e: self.reload_catalog_action())
|
||||||
|
self.root.bind("<R>", lambda e: self.reload_catalog_action())
|
||||||
|
|
||||||
|
# Plátno s čistým tmavým pozadím
|
||||||
|
self.canvas = tk.Canvas(root, bg="#07010f", highlightthickness=0)
|
||||||
self.canvas.pack(fill=tk.BOTH, expand=True)
|
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
self.load_background()
|
self.canvas.bind("<Configure>", self.on_resize)
|
||||||
|
|
||||||
# Název produktu nahoře
|
# Částice
|
||||||
self.title_text_id = self.canvas.create_text(960, 120, text="", fill="white", font=("Impact", 75, "bold"))
|
self.particles = [AdvancedParticle(self.w, self.h) for _ in range(PARTICLE_COUNT)]
|
||||||
|
self.particle_draw_ids = []
|
||||||
|
self.init_particles_canvas()
|
||||||
|
|
||||||
# Obrázek produktu uprostřed
|
# Canvas Prvky - Název produktu se stínem pro skvělou čitelnost bez rámčku
|
||||||
self.prod_image_id = self.canvas.create_image(920, 510, anchor="center")
|
self.title_shadow_id = self.canvas.create_text(0, 0, text="", fill="#000000", font=("Impact", 42, "bold"), anchor="center")
|
||||||
|
self.title_text_id = self.canvas.create_text(0, 0, text="", fill="#ffffff", font=("Impact", 42, "bold"), anchor="center")
|
||||||
|
|
||||||
# --- DESIGN CENOVKY (Vpravo) ---
|
self.badge_bg_id = self.canvas.create_rectangle(0, 0, 0, 0, fill="", outline="", state="hidden")
|
||||||
# 1. Podkladový badge/karta pro cenu
|
self.badge_text_id = self.canvas.create_text(0, 0, text="", fill="white", font=("Segoe UI", 13, "bold"), state="hidden")
|
||||||
self.price_bg_id = self.canvas.create_rectangle(1380, 450, 1840, 570, fill="#150826", outline="#9d4edd", width=3)
|
|
||||||
|
|
||||||
# 2. Stín ceny (3D efekt)
|
# Produkt fotka (zcela bez rámečku, volně na pozadí)
|
||||||
self.price_shadow_id = self.canvas.create_text(1613, 513, text="", fill="#000000", font=("Trebuchet MS", 62, "bold"), anchor="center")
|
self.prod_image_id = self.canvas.create_image(0, 0, anchor="center")
|
||||||
|
|
||||||
# 3. Hlavní text ceny (Zářivě zlatá)
|
# Cenovka vpravo
|
||||||
self.price_text_id = self.canvas.create_text(1610, 510, text="", fill="#FFD700", font=("Trebuchet MS", 62, "bold"), anchor="center")
|
self.price_bg_id = self.canvas.create_rectangle(0, 0, 0, 0, fill="#120521", outline="#9d4edd", width=2)
|
||||||
|
self.price_shadow_id = self.canvas.create_text(0, 0, text="", fill="#000000", font=("Segoe UI", 38, "bold"), anchor="center")
|
||||||
|
self.price_text_id = self.canvas.create_text(0, 0, text="", fill="#ffb703", font=("Segoe UI", 38, "bold"), anchor="center")
|
||||||
|
|
||||||
|
# Hodiny & Datum
|
||||||
|
self.clock_time_id = self.canvas.create_text(0, 0, text="", fill="#ffffff", font=("Segoe UI", 26, "bold"), anchor="e")
|
||||||
|
self.clock_date_id = self.canvas.create_text(0, 0, text="", fill="#9d4edd", font=("Segoe UI", 13, "bold"), anchor="e")
|
||||||
|
|
||||||
# Spodní lišta přehrávače
|
# Indikátor pauzy
|
||||||
self.canvas.create_rectangle(0, 910, 1920, 1080, fill="#000000", outline="")
|
self.pause_indicator_id = self.canvas.create_text(0, 0, text="", fill="#ff0055", font=("Segoe UI", 13, "bold"), anchor="w")
|
||||||
|
|
||||||
self.cover_img_id = self.canvas.create_image(80, 995, anchor="center")
|
# Spotify Karta (ovládaná vaším rozšířením, vlevo dole)
|
||||||
|
self.card_x1, self.card_y1 = 0, 0
|
||||||
|
self.card_w, self.card_h = 360, 150
|
||||||
|
self.card_bg_photo = None
|
||||||
|
self.card_bg_id = self.canvas.create_image(0, 0, anchor="nw")
|
||||||
|
|
||||||
self.spotify_title_id = self.canvas.create_text(160, 955, text="Načítám...", fill="white", font=("Arial", 22, "bold"), anchor="w")
|
self.cover_img_id = self.canvas.create_image(0, 0, anchor="center")
|
||||||
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.spotify_title_id = self.canvas.create_text(0, 0, text="Načítám...", fill="white", font=("Segoe UI", 13, "bold"), anchor="w")
|
||||||
|
self.spotify_subtitle_id = self.canvas.create_text(0, 0, text="Čekám na Spotify", fill="#c77dff", font=("Segoe UI", 10), anchor="w")
|
||||||
|
|
||||||
self.time_curr_id = self.canvas.create_text(160, 1040, text="0:00", fill="#aaaaaa", font=("Arial", 14), anchor="w")
|
self.time_curr_id = self.canvas.create_text(0, 0, text="0:00", fill="#aaaaaa", font=("Segoe UI", 9), anchor="w")
|
||||||
self.time_total_id = self.canvas.create_text(1860, 1040, text="0:00", fill="#aaaaaa", font=("Arial", 14), anchor="e")
|
self.time_total_id = self.canvas.create_text(0, 0, text="0:00", fill="#aaaaaa", font=("Segoe UI", 9), anchor="e")
|
||||||
|
|
||||||
self.pbar_bg = self.canvas.create_line(220, 1040, 1800, 1040, fill="#444444", width=5)
|
self.pbar_bg = self.canvas.create_line(0, 0, 0, 0, fill="#3c096c", width=5, capstyle=tk.ROUND)
|
||||||
self.pbar_fg = self.canvas.create_line(220, 1040, 220, 1040, fill="#ffffff", width=5)
|
self.pbar_fg = self.canvas.create_line(0, 0, 0, 0, fill="#f72585", width=5, capstyle=tk.ROUND)
|
||||||
|
|
||||||
|
# Stavové proměnné
|
||||||
self.running = True
|
self.running = True
|
||||||
|
self.is_paused = False
|
||||||
|
self.is_ad_active = False
|
||||||
|
self.ad_sound_process = None
|
||||||
self.current_img_url = None
|
self.current_img_url = None
|
||||||
self.photo_cover = None
|
self.photo_cover = None
|
||||||
|
self.raw_cover_img = None
|
||||||
|
self.current_card_rgba = (25, 10, 40, 230)
|
||||||
self.current_prod_photo = None
|
self.current_prod_photo = None
|
||||||
|
|
||||||
self.catalog_items = []
|
self.catalog_items = []
|
||||||
|
self.active_item = None
|
||||||
self.current_catalog_index = 0
|
self.current_catalog_index = 0
|
||||||
|
self.current_frame_index = 0
|
||||||
|
|
||||||
|
# Spuštění procesů
|
||||||
self.load_catalog()
|
self.load_catalog()
|
||||||
self.cycle_product()
|
self.cycle_product()
|
||||||
|
self.animate_product_3d()
|
||||||
|
self.animate_particles()
|
||||||
|
self.update_clock()
|
||||||
|
|
||||||
threading.Thread(target=self.poll_data, daemon=True).start()
|
threading.Thread(target=self.poll_data, daemon=True).start()
|
||||||
|
|
||||||
def load_background(self):
|
def trigger_ad_sound(self):
|
||||||
bg_candidates = [
|
print("🔇 Ztlumuji vše kromě Pythonu...")
|
||||||
"backgroung.png",
|
set_spotify_mute(True)
|
||||||
"background.png",
|
|
||||||
"background.jpg",
|
|
||||||
"backgroung.jpg"
|
|
||||||
]
|
|
||||||
|
|
||||||
bg_path = None
|
if not os.path.exists(SOUNDS_DIR):
|
||||||
for filename in bg_candidates:
|
return
|
||||||
full_path = os.path.join(SCRIPT_DIR, filename)
|
|
||||||
if os.path.exists(full_path):
|
|
||||||
bg_path = full_path
|
|
||||||
break
|
|
||||||
|
|
||||||
if bg_path:
|
valid_exts = ('.wav', '.mp3', '.wma', '.ogg')
|
||||||
|
sounds = [os.path.join(SOUNDS_DIR, f) for f in os.listdir(SOUNDS_DIR) if f.lower().endswith(valid_exts)]
|
||||||
|
|
||||||
|
if not sounds:
|
||||||
|
return
|
||||||
|
|
||||||
|
chosen_sound = random.choice(sounds)
|
||||||
|
|
||||||
|
def _play():
|
||||||
try:
|
try:
|
||||||
bg_img = Image.open(bg_path).convert("RGBA").resize((1920, 1080), Image.Resampling.LANCZOS)
|
if HAS_PYGAME:
|
||||||
self.bg_photo = ImageTk.PhotoImage(bg_img)
|
pygame.mixer.music.load(chosen_sound)
|
||||||
self.canvas.create_image(0, 0, image=self.bg_photo, anchor="nw")
|
pygame.mixer.music.play()
|
||||||
|
elif chosen_sound.lower().endswith('.wav') and HAS_WINSOUND:
|
||||||
|
winsound.PlaySound(chosen_sound, winsound.SND_FILENAME | winsound.SND_ASYNC)
|
||||||
|
else:
|
||||||
|
ps_script = f"$m = New-Object -ComObject WMPlayer.OCX; $m.URL = '{chosen_sound}'; $m.controls.play(); Start-Sleep -s 60"
|
||||||
|
self.ad_sound_process = subprocess.Popen(
|
||||||
|
["powershell", "-Command", ps_script],
|
||||||
|
creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0)
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Chyba při načítání pozadí {bg_path}: {e}")
|
print(f"Chyba při přehrávání zvuku: {e}")
|
||||||
else:
|
|
||||||
colors = ["#2b0845", "#410b66", "#581287", "#731aa8", "#8b24ca"]
|
threading.Thread(target=_play, daemon=True).start()
|
||||||
random.seed(42)
|
|
||||||
for _ in range(40):
|
def stop_ad_sound(self):
|
||||||
x = random.randint(0, 1920)
|
print("🔊 REKLAMA SKONČILA: Vracím hlasitost zpět.")
|
||||||
y = random.randint(0, 1080)
|
try:
|
||||||
r = random.randint(40, 150)
|
if HAS_PYGAME and pygame.mixer.music.get_busy():
|
||||||
c = random.choice(colors)
|
pygame.mixer.music.stop()
|
||||||
self.canvas.create_oval(x-r, y-r, x+r, y+r, fill=c, outline="")
|
if HAS_WINSOUND:
|
||||||
|
winsound.PlaySound(None, winsound.SND_PURGE)
|
||||||
|
if self.ad_sound_process:
|
||||||
|
self.ad_sound_process.kill()
|
||||||
|
self.ad_sound_process = None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Chyba při zastavování: {e}")
|
||||||
|
|
||||||
|
set_spotify_mute(False)
|
||||||
|
|
||||||
|
def on_resize(self, event):
|
||||||
|
if event.width <= 10 or event.height <= 10:
|
||||||
|
return
|
||||||
|
if self.w == event.width and self.h == event.height:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.w = event.width
|
||||||
|
self.h = event.height
|
||||||
|
self.reposition_all()
|
||||||
|
|
||||||
|
def reposition_all(self):
|
||||||
|
w, h = self.w, self.h
|
||||||
|
|
||||||
|
# 1. Název produktu + stín
|
||||||
|
font_title_sz = max(24, int(h * 0.055))
|
||||||
|
self.canvas.itemconfig(self.title_text_id, font=("Impact", font_title_sz, "bold"))
|
||||||
|
self.canvas.itemconfig(self.title_shadow_id, font=("Impact", font_title_sz, "bold"))
|
||||||
|
self.canvas.coords(self.title_text_id, w * 0.5, h * 0.09)
|
||||||
|
self.canvas.coords(self.title_shadow_id, w * 0.5 + 2, h * 0.09 + 2)
|
||||||
|
|
||||||
|
# 2. Produkt
|
||||||
|
self.canvas.coords(self.prod_image_id, w * 0.5, h * 0.48)
|
||||||
|
self.update_product_frame()
|
||||||
|
|
||||||
|
# 3. Cenovka vpravo
|
||||||
|
font_price_sz = max(22, int(h * 0.050))
|
||||||
|
price_w, price_h = int(w * 0.20), int(h * 0.10)
|
||||||
|
px1, py1 = int(w * 0.74), int(h * 0.46)
|
||||||
|
px2, py2 = px1 + price_w, py1 + price_h
|
||||||
|
|
||||||
|
self.canvas.coords(self.price_bg_id, px1, py1, px2, py2)
|
||||||
|
self.canvas.coords(self.price_shadow_id, px1 + price_w/2 + 2, py1 + price_h/2 + 2)
|
||||||
|
self.canvas.coords(self.price_text_id, px1 + price_w/2, py1 + price_h/2)
|
||||||
|
|
||||||
|
self.canvas.itemconfig(self.price_shadow_id, font=("Segoe UI", font_price_sz, "bold"))
|
||||||
|
self.canvas.itemconfig(self.price_text_id, font=("Segoe UI", font_price_sz, "bold"))
|
||||||
|
|
||||||
|
# 4. Hodiny & Datum
|
||||||
|
font_time_sz = max(18, int(h * 0.032))
|
||||||
|
font_date_sz = max(11, int(h * 0.016))
|
||||||
|
self.canvas.itemconfig(self.clock_time_id, font=("Segoe UI", font_time_sz, "bold"))
|
||||||
|
self.canvas.itemconfig(self.clock_date_id, font=("Segoe UI", font_date_sz, "bold"))
|
||||||
|
self.canvas.coords(self.clock_time_id, w * 0.97, h * 0.04)
|
||||||
|
self.canvas.coords(self.clock_date_id, w * 0.97, h * 0.08)
|
||||||
|
|
||||||
|
# 5. Indikátor pauzy
|
||||||
|
self.canvas.coords(self.pause_indicator_id, w * 0.03, h * 0.04)
|
||||||
|
|
||||||
|
# 6. Spotify Karta vlevo dole
|
||||||
|
self.card_w = max(320, int(w * 0.23))
|
||||||
|
self.card_h = max(135, int(h * 0.16))
|
||||||
|
self.card_x1 = int(w * 0.03)
|
||||||
|
self.card_y1 = int(h - self.card_h - (h * 0.03))
|
||||||
|
|
||||||
|
self.canvas.coords(self.card_bg_id, self.card_x1, self.card_y1)
|
||||||
|
self.update_card_background(self.current_card_rgba)
|
||||||
|
|
||||||
|
cover_size = int(self.card_h * 0.58)
|
||||||
|
cover_cx = self.card_x1 + int(self.card_h * 0.42)
|
||||||
|
cover_cy = self.card_y1 + int(self.card_h * 0.50)
|
||||||
|
self.canvas.coords(self.cover_img_id, cover_cx, cover_cy)
|
||||||
|
|
||||||
|
if self.raw_cover_img:
|
||||||
|
resized_cover = self.raw_cover_img.resize((cover_size, cover_size), Image.Resampling.LANCZOS)
|
||||||
|
self.photo_cover = ImageTk.PhotoImage(resized_cover)
|
||||||
|
self.canvas.itemconfig(self.cover_img_id, image=self.photo_cover)
|
||||||
|
|
||||||
|
text_x = self.card_x1 + int(self.card_h * 0.82)
|
||||||
|
font_sp_title = max(11, int(self.card_h * 0.11))
|
||||||
|
font_sp_sub = max(9, int(self.card_h * 0.085))
|
||||||
|
|
||||||
|
self.canvas.itemconfig(self.spotify_title_id, font=("Segoe UI", font_sp_title, "bold"))
|
||||||
|
self.canvas.itemconfig(self.spotify_subtitle_id, font=("Segoe UI", font_sp_sub, "bold"))
|
||||||
|
|
||||||
|
self.canvas.coords(self.spotify_title_id, text_x, self.card_y1 + int(self.card_h * 0.22))
|
||||||
|
self.canvas.coords(self.spotify_subtitle_id, text_x, self.card_y1 + int(self.card_h * 0.40))
|
||||||
|
|
||||||
|
bar_x1 = text_x
|
||||||
|
bar_x2 = self.card_x1 + self.card_w - int(self.card_h * 0.12)
|
||||||
|
bar_y = self.card_y1 + int(self.card_h * 0.68)
|
||||||
|
|
||||||
|
self.canvas.coords(self.pbar_bg, bar_x1, bar_y, bar_x2, bar_y)
|
||||||
|
self.canvas.coords(self.time_curr_id, bar_x1, bar_y + int(self.card_h * 0.18))
|
||||||
|
self.canvas.coords(self.time_total_id, bar_x2, bar_y + int(self.card_h * 0.18))
|
||||||
|
|
||||||
|
if self.active_item:
|
||||||
|
self.show_product_by_index(self.current_catalog_index - 1)
|
||||||
|
|
||||||
|
def update_clock(self):
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
time_str = now.strftime("%H:%M:%S")
|
||||||
|
|
||||||
|
days_cz = ["Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"]
|
||||||
|
months_cz = ["ledna", "února", "března", "dubna", "května", "června", "července", "srpna", "září", "října", "listopadu", "prosince"]
|
||||||
|
|
||||||
|
day_name = days_cz[now.weekday()]
|
||||||
|
month_name = months_cz[now.month - 1]
|
||||||
|
date_str = f"{day_name}, {now.day}. {month_name} {now.year}"
|
||||||
|
|
||||||
|
self.canvas.itemconfig(self.clock_time_id, text=time_str)
|
||||||
|
self.canvas.itemconfig(self.clock_date_id, text=date_str)
|
||||||
|
self.root.after(1000, self.update_clock)
|
||||||
|
|
||||||
|
def init_particles_canvas(self):
|
||||||
|
for p in self.particles:
|
||||||
|
if p.p_type in ['bokeh_large', 'bokeh_medium']:
|
||||||
|
outer_id = self.canvas.create_oval(p.x - p.radius, p.y - p.radius, p.x + p.radius, p.y + p.radius, fill=p.color_outer, outline="")
|
||||||
|
r_in = p.radius * 0.45
|
||||||
|
inner_id = self.canvas.create_oval(p.x - r_in, p.y - r_in, p.x + r_in, p.y + r_in, fill=p.color_inner, outline="")
|
||||||
|
self.particle_draw_ids.append((outer_id, inner_id))
|
||||||
|
else:
|
||||||
|
draw_id = self.canvas.create_oval(p.x - p.radius, p.y - p.radius, p.x + p.radius, p.y + p.radius, fill=p.color_inner, outline="")
|
||||||
|
self.particle_draw_ids.append((draw_id, None))
|
||||||
|
|
||||||
|
def animate_particles(self):
|
||||||
|
for p, draw_ids in zip(self.particles, self.particle_draw_ids):
|
||||||
|
p.update(self.w, self.h)
|
||||||
|
outer_id, inner_id = draw_ids
|
||||||
|
|
||||||
|
if inner_id is not None:
|
||||||
|
self.canvas.coords(outer_id, p.x - p.radius, p.y - p.radius, p.x + p.radius, p.y + p.radius)
|
||||||
|
r_in = p.radius * 0.45
|
||||||
|
self.canvas.coords(inner_id, p.x - r_in, p.y - r_in, p.x + r_in, p.y + r_in)
|
||||||
|
else:
|
||||||
|
self.canvas.coords(outer_id, p.x - p.radius, p.y - p.radius, p.x + p.radius, p.y + p.radius)
|
||||||
|
self.root.after(35, self.animate_particles)
|
||||||
|
|
||||||
|
def toggle_pause(self):
|
||||||
|
self.is_paused = not self.is_paused
|
||||||
|
text = "⏸ PAUZA" if self.is_paused else ""
|
||||||
|
self.canvas.itemconfig(self.pause_indicator_id, text=text)
|
||||||
|
|
||||||
|
def next_product(self):
|
||||||
|
if self.catalog_items:
|
||||||
|
self.show_product_by_index(self.current_catalog_index)
|
||||||
|
self.current_catalog_index = (self.current_catalog_index + 1) % len(self.catalog_items)
|
||||||
|
|
||||||
|
def prev_product(self):
|
||||||
|
if self.catalog_items:
|
||||||
|
prev_idx = (self.current_catalog_index - 2) % len(self.catalog_items)
|
||||||
|
self.show_product_by_index(prev_idx)
|
||||||
|
self.current_catalog_index = (prev_idx + 1) % len(self.catalog_items)
|
||||||
|
|
||||||
|
def reload_catalog_action(self):
|
||||||
|
self.load_catalog()
|
||||||
|
if self.catalog_items:
|
||||||
|
self.show_product_by_index(0)
|
||||||
|
self.current_catalog_index = 1 % len(self.catalog_items)
|
||||||
|
|
||||||
|
def update_card_background(self, rgba_color):
|
||||||
|
self.current_card_rgba = rgba_color
|
||||||
|
img = Image.new("RGBA", (self.card_w, self.card_h), (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
r, g, b, a = rgba_color
|
||||||
|
border_color = (min(r + 80, 255), min(g + 80, 255), min(b + 80, 255), 200)
|
||||||
|
|
||||||
|
draw.rounded_rectangle([0, 0, self.card_w - 1, self.card_h - 1], radius=16, fill=rgba_color, outline=border_color, width=2)
|
||||||
|
|
||||||
|
self.card_bg_photo = ImageTk.PhotoImage(img)
|
||||||
|
self.canvas.itemconfig(self.card_bg_id, image=self.card_bg_photo)
|
||||||
|
|
||||||
def load_catalog(self):
|
def load_catalog(self):
|
||||||
global KATALOG_DIR
|
global KATALOG_DIR
|
||||||
@@ -114,17 +462,18 @@ class FullscreenJarmarkDisplay:
|
|||||||
|
|
||||||
self.catalog_items = []
|
self.catalog_items = []
|
||||||
if not os.path.exists(KATALOG_DIR):
|
if not os.path.exists(KATALOG_DIR):
|
||||||
print(f"Adresář 'katalog' neexistuje na cestě: {KATALOG_DIR}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
valid_extensions = ('.png', '.jpg', '.jpeg', '.webp')
|
||||||
|
|
||||||
for folder_name in sorted(os.listdir(KATALOG_DIR)):
|
for folder_name in sorted(os.listdir(KATALOG_DIR)):
|
||||||
folder_path = os.path.join(KATALOG_DIR, folder_name)
|
folder_path = os.path.join(KATALOG_DIR, folder_name)
|
||||||
if os.path.isdir(folder_path):
|
if os.path.isdir(folder_path):
|
||||||
info_path = os.path.join(folder_path, "info.txt")
|
info_path = os.path.join(folder_path, "info.txt")
|
||||||
image_path = os.path.join(folder_path, "image.png")
|
|
||||||
|
|
||||||
title = folder_name
|
title = folder_name
|
||||||
price = ""
|
price = ""
|
||||||
|
badge = ""
|
||||||
|
|
||||||
if os.path.exists(info_path):
|
if os.path.exists(info_path):
|
||||||
try:
|
try:
|
||||||
@@ -134,67 +483,164 @@ class FullscreenJarmarkDisplay:
|
|||||||
title = lines[0]
|
title = lines[0]
|
||||||
if len(lines) >= 2:
|
if len(lines) >= 2:
|
||||||
price = lines[1]
|
price = lines[1]
|
||||||
|
if len(lines) >= 3:
|
||||||
|
badge = lines[2]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Chyba při čtení {info_path}: {e}")
|
print(f"Chyba při čtení {info_path}: {e}")
|
||||||
|
|
||||||
|
images = [f for f in os.listdir(folder_path) if f.lower().endswith(valid_extensions)]
|
||||||
|
images.sort(key=natural_sort_key)
|
||||||
|
image_paths = [os.path.join(folder_path, img) for img in images]
|
||||||
|
|
||||||
self.catalog_items.append({
|
self.catalog_items.append({
|
||||||
"title": title,
|
"title": title,
|
||||||
"price": price,
|
"price": price,
|
||||||
"image_path": image_path if os.path.exists(image_path) else None
|
"badge": badge,
|
||||||
|
"image_paths": image_paths
|
||||||
})
|
})
|
||||||
|
|
||||||
def cycle_product(self):
|
def cycle_product(self):
|
||||||
if self.current_catalog_index == 0:
|
if not self.is_paused:
|
||||||
self.load_catalog()
|
if not self.catalog_items:
|
||||||
|
self.load_catalog()
|
||||||
|
|
||||||
if self.catalog_items:
|
if self.catalog_items:
|
||||||
self.current_catalog_index %= len(self.catalog_items)
|
self.show_product_by_index(self.current_catalog_index)
|
||||||
item = self.catalog_items[self.current_catalog_index]
|
self.current_catalog_index = (self.current_catalog_index + 1) % len(self.catalog_items)
|
||||||
|
|
||||||
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)
|
self.root.after(CYCLE_INTERVAL_MS, self.cycle_product)
|
||||||
|
|
||||||
|
def show_product_by_index(self, index):
|
||||||
|
if not self.catalog_items:
|
||||||
|
return
|
||||||
|
|
||||||
|
idx = index % len(self.catalog_items)
|
||||||
|
self.active_item = self.catalog_items[idx]
|
||||||
|
|
||||||
|
self.canvas.itemconfig(self.title_text_id, text=self.active_item["title"])
|
||||||
|
self.canvas.itemconfig(self.title_shadow_id, text=self.active_item["title"])
|
||||||
|
|
||||||
|
price_val = self.active_item["price"]
|
||||||
|
self.canvas.itemconfig(self.price_text_id, text=price_val)
|
||||||
|
self.canvas.itemconfig(self.price_shadow_id, text=price_val)
|
||||||
|
if price_val:
|
||||||
|
self.canvas.itemconfig(self.price_bg_id, state="normal")
|
||||||
|
self.canvas.itemconfig(self.price_shadow_id, state="normal")
|
||||||
|
self.canvas.itemconfig(self.price_text_id, state="normal")
|
||||||
|
else:
|
||||||
|
self.canvas.itemconfig(self.price_bg_id, state="hidden")
|
||||||
|
self.canvas.itemconfig(self.price_shadow_id, state="hidden")
|
||||||
|
self.canvas.itemconfig(self.price_text_id, state="hidden")
|
||||||
|
|
||||||
|
badge_val = self.active_item["badge"]
|
||||||
|
if badge_val:
|
||||||
|
badge_upper = badge_val.upper()
|
||||||
|
if any(w in badge_upper for w in ["VYPRODÁNO", "NENÍ", "OUT"]):
|
||||||
|
bg_color, text_color = "#e63946", "#ffffff"
|
||||||
|
elif any(w in badge_upper for w in ["AKCE", "SLEVA", "SALE", "%"]):
|
||||||
|
bg_color, text_color = "#f77f00", "#ffffff"
|
||||||
|
elif any(w in badge_upper for w in ["NOVINKA", "NEW", "TOP"]):
|
||||||
|
bg_color, text_color = "#2a9d8f", "#ffffff"
|
||||||
|
else:
|
||||||
|
bg_color, text_color = "#7209b7", "#ffffff"
|
||||||
|
|
||||||
|
self.canvas.itemconfig(self.badge_text_id, text=f" {badge_val.upper()} ", fill=text_color, state="normal")
|
||||||
|
|
||||||
|
badge_y = self.h * 0.14
|
||||||
|
self.canvas.coords(self.badge_text_id, self.w * 0.5, badge_y)
|
||||||
|
|
||||||
|
bbox = self.canvas.bbox(self.badge_text_id)
|
||||||
|
if bbox:
|
||||||
|
x1, y1, x2, y2 = bbox
|
||||||
|
self.canvas.coords(self.badge_bg_id, x1 - 12, y1 - 5, x2 + 12, y2 + 5)
|
||||||
|
self.canvas.itemconfig(self.badge_bg_id, fill=bg_color, outline="#ffffff", width=1, state="normal")
|
||||||
|
else:
|
||||||
|
self.canvas.itemconfig(self.badge_text_id, state="hidden")
|
||||||
|
self.canvas.itemconfig(self.badge_bg_id, state="hidden")
|
||||||
|
|
||||||
|
self.current_frame_index = 0
|
||||||
|
self.update_product_frame()
|
||||||
|
|
||||||
|
def animate_product_3d(self):
|
||||||
|
if self.active_item:
|
||||||
|
paths = self.active_item["image_paths"]
|
||||||
|
if len(paths) > 1:
|
||||||
|
self.current_frame_index = (self.current_frame_index + 1) % len(paths)
|
||||||
|
self.update_product_frame()
|
||||||
|
|
||||||
|
self.root.after(FRAME_INTERVAL_MS, self.animate_product_3d)
|
||||||
|
|
||||||
|
def update_product_frame(self):
|
||||||
|
if not self.active_item:
|
||||||
|
return
|
||||||
|
|
||||||
|
paths = self.active_item["image_paths"]
|
||||||
|
if paths:
|
||||||
|
img_path = paths[self.current_frame_index % len(paths)]
|
||||||
|
try:
|
||||||
|
raw_img = Image.open(img_path).convert("RGBA")
|
||||||
|
max_w = int(self.w * 0.42)
|
||||||
|
max_h = int(self.h * 0.52)
|
||||||
|
|
||||||
|
raw_img.thumbnail((max_w, max_h), 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í snímku {img_path}: {e}")
|
||||||
|
self.canvas.itemconfig(self.prod_image_id, image="")
|
||||||
|
else:
|
||||||
|
self.canvas.itemconfig(self.prod_image_id, image="")
|
||||||
|
|
||||||
def poll_data(self):
|
def poll_data(self):
|
||||||
|
pythoncom.CoInitialize()
|
||||||
while self.running:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
res = requests.get(SERVER_URL, timeout=1)
|
res = requests.get(SERVER_URL, timeout=1)
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
data = res.json()
|
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)
|
artist = str(data.get("artist", "")).strip()
|
||||||
|
title = str(data.get("title", "")).strip()
|
||||||
|
progress = str(data.get("progressTime", "0:00/0:00"))
|
||||||
|
img_url = data.get("coverImg", None)
|
||||||
|
is_ad_flag = bool(data.get("isAd", False) or data.get("is_ad", False))
|
||||||
|
|
||||||
|
# Sloučíme VŠECHNY hodnoty z JSONu do jednoho řetězce (pro jistotu, kdyby rozšíření poslalo text v jiném poli)
|
||||||
|
all_text_values = " ".join([str(v).lower() for v in data.values()])
|
||||||
|
|
||||||
|
# Kompletní a rozšířený seznam frází pro spolehlivou detekci reklam
|
||||||
|
ad_phrases = [
|
||||||
|
"advertisement", "reklama", "přetvoř svůj poslech",
|
||||||
|
"pretvor svoj poslech", "tvoje uši si zaslouží",
|
||||||
|
"spotify premium", "sponzorované", "sponzorovano",
|
||||||
|
"spotify partner", "partner", "commercial", "spot",
|
||||||
|
"poslech", "hudba", "atmosféra", "atmosfera",
|
||||||
|
"1 z 2", "2 z 2", "1 z 1", "2 z 1", "zaslouží",
|
||||||
|
"zaslouzi", "premium", "propagace", "z 2", "z 1"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Detekce shody buď podle frází kdekoli v datech, nebo podle speciálního vzoru Spotify + čítač (např. 2 z 2)
|
||||||
|
matched_phrase = next((p for p in ad_phrases if p in all_text_values), None)
|
||||||
|
is_spotify_ad_pattern = "spotify" in all_text_values and ("z 2" in all_text_values or "z 1" in all_text_values or "reklama" in all_text_values)
|
||||||
|
|
||||||
|
is_ad_detected = is_ad_flag or (matched_phrase is not None) or is_spotify_ad_pattern
|
||||||
|
|
||||||
|
# Debug výpis do konzole, abyste viděl, co přesně přišlo
|
||||||
|
if is_ad_detected:
|
||||||
|
print(f"[REKLAMA DETEKOVÁNA] Zastavuji zvuk. (Shoda s frází: '{matched_phrase}' / vzor Spotify | Všechna data: {all_text_values})")
|
||||||
|
if not self.is_ad_active:
|
||||||
|
self.is_ad_active = True
|
||||||
|
self.trigger_ad_sound()
|
||||||
|
else:
|
||||||
|
if self.is_ad_active:
|
||||||
|
print(f"[KONEC REKLAMY] Vracím hlasitost. | Všechna data: {all_text_values}")
|
||||||
|
self.is_ad_active = False
|
||||||
|
self.stop_ad_sound()
|
||||||
|
|
||||||
|
self.root.after(0, self.update_gui, artist, title, progress, img_url, self.is_ad_active)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
time.sleep(0.8)
|
time.sleep(0.4)
|
||||||
|
|
||||||
def parse_time_to_seconds(self, time_str):
|
def parse_time_to_seconds(self, time_str):
|
||||||
try:
|
try:
|
||||||
@@ -203,9 +649,16 @@ class FullscreenJarmarkDisplay:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def update_gui(self, artist, title, progress, img_url):
|
def update_gui(self, artist, title, progress, img_url, is_ad=False):
|
||||||
self.canvas.itemconfig(self.spotify_title_id, text=title)
|
if is_ad:
|
||||||
self.canvas.itemconfig(self.spotify_subtitle_id, text=f"Hudobné video • {artist}")
|
title_disp = "📢 REKLAMA"
|
||||||
|
artist_disp = "Spotify Partner"
|
||||||
|
else:
|
||||||
|
title_disp = title if len(title) <= 22 else title[:20] + "..."
|
||||||
|
artist_disp = artist if len(artist) <= 26 else artist[:24] + "..."
|
||||||
|
|
||||||
|
self.canvas.itemconfig(self.spotify_title_id, text=title_disp)
|
||||||
|
self.canvas.itemconfig(self.spotify_subtitle_id, text=artist_disp)
|
||||||
|
|
||||||
if "/" in progress:
|
if "/" in progress:
|
||||||
curr, dur = progress.split("/")
|
curr, dur = progress.split("/")
|
||||||
@@ -216,10 +669,14 @@ class FullscreenJarmarkDisplay:
|
|||||||
d_sec = self.parse_time_to_seconds(dur)
|
d_sec = self.parse_time_to_seconds(dur)
|
||||||
percent = (c_sec / d_sec) if d_sec > 0 else 0
|
percent = (c_sec / d_sec) if d_sec > 0 else 0
|
||||||
|
|
||||||
start_x = 220
|
text_x = self.card_x1 + int(self.card_h * 0.82)
|
||||||
max_w = 1800 - start_x
|
bar_x1 = text_x
|
||||||
fill_x = start_x + int(max_w * percent)
|
bar_x2 = self.card_x1 + self.card_w - int(self.card_h * 0.12)
|
||||||
self.canvas.coords(self.pbar_fg, start_x, 1040, fill_x, 1040)
|
bar_y = self.card_y1 + int(self.card_h * 0.68)
|
||||||
|
|
||||||
|
max_w = bar_x2 - bar_x1
|
||||||
|
fill_x = bar_x1 + int(max_w * percent)
|
||||||
|
self.canvas.coords(self.pbar_fg, bar_x1, bar_y, fill_x, bar_y)
|
||||||
|
|
||||||
if img_url and img_url != self.current_img_url:
|
if img_url and img_url != self.current_img_url:
|
||||||
self.current_img_url = img_url
|
self.current_img_url = img_url
|
||||||
@@ -229,13 +686,27 @@ class FullscreenJarmarkDisplay:
|
|||||||
try:
|
try:
|
||||||
res = requests.get(url, timeout=3)
|
res = requests.get(url, timeout=3)
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
raw_img = Image.open(BytesIO(res.content)).convert("RGBA")
|
self.raw_cover_img = Image.open(BytesIO(res.content)).convert("RGBA")
|
||||||
raw_img = raw_img.resize((100, 100), Image.Resampling.LANCZOS)
|
|
||||||
|
small_img = self.raw_cover_img.resize((1, 1), Image.Resampling.BILINEAR)
|
||||||
|
dom_color = small_img.getpixel((0, 0))
|
||||||
|
|
||||||
|
dark_r = int(dom_color[0] * 0.35)
|
||||||
|
dark_g = int(dom_color[1] * 0.35)
|
||||||
|
dark_b = int(dom_color[2] * 0.35)
|
||||||
|
card_rgba = (dark_r, dark_g, dark_b, 225)
|
||||||
|
|
||||||
|
cover_size = int(self.card_h * 0.58)
|
||||||
|
cover_img = self.raw_cover_img.resize((cover_size, cover_size), Image.Resampling.LANCZOS)
|
||||||
|
self.photo_cover = ImageTk.PhotoImage(cover_img)
|
||||||
|
|
||||||
|
self.root.after(0, lambda: [
|
||||||
|
self.canvas.itemconfig(self.cover_img_id, image=self.photo_cover),
|
||||||
|
self.update_card_background(card_rgba)
|
||||||
|
])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Chyba při načítání obalu alba: {e}")
|
||||||
|
|
||||||
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__":
|
if __name__ == "__main__":
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
|
|||||||
Reference in New Issue
Block a user