Compare commits
2 Commits
8293111e09
...
7e69b12f71
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e69b12f71 | |||
| 1197077954 |
111
src/README.md
Normal file
111
src/README.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Signage Player - Complete Offline Installation Package
|
||||
|
||||
This directory contains everything needed to install the Signage Player application completely offline on a Raspberry Pi or similar Debian-based system.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── offline_packages/ # Pre-downloaded Python packages (.whl files)
|
||||
│ ├── requests-2.32.4-py3-none-any.whl
|
||||
│ ├── pillow-11.1.0-cp311-cp311-linux_armv7l.whl
|
||||
│ ├── pygame-2.6.1-cp311-cp311-linux_armv7l.whl
|
||||
│ └── ... (dependencies)
|
||||
├── shared_modules/ # Shared Python modules
|
||||
│ ├── logging_config.py
|
||||
│ └── python_functions.py
|
||||
├── system_packages/ # System dependency information
|
||||
│ └── apt_packages.txt # List of required APT packages
|
||||
└── scripts/ # Installation and utility scripts
|
||||
├── install_offline.sh # Main offline installation script
|
||||
└── check_dependencies.sh # Dependency verification script
|
||||
```
|
||||
|
||||
## Quick Installation
|
||||
|
||||
1. **Run the offline installer:**
|
||||
```bash
|
||||
cd /path/to/signage-player
|
||||
chmod +x src/scripts/install_offline.sh
|
||||
./src/scripts/install_offline.sh
|
||||
```
|
||||
|
||||
2. **Verify installation:**
|
||||
```bash
|
||||
chmod +x src/scripts/check_dependencies.sh
|
||||
./src/scripts/check_dependencies.sh
|
||||
```
|
||||
|
||||
3. **Run the application:**
|
||||
```bash
|
||||
./run_tkinter_debug.sh
|
||||
```
|
||||
|
||||
## What Gets Installed
|
||||
|
||||
### System Packages (via APT)
|
||||
- Python 3 development tools
|
||||
- OpenCV libraries and Python bindings
|
||||
- SDL2 libraries for pygame
|
||||
- Image processing libraries (JPEG, PNG, TIFF, WebP)
|
||||
- Audio libraries
|
||||
- Build tools
|
||||
|
||||
### Python Packages (from offline wheels)
|
||||
- **requests** - HTTP library for server communication
|
||||
- **pillow** - Image processing library
|
||||
- **pygame** - Audio and input handling
|
||||
- **certifi, charset_normalizer, idna, urllib3** - Dependencies
|
||||
|
||||
### Application Components
|
||||
- Shared logging and playlist management modules
|
||||
- Modern tkinter-based media player
|
||||
- Configuration management
|
||||
- Resource directories
|
||||
|
||||
## Manual Installation Steps
|
||||
|
||||
If you prefer to install manually:
|
||||
|
||||
1. **Install system packages:**
|
||||
```bash
|
||||
sudo apt update
|
||||
cat src/system_packages/apt_packages.txt | grep -v '^#' | xargs sudo apt install -y
|
||||
```
|
||||
|
||||
2. **Create virtual environment:**
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
3. **Install Python packages:**
|
||||
```bash
|
||||
pip install --no-index --find-links src/offline_packages requests pillow pygame
|
||||
```
|
||||
|
||||
4. **Copy shared modules:**
|
||||
```bash
|
||||
cp src/shared_modules/*.py tkinter_app/src/
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Permission errors:** Make sure scripts are executable with `chmod +x`
|
||||
- **Missing packages:** Run `src/scripts/check_dependencies.sh` to verify installation
|
||||
- **Virtual environment issues:** Delete `venv` folder and re-run installer
|
||||
- **OpenCV errors:** Ensure `python3-opencv` system package is installed
|
||||
|
||||
## Requirements
|
||||
|
||||
- Debian/Ubuntu-based system (Raspberry Pi OS recommended)
|
||||
- Internet connection for system package installation (APT only)
|
||||
- Sudo privileges for system package installation
|
||||
- At least 200MB free space
|
||||
|
||||
## Notes
|
||||
|
||||
- This package includes all Python dependencies as pre-compiled wheels
|
||||
- No internet connection needed for Python packages during installation
|
||||
- Compatible with ARM-based systems (Raspberry Pi)
|
||||
- Includes fallback mechanisms for offline operation
|
||||
BIN
src/offline_packages/certifi-2025.8.3-py3-none-any.whl
Normal file
BIN
src/offline_packages/certifi-2025.8.3-py3-none-any.whl
Normal file
Binary file not shown.
BIN
src/offline_packages/charset_normalizer-3.4.2-py3-none-any.whl
Normal file
BIN
src/offline_packages/charset_normalizer-3.4.2-py3-none-any.whl
Normal file
Binary file not shown.
BIN
src/offline_packages/idna-3.10-py3-none-any.whl
Normal file
BIN
src/offline_packages/idna-3.10-py3-none-any.whl
Normal file
Binary file not shown.
BIN
src/offline_packages/pillow-11.1.0-cp311-cp311-linux_armv7l.whl
Normal file
BIN
src/offline_packages/pillow-11.1.0-cp311-cp311-linux_armv7l.whl
Normal file
Binary file not shown.
BIN
src/offline_packages/pygame-2.6.1-cp311-cp311-linux_armv7l.whl
Normal file
BIN
src/offline_packages/pygame-2.6.1-cp311-cp311-linux_armv7l.whl
Normal file
Binary file not shown.
BIN
src/offline_packages/requests-2.32.4-py3-none-any.whl
Normal file
BIN
src/offline_packages/requests-2.32.4-py3-none-any.whl
Normal file
Binary file not shown.
BIN
src/offline_packages/urllib3-2.5.0-py3-none-any.whl
Normal file
BIN
src/offline_packages/urllib3-2.5.0-py3-none-any.whl
Normal file
Binary file not shown.
77
src/scripts/check_dependencies.sh
Executable file
77
src/scripts/check_dependencies.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
# Dependency Verification Script
|
||||
# Checks if all required dependencies are properly installed
|
||||
|
||||
echo "=== Signage Player Dependency Check ==="
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
ERRORS=0
|
||||
|
||||
# Function to check system package
|
||||
check_system_package() {
|
||||
if dpkg -l | grep -q "^ii.*$1"; then
|
||||
echo -e "${GREEN}✓${NC} $1 is installed"
|
||||
else
|
||||
echo -e "${RED}✗${NC} $1 is NOT installed"
|
||||
((ERRORS++))
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check Python package
|
||||
check_python_package() {
|
||||
if python3 -c "import $1" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓${NC} Python package '$1' is available"
|
||||
else
|
||||
echo -e "${RED}✗${NC} Python package '$1' is NOT available"
|
||||
((ERRORS++))
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Checking system packages..."
|
||||
check_system_package "python3-dev"
|
||||
check_system_package "python3-opencv"
|
||||
check_system_package "libsdl2-dev"
|
||||
check_system_package "libjpeg-dev"
|
||||
|
||||
echo ""
|
||||
echo "Checking Python packages..."
|
||||
check_python_package "cv2"
|
||||
check_python_package "pygame"
|
||||
check_python_package "PIL"
|
||||
check_python_package "requests"
|
||||
|
||||
echo ""
|
||||
echo "Checking application files..."
|
||||
if [ -f "tkinter_app/src/main.py" ]; then
|
||||
echo -e "${GREEN}✓${NC} Main application file exists"
|
||||
else
|
||||
echo -e "${RED}✗${NC} Main application file missing"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
if [ -f "tkinter_app/src/tkinter_simple_player.py" ]; then
|
||||
echo -e "${GREEN}✓${NC} Player module exists"
|
||||
else
|
||||
echo -e "${RED}✗${NC} Player module missing"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
if [ -d "venv" ]; then
|
||||
echo -e "${GREEN}✓${NC} Virtual environment exists"
|
||||
else
|
||||
echo -e "${YELLOW}⚠${NC} Virtual environment not found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ $ERRORS -eq 0 ]; then
|
||||
echo -e "${GREEN}=== All dependencies are properly installed! ===${NC}"
|
||||
echo "You can run the application with: ./run_tkinter_debug.sh"
|
||||
else
|
||||
echo -e "${RED}=== Found $ERRORS issues ===${NC}"
|
||||
echo "Run the installation script: src/scripts/install_offline.sh"
|
||||
fi
|
||||
103
src/scripts/install_offline.sh
Executable file
103
src/scripts/install_offline.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
# Offline Installation Script for Signage Player
|
||||
# This script installs all dependencies and sets up the application completely offline
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
echo "=== Signage Player Offline Installation ==="
|
||||
echo "Project root: $PROJECT_ROOT"
|
||||
|
||||
# Check if running as root for system packages
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
echo "ERROR: Please run this script as a regular user, not as root."
|
||||
echo "The script will prompt for sudo when needed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Install system packages
|
||||
echo "Step 1: Installing system packages..."
|
||||
if command_exists apt; then
|
||||
echo "Installing APT packages..."
|
||||
sudo apt update
|
||||
|
||||
# Read and install packages from the list
|
||||
while IFS= read -r package; do
|
||||
# Skip comments and empty lines
|
||||
if [[ ! "$package" =~ ^[[:space:]]*# ]] && [[ -n "${package// }" ]]; then
|
||||
echo "Installing: $package"
|
||||
sudo apt install -y "$package" || echo "Warning: Could not install $package"
|
||||
fi
|
||||
done < "$SCRIPT_DIR/../system_packages/apt_packages.txt"
|
||||
else
|
||||
echo "ERROR: apt package manager not found. This script is designed for Debian/Ubuntu systems."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create virtual environment
|
||||
echo "Step 2: Creating virtual environment..."
|
||||
cd "$PROJECT_ROOT"
|
||||
if [ ! -d "venv" ]; then
|
||||
python3 -m venv venv
|
||||
echo "Virtual environment created."
|
||||
else
|
||||
echo "Virtual environment already exists."
|
||||
fi
|
||||
|
||||
# Activate virtual environment
|
||||
echo "Step 3: Activating virtual environment..."
|
||||
source venv/bin/activate
|
||||
|
||||
# Install Python packages from offline wheels
|
||||
echo "Step 4: Installing Python packages from offline wheels..."
|
||||
if [ -d "src/offline_packages" ]; then
|
||||
pip install --upgrade pip
|
||||
pip install --no-index --find-links "src/offline_packages" \
|
||||
requests pillow pygame certifi charset_normalizer idna urllib3
|
||||
echo "Python packages installed successfully."
|
||||
else
|
||||
echo "ERROR: Offline packages directory not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Copy shared modules to tkinter app
|
||||
echo "Step 5: Setting up shared modules..."
|
||||
if [ -d "src/shared_modules" ]; then
|
||||
cp src/shared_modules/*.py tkinter_app/src/ 2>/dev/null || echo "Shared modules already in place."
|
||||
echo "Shared modules configured."
|
||||
else
|
||||
echo "Warning: Shared modules directory not found."
|
||||
fi
|
||||
|
||||
# Create necessary directories
|
||||
echo "Step 6: Creating application directories..."
|
||||
mkdir -p tkinter_app/resources/static/resurse
|
||||
mkdir -p tkinter_app/src/static/resurse
|
||||
|
||||
# Set permissions
|
||||
echo "Step 7: Setting permissions..."
|
||||
chmod +x run_tkinter_debug.sh
|
||||
chmod +x install_tkinter.sh
|
||||
chmod +x src/scripts/*.sh 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "=== Installation Complete! ==="
|
||||
echo ""
|
||||
echo "To run the signage player:"
|
||||
echo " ./run_tkinter_debug.sh"
|
||||
echo ""
|
||||
echo "To configure settings, run the app and click the Settings button."
|
||||
echo ""
|
||||
echo "The application has been set up with:"
|
||||
echo " - All system dependencies"
|
||||
echo " - Python virtual environment with required packages"
|
||||
echo " - Shared modules properly configured"
|
||||
echo " - Necessary directories created"
|
||||
echo ""
|
||||
27
src/shared_modules/logging_config.py
Normal file
27
src/shared_modules/logging_config.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
# Path to the log file
|
||||
# Update the path to point to the new resources directory
|
||||
LOG_FILE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'log.txt')
|
||||
|
||||
# Create a logger instance
|
||||
Logger = logging.getLogger('SignageApp')
|
||||
Logger.setLevel(logging.INFO) # Set the logging level to INFO
|
||||
|
||||
# Create a file handler to write logs to the log.txt file
|
||||
file_handler = logging.FileHandler(LOG_FILE_PATH, mode='a') # Append logs to the file
|
||||
file_handler.setLevel(logging.INFO)
|
||||
|
||||
# Create a formatter for the log messages
|
||||
formatter = logging.Formatter('[%(levelname)s] [%(name)s] %(message)s')
|
||||
file_handler.setFormatter(formatter)
|
||||
|
||||
# Add the file handler to the logger
|
||||
Logger.addHandler(file_handler)
|
||||
|
||||
# Optionally, add a stream handler to log messages to the console
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.setLevel(logging.INFO)
|
||||
stream_handler.setFormatter(formatter)
|
||||
Logger.addHandler(stream_handler)
|
||||
196
src/shared_modules/python_functions.py
Normal file
196
src/shared_modules/python_functions.py
Normal file
@@ -0,0 +1,196 @@
|
||||
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}")
|
||||
43
src/system_packages/apt_packages.txt
Normal file
43
src/system_packages/apt_packages.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# System Package Dependencies for Signage Player
|
||||
# These packages need to be installed via apt before installing Python packages
|
||||
|
||||
# Core system packages
|
||||
python3-dev
|
||||
python3-pip
|
||||
python3-venv
|
||||
python3-setuptools
|
||||
python3-wheel
|
||||
|
||||
# OpenCV system dependencies
|
||||
libopencv-dev
|
||||
python3-opencv
|
||||
libopencv-core-dev
|
||||
libopencv-imgproc-dev
|
||||
libopencv-imgcodecs-dev
|
||||
libopencv-videoio-dev
|
||||
|
||||
# Audio/Video libraries
|
||||
libasound2-dev
|
||||
libsdl2-dev
|
||||
libsdl2-image-dev
|
||||
libsdl2-mixer-dev
|
||||
libsdl2-ttf-dev
|
||||
libfreetype6-dev
|
||||
libportmidi-dev
|
||||
|
||||
# Image processing libraries
|
||||
libjpeg-dev
|
||||
libpng-dev
|
||||
libtiff-dev
|
||||
libwebp-dev
|
||||
libopenjp2-7-dev
|
||||
|
||||
# Build tools (may be needed for some packages)
|
||||
build-essential
|
||||
cmake
|
||||
pkg-config
|
||||
|
||||
# Networking
|
||||
curl
|
||||
wget
|
||||
@@ -831,3 +831,31 @@
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Application exit requested
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] python_functions: Configuration loaded: server=192.168.1.245, host=tv-holba1, quick=8887779, port=5000
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Initializing with settings: server=192.168.1.245, host=tv-holba1, port=5000
|
||||
[INFO] [SignageApp] Attempting to connect to server...
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.245:5000/api/playlists with params: {'hostname': 'tv-holba1', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='192.168.1.245', port=5000): Max retries exceeded with url: /api/playlists?hostname=tv-holba1&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5623410>: Failed to establish a new connection: [Errno 111] Connection refused'))
|
||||
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-05 17:00:43 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||
[INFO] [SignageApp] Loading configuration in settings window
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-holba1', 'quickconnect_key': '8887779', 'server_ip': '192.168.1.245', 'port': '5000', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||
[INFO] [SignageApp] Configuration values loaded successfully in settings
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Application exit requested
|
||||
|
||||
Reference in New Issue
Block a user