updated to show when is not online

This commit is contained in:
2025-09-09 17:11:25 +03:00
parent a91b07ede4
commit 26fc946a65
11 changed files with 453 additions and 17 deletions

View File

@@ -6,6 +6,49 @@ import re
import datetime import datetime
from logging_config import Logger 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): def send_player_feedback(config, message, status="active", playlist_version=None, error_details=None):
""" """
Send feedback to the server about player status. 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: if response.status_code == 200:
Logger.info(f"Feedback sent successfully: {message}") Logger.info(f"Feedback sent successfully: {message}")
# Mark server as online on successful feedback
set_server_online()
return True return True
else: else:
Logger.warning(f"Feedback failed with status {response.status_code}: {response.text}") 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 return False
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
Logger.error(f"Failed to send feedback: {e}") Logger.error(f"Failed to send feedback: {e}")
set_server_offline(f"Network error during feedback: {e}")
return False return False
except Exception as e: except Exception as e:
Logger.error(f"Unexpected error sending feedback: {e}") Logger.error(f"Unexpected error sending feedback: {e}")
set_server_offline(f"Unexpected error during feedback: {e}")
return False return False
def send_playlist_check_feedback(config, playlist_version=None): def send_playlist_check_feedback(config, playlist_version=None):
@@ -187,25 +235,44 @@ def fetch_server_playlist(config):
'quickconnect_code': quick 'quickconnect_code': quick
} }
Logger.info(f"Fetching playlist from URL: {server_url} with params: {params}") 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: if response.status_code == 200:
response_data = response.json() response_data = response.json()
Logger.info(f"Server response: {response_data}") Logger.info(f"Server response: {response_data}")
playlist = response_data.get('playlist', []) playlist = response_data.get('playlist', [])
version = response_data.get('playlist_version', None) version = response_data.get('playlist_version', None)
hashed_quickconnect = response_data.get('hashed_quickconnect', None) hashed_quickconnect = response_data.get('hashed_quickconnect', None)
if version is not None and hashed_quickconnect is not None: if version is not None and hashed_quickconnect is not None:
if bcrypt.checkpw(quick.encode('utf-8'), hashed_quickconnect.encode('utf-8')): if bcrypt.checkpw(quick.encode('utf-8'), hashed_quickconnect.encode('utf-8')):
Logger.info("Fetched updated playlist from server.") Logger.info("Fetched updated playlist from server.")
# Mark server as online on successful connection
set_server_online()
return {'playlist': playlist, 'version': version} return {'playlist': playlist, 'version': version}
else: else:
Logger.error("Quickconnect code validation failed.") Logger.error("Quickconnect code validation failed.")
set_server_offline("Authentication failed - invalid quickconnect code")
else: else:
Logger.error("Failed to retrieve playlist or hashed quickconnect from the response.") Logger.error("Failed to retrieve playlist or hashed quickconnect from the response.")
set_server_offline("Invalid server response - missing playlist data")
else: else:
Logger.error(f"Failed to fetch playlist. Status Code: {response.status_code}") 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: 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} return {'playlist': [], 'version': 0}
def save_playlist_with_version(playlist_data, playlist_dir): 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. Also sends feedback to server about playlist check.
""" """
import json import json
global SERVER_CONNECTION_STATUS
server_data = fetch_server_playlist(config) server_data = fetch_server_playlist(config)
server_version = server_data.get('version', 0) server_version = server_data.get('version', 0)
if not os.path.exists(local_playlist_path): 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}") Logger.info(f"Local playlist version: {local_version}, Server playlist version: {server_version}")
# Send feedback about server interrogation (checking for updates) # Only send feedback if server is online
send_playlist_check_feedback(config, server_version if server_version > 0 else local_version) 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'): if server_data and server_data.get('playlist'):
updated_playlist = download_media_files(server_data['playlist'], media_dir) updated_playlist = download_media_files(server_data['playlist'], media_dir)
server_data['playlist'] = updated_playlist 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 unreferenced media
delete_old_playlists_and_media(server_version, playlist_dir, media_dir) 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 return True
else: else:
Logger.warning("No playlist data fetched from server or playlist is empty.") 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 return False
else: 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 return False

