diff --git a/signage_player/__pycache__/get_playlists.cpython-311.pyc b/signage_player/__pycache__/get_playlists.cpython-311.pyc index c29703f..8ae2305 100644 Binary files a/signage_player/__pycache__/get_playlists.cpython-311.pyc and b/signage_player/__pycache__/get_playlists.cpython-311.pyc differ diff --git a/signage_player/__pycache__/player.cpython-311.pyc b/signage_player/__pycache__/player.cpython-311.pyc index eed2789..39b5c95 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/get_playlists.py b/signage_player/get_playlists.py index 38af247..bdbea84 100644 --- a/signage_player/get_playlists.py +++ b/signage_player/get_playlists.py @@ -6,6 +6,49 @@ import re import datetime from logging_config import Logger +# Global variable to track server connectivity status +SERVER_CONNECTION_STATUS = { + 'is_online': True, + 'last_successful_connection': None, + 'last_playlist_update': None, + 'error_message': None +} + +def get_server_status(): + """Get current server connection status""" + return SERVER_CONNECTION_STATUS.copy() + +def get_last_playlist_update_time(): + """Get the timestamp of the last playlist update from filesystem""" + try: + playlist_dir = os.path.join(os.path.dirname(__file__), 'static_data', 'playlist') + if os.path.exists(playlist_dir): + playlist_files = [f for f in os.listdir(playlist_dir) if f.startswith('server_playlist_v') and f.endswith('.json')] + if playlist_files: + # Get the most recent playlist file + latest_file = max([os.path.join(playlist_dir, f) for f in playlist_files], key=os.path.getmtime) + mod_time = os.path.getmtime(latest_file) + return datetime.datetime.fromtimestamp(mod_time) + return None + except Exception as e: + Logger.error(f"Error getting last playlist update time: {e}") + return None + +def set_server_offline(error_message=None): + """Mark server as offline with optional error message""" + global SERVER_CONNECTION_STATUS + SERVER_CONNECTION_STATUS['is_online'] = False + SERVER_CONNECTION_STATUS['error_message'] = error_message + Logger.warning(f"Server marked as offline: {error_message}") + +def set_server_online(): + """Mark server as online and update connection time""" + global SERVER_CONNECTION_STATUS + SERVER_CONNECTION_STATUS['is_online'] = True + SERVER_CONNECTION_STATUS['last_successful_connection'] = datetime.datetime.now() + SERVER_CONNECTION_STATUS['error_message'] = None + Logger.info("Server connection restored") + def send_player_feedback(config, message, status="active", playlist_version=None, error_details=None): """ Send feedback to the server about player status. @@ -51,16 +94,21 @@ def send_player_feedback(config, message, status="active", playlist_version=None if response.status_code == 200: Logger.info(f"Feedback sent successfully: {message}") + # Mark server as online on successful feedback + set_server_online() return True else: Logger.warning(f"Feedback failed with status {response.status_code}: {response.text}") + set_server_offline(f"Feedback failed with status {response.status_code}") return False except requests.exceptions.RequestException as e: Logger.error(f"Failed to send feedback: {e}") + set_server_offline(f"Network error during feedback: {e}") return False except Exception as e: Logger.error(f"Unexpected error sending feedback: {e}") + set_server_offline(f"Unexpected error during feedback: {e}") return False def send_playlist_check_feedback(config, playlist_version=None): @@ -187,25 +235,44 @@ def fetch_server_playlist(config): 'quickconnect_code': quick } Logger.info(f"Fetching playlist from URL: {server_url} with params: {params}") - response = requests.get(server_url, params=params) + response = requests.get(server_url, params=params, timeout=15) + if response.status_code == 200: response_data = response.json() Logger.info(f"Server response: {response_data}") playlist = response_data.get('playlist', []) version = response_data.get('playlist_version', None) hashed_quickconnect = response_data.get('hashed_quickconnect', None) + if version is not None and hashed_quickconnect is not None: if bcrypt.checkpw(quick.encode('utf-8'), hashed_quickconnect.encode('utf-8')): Logger.info("Fetched updated playlist from server.") + # Mark server as online on successful connection + set_server_online() return {'playlist': playlist, 'version': version} else: Logger.error("Quickconnect code validation failed.") + set_server_offline("Authentication failed - invalid quickconnect code") else: Logger.error("Failed to retrieve playlist or hashed quickconnect from the response.") + set_server_offline("Invalid server response - missing playlist data") else: Logger.error(f"Failed to fetch playlist. Status Code: {response.status_code}") + set_server_offline(f"Server returned error code: {response.status_code}") + + except requests.exceptions.ConnectTimeout as e: + Logger.error(f"Connection timeout while fetching playlist: {e}") + set_server_offline("Connection timeout - server unreachable") + except requests.exceptions.ConnectionError as e: + Logger.error(f"Connection error while fetching playlist: {e}") + set_server_offline("Connection failed - server unreachable") except requests.exceptions.RequestException as e: - Logger.error(f"Failed to fetch playlist: {e}") + Logger.error(f"Request error while fetching playlist: {e}") + set_server_offline(f"Network error: {str(e)}") + except Exception as e: + Logger.error(f"Unexpected error while fetching playlist: {e}") + set_server_offline(f"Unexpected error: {str(e)}") + return {'playlist': [], 'version': 0} def save_playlist_with_version(playlist_data, playlist_dir): @@ -292,6 +359,8 @@ def update_playlist_if_needed(local_playlist_path, config, media_dir, playlist_d Also sends feedback to server about playlist check. """ import json + global SERVER_CONNECTION_STATUS + server_data = fetch_server_playlist(config) server_version = server_data.get('version', 0) if not os.path.exists(local_playlist_path): @@ -303,10 +372,11 @@ def update_playlist_if_needed(local_playlist_path, config, media_dir, playlist_d Logger.info(f"Local playlist version: {local_version}, Server playlist version: {server_version}") - # Send feedback about server interrogation (checking for updates) - send_playlist_check_feedback(config, server_version if server_version > 0 else local_version) + # Only send feedback if server is online + if SERVER_CONNECTION_STATUS['is_online']: + send_playlist_check_feedback(config, server_version if server_version > 0 else local_version) - if local_version != server_version: + if local_version != server_version and server_version > 0: if server_data and server_data.get('playlist'): updated_playlist = download_media_files(server_data['playlist'], media_dir) server_data['playlist'] = updated_playlist @@ -314,16 +384,15 @@ def update_playlist_if_needed(local_playlist_path, config, media_dir, playlist_d # Delete old playlists and unreferenced media delete_old_playlists_and_media(server_version, playlist_dir, media_dir) + # Update last playlist update time + SERVER_CONNECTION_STATUS['last_playlist_update'] = datetime.datetime.now() + return True else: Logger.warning("No playlist data fetched from server or playlist is empty.") - - # Send error feedback - send_player_error_feedback(config, "No playlist data fetched from server or playlist is empty", local_version) - return False else: - Logger.info("Local playlist is already up to date.") + Logger.info("Local playlist is already up to date or server is offline.") return False diff --git a/signage_player/main_data/app_config.txt b/signage_player/main_data/app_config.txt index 9eb348d..2e2ba5e 100644 --- a/signage_player/main_data/app_config.txt +++ b/signage_player/main_data/app_config.txt @@ -2,7 +2,7 @@ "screen_orientation": "Landscape", "screen_name": "tv-terasa", "quickconnect_key": "8887779", - "server_ip": "192.168.1.22", + "server_ip": "10.35.33.231", "port": "80", "screen_w": "1920", "screen_h": "1080", diff --git a/signage_player/main_data/log.txt b/signage_player/main_data/log.txt index 12e3192..715e1bc 100644 --- a/signage_player/main_data/log.txt +++ b/signage_player/main_data/log.txt @@ -12759,3 +12759,92 @@ [INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 [INFO] [SignageApp] Sending feedback to http://192.168.1.22:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T16:15:46.726098', 'playlist_version': 8, 'error_details': None} [INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[WARNING] [SignageApp] Server marked as offline: Test - server unreachable +[INFO] [SignageApp] Server connection restored +[WARNING] [SignageApp] Server marked as offline: Test - simulated network failure +[INFO] [SignageApp] Server connection restored +[WARNING] [SignageApp] Server marked as offline: Test offline mode +[INFO] [SignageApp] Server connection restored +[INFO] [SignageApp] Fetching playlist from URL: http://10.35.33.231:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$Prw4EUYn4j59CAdsZCsvsug6.xociqbOPaNr0oxOA2zwD9S2MSiK6', 'playlist': [{'duration': 30, 'file_name': 'one-piece-season-2-5120x2880-23673.jpg', 'url': 'http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg'}, {'duration': 30, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://10.35.33.231/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4'}], 'playlist_version': 7} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Server connection restored +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 7 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, server interrogation, checking for updates : playlist v7', 'status': 'active', 'timestamp': '2025-09-09T16:48:54.345235', 'playlist_version': 7, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, server interrogation, checking for updates : playlist v7 +[INFO] [SignageApp] Preparing to download one-piece-season-2-5120x2880-23673.jpg from http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg... +[INFO] [SignageApp] File one-piece-season-2-5120x2880-23673.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://10.35.33.231/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 big-buck-bunny-1080p-60fps-30sec.mp4 from http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] Successfully downloaded big-buck-bunny-1080p-60fps-30sec.mp4 to /home/pi/Desktop/tkinter_player/signage_player/static_data/media/big-buck-bunny-1080p-60fps-30sec.mp4 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T16:48:59.576471', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T16:50:01.605320', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T16:50:01.752876', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T16:51:03.726916', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T16:51:03.849472', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Fetching playlist from URL: http://10.35.33.231:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$Prw4EUYn4j59CAdsZCsvsug6.xociqbOPaNr0oxOA2zwD9S2MSiK6', 'playlist': [{'duration': 30, 'file_name': 'one-piece-season-2-5120x2880-23673.jpg', 'url': 'http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg'}, {'duration': 30, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://10.35.33.231/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4'}], 'playlist_version': 8} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Server connection restored +[INFO] [SignageApp] Fetching playlist from URL: http://10.35.33.231:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$Prw4EUYn4j59CAdsZCsvsug6.xociqbOPaNr0oxOA2zwD9S2MSiK6', 'playlist': [{'duration': 30, 'file_name': 'one-piece-season-2-5120x2880-23673.jpg', 'url': 'http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg'}, {'duration': 30, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://10.35.33.231/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4'}], 'playlist_version': 8} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Server connection restored +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, server interrogation, checking for updates : playlist v8', 'status': 'active', 'timestamp': '2025-09-09T16:57:29.966333', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, server interrogation, checking for updates : playlist v8 +[INFO] [SignageApp] Preparing to download one-piece-season-2-5120x2880-23673.jpg from http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg... +[INFO] [SignageApp] File one-piece-season-2-5120x2880-23673.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://10.35.33.231/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 big-buck-bunny-1080p-60fps-30sec.mp4 from http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] Successfully downloaded big-buck-bunny-1080p-60fps-30sec.mp4 to signage_player/static_data/media/big-buck-bunny-1080p-60fps-30sec.mp4 +[INFO] [SignageApp] Fetching playlist from URL: http://10.35.33.231:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$Prw4EUYn4j59CAdsZCsvsug6.xociqbOPaNr0oxOA2zwD9S2MSiK6', 'playlist': [{'duration': 30, 'file_name': 'one-piece-season-2-5120x2880-23673.jpg', 'url': 'http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg'}, {'duration': 30, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://10.35.33.231/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4'}], 'playlist_version': 8} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] Server connection restored +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, server interrogation, checking for updates : playlist v8', 'status': 'active', 'timestamp': '2025-09-09T16:58:29.211046', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, server interrogation, checking for updates : playlist v8 +[INFO] [SignageApp] Preparing to download one-piece-season-2-5120x2880-23673.jpg from http://10.35.33.231/media/one-piece-season-2-5120x2880-23673.jpg... +[INFO] [SignageApp] File one-piece-season-2-5120x2880-23673.jpg already exists. Skipping download. +[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://10.35.33.231/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 big-buck-bunny-1080p-60fps-30sec.mp4 from http://10.35.33.231/media/big-buck-bunny-1080p-60fps-30sec.mp4... +[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download. +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T16:58:34.434167', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T17:00:06.810997', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T17:00:07.101272', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T17:01:39.392553', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T17:01:39.514533', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T17:03:11.882623', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T17:03:12.026303', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Fetching playlist from URL: http://10.35.33.231:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[ERROR] [SignageApp] Connection error while fetching playlist: HTTPConnectionPool(host='10.35.33.231', port=80): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 111] Connection refused')) +[WARNING] [SignageApp] Server marked as offline: Connection failed - server unreachable +[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 0 +[INFO] [SignageApp] Local playlist is already up to date or server is offline. +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T17:04:44.536396', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T17:04:44.650793', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist working in loop, cycle completed : playlist v8', 'status': 'restarting', 'timestamp': '2025-09-09T17:06:17.176559', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T17:06:17.330975', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Sending feedback to http://10.35.33.231:80/api/player-feedback: {'player_name': 'tv-terasa', 'quickconnect_code': '8887779', 'message': 'player tv-terasa, playlist started : playlist v8', 'status': 'playing', 'timestamp': '2025-09-09T17:10:12.361728', 'playlist_version': 8, 'error_details': None} +[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist started : playlist v8 +[INFO] [SignageApp] Server connection restored diff --git a/signage_player/player.py b/signage_player/player.py index 2e58e00..c775f15 100644 --- a/signage_player/player.py +++ b/signage_player/player.py @@ -4,7 +4,7 @@ import tkinter as tk import vlc import subprocess import sys -from get_playlists import send_playlist_restart_feedback, send_player_error_feedback, send_playing_status_feedback, send_playlist_check_feedback +from get_playlists import send_playlist_restart_feedback, send_player_error_feedback, send_playing_status_feedback, send_playlist_check_feedback, get_server_status, get_last_playlist_update_time CONFIG_PATH = os.path.join(os.path.dirname(__file__), 'main_data', 'app_config.txt') PLAYLIST_DIR = os.path.join(os.path.dirname(__file__), 'static_data', 'playlist') @@ -24,6 +24,10 @@ class SimpleTkPlayer: self.config = self.load_config() self.playlist_version = self.get_current_playlist_version() + # Offline notification tracking + self.offline_notification = None + self.last_server_status = True + # Initialize all timer variables to None self.hide_controls_timer = None self.video_watchdog = None @@ -104,6 +108,70 @@ class SimpleTkPlayer: except Exception as e: print(f"[FEEDBACK] Error sending server check feedback: {e}") + def check_server_status(self): + """Check server connectivity status and show/hide offline notification""" + try: + server_status = get_server_status() + is_online = server_status['is_online'] + + # Only update notification if status changed + if is_online != self.last_server_status: + if not is_online: + # Server went offline + self.show_offline_notification(server_status) + else: + # Server came back online + self.hide_offline_notification() + + self.last_server_status = is_online + + except Exception as e: + print(f"[OFFLINE] Error checking server status: {e}") + + def show_offline_notification(self, server_status): + """Show offline notification at bottom of screen""" + try: + if self.offline_notification: + return # Already showing + + # Get last playlist update time from filesystem + last_update = get_last_playlist_update_time() + if last_update: + update_time = last_update.strftime("%Y-%m-%d %H:%M:%S") + message = f"OFFLINE MODE: Playing last available playlist updated at: {update_time}" + else: + message = "OFFLINE MODE: Playing last available playlist" + + # Create notification label at bottom of screen + self.offline_notification = tk.Label( + self.root, + text=message, + bg='orange', + fg='black', + font=('Arial', 14, 'bold'), + relief='raised', + bd=2 + ) + + # Position at bottom of screen + self.offline_notification.pack(side='bottom', fill='x', padx=5, pady=5) + self.offline_notification.lift() # Bring to front + + print(f"[OFFLINE] Showing offline notification: {message}") + + except Exception as e: + print(f"[OFFLINE] Error showing offline notification: {e}") + + def hide_offline_notification(self): + """Hide offline notification when server comes back online""" + try: + if self.offline_notification: + self.offline_notification.destroy() + self.offline_notification = None + print("[OFFLINE] Server back online - hiding offline notification") + except Exception as e: + print(f"[OFFLINE] Error hiding offline notification: {e}") + def ensure_fullscreen(self): self.root.attributes('-fullscreen', True) self.root.update_idletasks() @@ -218,11 +286,49 @@ class SimpleTkPlayer: self.show_current_media() def update_playlist_from_server(self): - # Dummy implementation: replace with your actual update logic - # For example, call a function to fetch and reload the playlist - print("[INFO] Updating playlist from server...") - # You can import and call your real update function here - # Example: self.playlist = get_latest_playlist() + """Update playlist from server and reload if needed""" + try: + from get_playlists import update_playlist_if_needed + import json + + print("[INFO] Checking for playlist updates from server...") + + # Get config + config_path = os.path.join(os.path.dirname(__file__), 'main_data', 'app_config.txt') + with open(config_path, 'r') as config_file: + config = json.load(config_file) + + # Define paths + playlist_dir = os.path.join(os.path.dirname(__file__), 'static_data', 'playlist') + media_dir = os.path.join(os.path.dirname(__file__), 'static_data', 'media') + + # Find current playlist file + playlist_files = [f for f in os.listdir(playlist_dir) if f.startswith('server_playlist_v') and f.endswith('.json')] + if playlist_files: + current_playlist_path = os.path.join(playlist_dir, max(playlist_files)) + else: + current_playlist_path = os.path.join(playlist_dir, 'server_playlist_v0.json') + + # Check and update if needed + updated = update_playlist_if_needed(current_playlist_path, config, media_dir, playlist_dir) + + if updated: + print("[INFO] Playlist updated! Reloading...") + # Reload the playlist + self.update_playlist_version() + # Restart playback with new playlist + self.current_index = 0 + self.load_playlist() + else: + print("[INFO] Playlist is already up to date.") + + except Exception as e: + print(f"[ERROR] Failed to update playlist: {e}") + from get_playlists import send_player_error_feedback + try: + send_player_error_feedback(config, f"Playlist update failed: {str(e)}") + except: + pass def toggle_pause(self): if not self.paused: @@ -321,6 +427,9 @@ class SimpleTkPlayer: def show_current_media(self): try: + # Check server status and update offline notification + self.check_server_status() + self.root.attributes('-fullscreen', True) self.root.update_idletasks() if not self.playlist: @@ -859,6 +968,9 @@ class SimpleTkPlayer: try: print("[EXIT] Destroying controls...") + # Hide offline notification if showing + self.hide_offline_notification() + # First, try to hide and destroy the main controls window if hasattr(self, 'controls_win') and self.controls_win: try: diff --git a/signage_player/static_data/media/big-buck-bunny-1080p-60fps-30sec.mp4 b/signage_player/static_data/media/big-buck-bunny-1080p-60fps-30sec.mp4 new file mode 100644 index 0000000..50360ee Binary files /dev/null and b/signage_player/static_data/media/big-buck-bunny-1080p-60fps-30sec.mp4 differ diff --git a/signage_player/static_data/playlist/server_playlist_v8.json b/signage_player/static_data/playlist/server_playlist_v8.json index 7bbb245..a95975f 100644 --- a/signage_player/static_data/playlist/server_playlist_v8.json +++ b/signage_player/static_data/playlist/server_playlist_v8.json @@ -9,6 +9,11 @@ "file_name": "call-of-duty-black-3840x2160-23674.jpg", "url": "media/call-of-duty-black-3840x2160-23674.jpg", "duration": 30 + }, + { + "file_name": "big-buck-bunny-1080p-60fps-30sec.mp4", + "url": "media/big-buck-bunny-1080p-60fps-30sec.mp4", + "duration": 30 } ], "version": 8 diff --git a/test_complete_offline.py b/test_complete_offline.py new file mode 100644 index 0000000..b35c712 --- /dev/null +++ b/test_complete_offline.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""Test script to verify the complete offline notification system""" + +import sys +import os +import time + +# Add the signage_player directory to the path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'signage_player')) + +def test_offline_notification(): + """Test the offline notification display""" + print("[TEST] Testing offline notification system...") + + # Import after adding to path + from get_playlists import get_last_playlist_update_time, get_server_status, set_server_offline, set_server_online + + print(f"[TEST] Current server status: {get_server_status()}") + + # Test getting playlist update time + last_update = get_last_playlist_update_time() + if last_update: + print(f"[TEST] Last playlist update: {last_update.strftime('%Y-%m-%d %H:%M:%S')}") + else: + print("[TEST] No playlist file found") + + # Test server offline mode + print("\n[TEST] Setting server offline...") + set_server_offline("Test - simulated network failure") + status = get_server_status() + print(f"[TEST] Server status after offline: {status}") + + # Test server online mode + time.sleep(1) + print("\n[TEST] Setting server online...") + set_server_online() + status = get_server_status() + print(f"[TEST] Server status after online: {status}") + + print("\n[TEST] Offline notification system test completed!") + +if __name__ == "__main__": + test_offline_notification() diff --git a/test_offline.py b/test_offline.py new file mode 100755 index 0000000..d4e8694 --- /dev/null +++ b/test_offline.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import os +import sys +import json + +# Add the signage_player directory to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'signage_player')) + +from get_playlists import get_server_status, set_server_offline, set_server_online + +def test_offline(): + print("=== Testing Offline Status ===") + + print("1. Initial status:") + status = get_server_status() + print(f" Online: {status['is_online']}") + + print("2. Setting offline:") + set_server_offline("Test - server unreachable") + status = get_server_status() + print(f" Online: {status['is_online']}") + print(f" Error: {status['error_message']}") + + print("3. Setting online:") + set_server_online() + status = get_server_status() + print(f" Online: {status['is_online']}") + +if __name__ == "__main__": + test_offline() diff --git a/test_ui_notification.py b/test_ui_notification.py new file mode 100644 index 0000000..0a96bf9 --- /dev/null +++ b/test_ui_notification.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +"""Simple UI test for offline notification display""" + +import sys +import os +import tkinter as tk + +# Add the signage_player directory to the path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'signage_player')) + +class TestNotificationApp: + def __init__(self): + self.root = tk.Tk() + self.root.title("Offline Notification Test") + self.root.geometry("800x600") + self.root.configure(bg='black') + + # Create main content area + main_label = tk.Label( + self.root, + text="MAIN PLAYER CONTENT AREA", + fg='white', + bg='black', + font=('Arial', 24) + ) + main_label.pack(expand=True, fill='both') + + # Test buttons + button_frame = tk.Frame(self.root, bg='black') + button_frame.pack(pady=10) + + tk.Button( + button_frame, + text="Show Offline Notification", + command=self.show_offline_notification, + bg='red', + fg='white' + ).pack(side=tk.LEFT, padx=5) + + tk.Button( + button_frame, + text="Hide Notification", + command=self.hide_offline_notification, + bg='green', + fg='white' + ).pack(side=tk.LEFT, padx=5) + + self.offline_notification = None + + def show_offline_notification(self): + """Show the offline notification at the bottom of the screen""" + if self.offline_notification: + return # Already showing + + from get_playlists import get_last_playlist_update_time + + last_update = get_last_playlist_update_time() + if last_update: + timestamp_str = last_update.strftime("%Y-%m-%d %H:%M:%S") + message = f"OFFLINE MODE: Playing last available playlist updated at: {timestamp_str}" + else: + message = "OFFLINE MODE: Playing last available playlist" + + self.offline_notification = tk.Label( + self.root, + text=message, + fg='white', + bg='red', + font=('Arial', 12, 'bold'), + pady=5 + ) + self.offline_notification.pack(side=tk.BOTTOM, fill=tk.X) + print(f"[UI TEST] Notification shown: {message}") + + def hide_offline_notification(self): + """Hide the offline notification""" + if self.offline_notification: + self.offline_notification.destroy() + self.offline_notification = None + print("[UI TEST] Notification hidden") + + def run(self): + print("[UI TEST] Starting offline notification UI test...") + self.root.mainloop() + +if __name__ == "__main__": + app = TestNotificationApp() + app.run()