diff --git a/signage_player/__pycache__/player.cpython-311.pyc b/signage_player/__pycache__/player.cpython-311.pyc index bdecfb2..f6f277f 100644 Binary files a/signage_player/__pycache__/player.cpython-311.pyc and b/signage_player/__pycache__/player.cpython-311.pyc differ diff --git a/signage_player/appsettings.py b/signage_player/appsettings.py new file mode 100644 index 0000000..8a23066 --- /dev/null +++ b/signage_player/appsettings.py @@ -0,0 +1,90 @@ +import tkinter as tk +from tkinter import ttk, messagebox +import json +import os + +CONFIG_PATH = os.path.join(os.path.dirname(__file__), 'main_data', 'app_config.txt') + +class AppSettingsWindow(tk.Tk): + def __init__(self): + super().__init__() + self.title('App Settings') + self.geometry('440x600') # Increased height for better button visibility + self.resizable(False, False) + self.config(bg='#23272e') + self.fields = {} + self.load_config() + self.style = ttk.Style(self) + self.set_styles() + self.create_widgets() + + def set_styles(self): + self.style.theme_use('clam') + self.style.configure('TLabel', background='#23272e', foreground='#e0e0e0', font=('Segoe UI', 13, 'bold')) + self.style.configure('TEntry', fieldbackground='#2c313c', foreground='#e0e0e0', borderwidth=1, relief='flat', font=('Segoe UI', 12)) + self.style.map('TEntry', fieldbackground=[('active', '#23272e')]) + self.style.configure('TButton', background='#3b82f6', foreground='white', font=('Segoe UI', 13, 'bold'), borderwidth=0, focusthickness=3, focuscolor='#60a5fa', padding=8) + self.style.map('TButton', background=[('active', '#2563eb')]) + + def load_config(self): + try: + with open(CONFIG_PATH, 'r') as f: + self.config_data = json.load(f) + except Exception as e: + self.config_data = {} + messagebox.showerror('Error', f'Failed to load config: {e}') + + def save_config(self): + try: + for key, entry in self.fields.items(): + if hasattr(entry, 'get'): + self.config_data[key] = entry.get() + with open(CONFIG_PATH, 'w') as f: + json.dump(self.config_data, f, indent=4) + self.show_custom_popup('Success', 'Settings saved!') + except Exception as e: + messagebox.showerror('Error', f'Failed to save config: {e}') + + def show_custom_popup(self, title, message): + popup = tk.Toplevel(self) + popup.title(title) + popup.geometry('320x120') + popup.configure(bg='#23272e') + popup.resizable(False, False) + popup.attributes('-topmost', True) + ttk.Label(popup, text=title, style='TLabel').pack(pady=(18, 0)) + ttk.Label(popup, text=message, style='TLabel').pack(pady=(8, 0)) + close_btn = ttk.Button(popup, text='OK', style='TButton', command=popup.destroy) + close_btn.pack(pady=18) + popup.grab_set() + popup.after(5000, popup.destroy) + + def create_widgets(self): + title = ttk.Label(self, text='Application Settings', style='TLabel') + title.grid(row=0, column=0, columnspan=2, pady=(18, 6)) + warning = tk.Label(self, text='⚠️ Modify values only if necessary or instructed!', fg='#ffb300', bg='#23272e', font=('Segoe UI', 11, 'bold')) + warning.grid(row=1, column=0, columnspan=2, pady=(0, 18)) + row = 2 + for key, value in self.config_data.items(): + label = ttk.Label(self, text=key+':', style='TLabel') + label.grid(row=row, column=0, sticky='e', padx=18, pady=10) + if key == 'touch_screen': + var = tk.StringVar() + combo = ttk.Combobox(self, textvariable=var, values=['On', 'Off'], state='readonly', width=26) + combo.set(str(value)) + combo.grid(row=row, column=1, padx=10, pady=10) + self.fields[key] = combo + else: + entry = ttk.Entry(self, style='TEntry', width=28) + entry.insert(0, str(value)) + entry.grid(row=row, column=1, padx=10, pady=10) + self.fields[key] = entry + row += 1 + save_btn = ttk.Button(self, text='Save Settings', style='TButton', command=self.save_config) + save_btn.grid(row=row, column=0, pady=30, sticky='e', padx=(0,10)) + close_btn = ttk.Button(self, text='Close', style='TButton', command=self.destroy) + close_btn.grid(row=row, column=1, pady=30, sticky='w', padx=(10,0)) + +if __name__ == '__main__': + app = AppSettingsWindow() + app.mainloop() diff --git a/signage_player/main_data/app_config.txt b/signage_player/main_data/app_config.txt index a27e789..9eb348d 100644 --- a/signage_player/main_data/app_config.txt +++ b/signage_player/main_data/app_config.txt @@ -6,5 +6,6 @@ "port": "80", "screen_w": "1920", "screen_h": "1080", - "refresh_time": "5" -} + "refresh_time": "5", + "touch_screen": "On" +} \ No newline at end of file diff --git a/signage_player/main_data/log.txt b/signage_player/main_data/log.txt index 6eda3ad..b738990 100644 --- a/signage_player/main_data/log.txt +++ b/signage_player/main_data/log.txt @@ -193,3 +193,43 @@ [INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download. [INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg... [INFO] [SignageApp] File demo2.jpeg already exists. Skipping download. +[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4 +[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg... +[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg... +[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download. +[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4 +[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg... +[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg... +[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download. +[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4 +[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg... +[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg... +[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download. +[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4 +[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg... +[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg... +[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download. diff --git a/signage_player/player.py b/signage_player/player.py index ee838b2..d6f966a 100644 --- a/signage_player/player.py +++ b/signage_player/player.py @@ -79,9 +79,13 @@ class SimpleTkPlayer: def hide_mouse(self): self.root.config(cursor='none') + if hasattr(self, 'controls_win'): + self.controls_win.config(cursor='none') def show_mouse(self): self.root.config(cursor='arrow') + if hasattr(self, 'controls_win'): + self.controls_win.config(cursor='arrow') def move_mouse_to_corner(self): try: @@ -232,20 +236,18 @@ class SimpleTkPlayer: if self.paused is not True: self.paused = True self.pause_btn.config(text='▶ Resume') - settings_win = tk.Toplevel(self.root) - settings_win.title('Settings') - settings_win.geometry('400x300+100+100') - settings_win.transient(self.root) - settings_win.grab_set() - tk.Label(settings_win, text='Settings', font=('Arial', 18)).pack(pady=10) - # Example setting: close button - tk.Button(settings_win, text='Close', command=settings_win.destroy).pack(pady=20) - def on_close(): - settings_win.grab_release() - settings_win.destroy() + import subprocess, sys + settings_path = os.path.join(os.path.dirname(__file__), 'appsettings.py') + # Open settings in a new process so it doesn't block the main player + proc = subprocess.Popen([sys.executable, settings_path]) + # Wait for the settings window to close, then resume + self.root.after(1000, lambda: self.check_settings_closed(proc)) + + def check_settings_closed(self, proc): + if proc.poll() is not None: self.resume_play() - settings_win.protocol('WM_DELETE_WINDOW', on_close) - settings_win.bind('', lambda e: self.resume_play() if not settings_win.winfo_exists() else None) + else: + self.root.after(1000, lambda: self.check_settings_closed(proc)) def main_start(self): self.play_intro_video()