View File

@@ -2,7 +2,7 @@
"screen_orientation": "Landscape", "screen_orientation": "Landscape",
"screen_name": "tv-terasa", "screen_name": "tv-terasa",
"quickconnect_key": "8887779", "quickconnect_key": "8887779",
"server_ip": "192.168.1.22", "server_ip": "10.35.33.231",
"port": "80", "port": "80",
"screen_w": "1920", "screen_w": "1920",
"screen_h": "1080", "screen_h": "1080",

View File

@@ -12759,3 +12759,92 @@
[INFO] [SignageApp] Feedback sent successfully: player tv-terasa, playlist working in loop, cycle completed : playlist v8 [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] 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 [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('<urllib3.connection.HTTPConnection object at 0x7f7feccd90>: 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

View File

@@ -4,7 +4,7 @@ import tkinter as tk
import vlc import vlc
import subprocess import subprocess
import sys 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') 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') PLAYLIST_DIR = os.path.join(os.path.dirname(__file__), 'static_data', 'playlist')
@@ -24,6 +24,10 @@ class SimpleTkPlayer:
self.config = self.load_config() self.config = self.load_config()
self.playlist_version = self.get_current_playlist_version() 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 # Initialize all timer variables to None
self.hide_controls_timer = None self.hide_controls_timer = None
self.video_watchdog = None self.video_watchdog = None
@@ -104,6 +108,70 @@ class SimpleTkPlayer:
except Exception as e: except Exception as e:
print(f"[FEEDBACK] Error sending server check feedback: {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): def ensure_fullscreen(self):
self.root.attributes('-fullscreen', True) self.root.attributes('-fullscreen', True)
self.root.update_idletasks() self.root.update_idletasks()
@@ -218,11 +286,49 @@ class SimpleTkPlayer:
self.show_current_media() self.show_current_media()
def update_playlist_from_server(self): def update_playlist_from_server(self):
# Dummy implementation: replace with your actual update logic """Update playlist from server and reload if needed"""
# For example, call a function to fetch and reload the playlist try:
print("[INFO] Updating playlist from server...") from get_playlists import update_playlist_if_needed
# You can import and call your real update function here import json
# Example: self.playlist = get_latest_playlist()
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): def toggle_pause(self):
if not self.paused: if not self.paused:
@@ -321,6 +427,9 @@ class SimpleTkPlayer:
def show_current_media(self): def show_current_media(self):
try: try:
# Check server status and update offline notification
self.check_server_status()
self.root.attributes('-fullscreen', True) self.root.attributes('-fullscreen', True)
self.root.update_idletasks() self.root.update_idletasks()
if not self.playlist: if not self.playlist:
@@ -859,6 +968,9 @@ class SimpleTkPlayer:
try: try:
print("[EXIT] Destroying controls...") print("[EXIT] Destroying controls...")
# Hide offline notification if showing
self.hide_offline_notification()
# First, try to hide and destroy the main controls window # First, try to hide and destroy the main controls window
if hasattr(self, 'controls_win') and self.controls_win: if hasattr(self, 'controls_win') and self.controls_win:
try: try:

View File

@@ -9,6 +9,11 @@
"file_name": "call-of-duty-black-3840x2160-23674.jpg", "file_name": "call-of-duty-black-3840x2160-23674.jpg",
"url": "media/call-of-duty-black-3840x2160-23674.jpg", "url": "media/call-of-duty-black-3840x2160-23674.jpg",
"duration": 30 "duration": 30
},
{
"file_name": "big-buck-bunny-1080p-60fps-30sec.mp4",
"url": "media/big-buck-bunny-1080p-60fps-30sec.mp4",
"duration": 30
} }
], ],
"version": 8 "version": 8

43
test_complete_offline.py Normal file
View File

@@ -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()

30
test_offline.py Executable file
View File

@@ -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()

88
test_ui_notification.py Normal file
View File

@@ -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()