import os import json import requests from logging_config import Logger # Import the shared logger import bcrypt import time # Update paths to use the new directory structure CONFIG_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'app_config.txt') LOCAL_PLAYLIST_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'local_playlist.json') def load_config(): """Load configuration from app_config.txt.""" Logger.info("python_functions: Starting load_config function.") if os.path.exists(CONFIG_FILE): try: with open(CONFIG_FILE, 'r') as file: Logger.info("python_functions: Configuration file loaded successfully.") return json.load(file) except json.JSONDecodeError as e: Logger.error(f"python_functions: Failed to parse configuration file. Error: {e}") return {} else: Logger.error(f"python_functions: Configuration file {CONFIG_FILE} not found.") return {} Logger.info("python_functions: Finished load_config function.") # Load configuration and initialize variables config_data = load_config() server = config_data.get("server_ip", "") host = config_data.get("screen_name", "") quick = config_data.get("quickconnect_key", "") port = config_data.get("port", "") Logger.info(f"python_functions: Configuration loaded: server={server}, host={host}, quick={quick}, port={port}") def load_local_playlist(): """Load the playlist and version from local storage.""" Logger.info("python_functions: Starting load_local_playlist function.") if os.path.exists(LOCAL_PLAYLIST_FILE): try: with open(LOCAL_PLAYLIST_FILE, 'r') as local_file: local_playlist = json.load(local_file) Logger.info(f"python_functions: Local playlist loaded: {local_playlist}") if isinstance(local_playlist, dict) and 'playlist' in local_playlist and 'version' in local_playlist: Logger.info("python_functions: Finished load_local_playlist function successfully.") return local_playlist # Return the full playlist data else: Logger.error("python_functions: Invalid local playlist structure.") return {'playlist': [], 'version': 0} except json.JSONDecodeError as e: Logger.error(f"python_functions: Failed to parse local playlist file. Error: {e}") return {'playlist': [], 'version': 0} else: Logger.warning("python_functions: Local playlist file not found.") return {'playlist': [], 'version': 0} Logger.info("python_functions: Finished load_local_playlist function.") def save_local_playlist(playlist): """Save the updated playlist locally.""" Logger.info("python_functions: Starting save_local_playlist function.") Logger.debug(f"python_functions: Playlist to save: {playlist}") if not playlist or 'playlist' not in playlist: Logger.error("python_functions: Invalid playlist data. Cannot save local playlist.") return try: with open(LOCAL_PLAYLIST_FILE, 'w') as local_file: json.dump(playlist, local_file, indent=4) # Ensure proper formatting Logger.info("python_functions: Updated local playlist with server data.") except IOError as e: Logger.error(f"python_functions: Failed to save local playlist: {e}") Logger.info("python_functions: Finished save_local_playlist function.") def fetch_server_playlist(): """Fetch the updated playlist from the server.""" try: server_ip = f'{server}:{port}' # Construct the server IP with port url = f'http://{server_ip}/api/playlists' params = { 'hostname': host, 'quickconnect_code': quick } Logger.info(f"Fetching playlist from URL: {url} with params: {params}") response = requests.get(url, params=params) 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.") # Update the playlist version in app_config.txt update_config_playlist_version(version) return {'playlist': playlist, 'version': version} else: Logger.error("Quickconnect code validation failed.") else: Logger.error("Failed to retrieve playlist or hashed quickconnect from the response.") else: Logger.error(f"Failed to fetch playlist. Status Code: {response.status_code}") except requests.exceptions.RequestException as e: Logger.error(f"Failed to fetch playlist: {e}") return {'playlist': [], 'version': 0} def download_media_files(playlist, version): """Download media files from the server and update the local playlist.""" Logger.info("python_functions: Starting media file download...") base_dir = os.path.join(os.path.dirname(__file__), 'static', 'resurse') # Path to the local folder if not os.path.exists(base_dir): os.makedirs(base_dir) Logger.info(f"python_functions: Created directory {base_dir} for media files.") updated_playlist = [] # List to store updated media entries for media in playlist: file_name = media.get('file_name', '') file_url = media.get('url', '') duration = media.get('duration', 10) # Default duration if not provided local_path = os.path.join(base_dir, file_name) # Local file path Logger.debug(f"python_functions: Preparing to download {file_name} from {file_url}...") if os.path.exists(local_path): Logger.info(f"python_functions: File {file_name} already exists. Skipping download.") else: try: response = requests.get(file_url, timeout=10) if response.status_code == 200: with open(local_path, 'wb') as file: file.write(response.content) Logger.info(f"python_functions: Successfully downloaded {file_name} to {local_path}") else: Logger.error(f"python_functions: Failed to download {file_name}. Status Code: {response.status_code}") continue except requests.exceptions.RequestException as e: Logger.error(f"python_functions: Error downloading {file_name}: {e}") continue # Update the playlist entry to point to the local file path updated_media = { 'file_name': file_name, 'url': f"static/resurse/{file_name}", # Update URL to local path 'duration': duration } Logger.debug(f"python_functions: Updated media entry: {updated_media}") updated_playlist.append(updated_media) # Save the updated playlist locally save_local_playlist({'playlist': updated_playlist, 'version': version}) Logger.info("python_functions: Finished media file download and updated local playlist.") def clean_unused_files(playlist): """Remove unused media files from the resource folder.""" Logger.info("python_functions: Cleaning unused media files...") base_dir = os.path.join(os.path.dirname(__file__), 'static', 'resurse') if not os.path.exists(base_dir): Logger.debug(f"python_functions: Directory {base_dir} does not exist. No files to clean.") return playlist_files = {media.get('file_name', '') for media in playlist} all_files = set(os.listdir(base_dir)) unused_files = all_files - playlist_files for file_name in unused_files: file_path = os.path.join(base_dir, file_name) try: os.remove(file_path) Logger.info(f"python_functions: Deleted unused file: {file_path}") except OSError as e: Logger.error(f"python_functions: Failed to delete {file_path}: {e}") def update_config_playlist_version(version): """Update the playlist version in app_config.txt.""" if not os.path.exists(CONFIG_FILE): Logger.error(f"python_functions: Configuration file {CONFIG_FILE} not found.") return try: with open(CONFIG_FILE, 'r') as file: config_data = json.load(file) config_data['playlist_version'] = version # Add or update the playlist version with open(CONFIG_FILE, 'w') as file: json.dump(config_data, file, indent=4) Logger.info(f"python_functions: Updated playlist version in app_config.txt to {version}.") except (IOError, json.JSONDecodeError) as e: Logger.error(f"python_functions: Failed to update playlist version in app_config.txt. Error: {e}")