updated player with playlist

This commit is contained in:
2025-11-22 10:04:30 +02:00
parent 3f9674517d
commit 68ed5b8534
2 changed files with 165 additions and 4 deletions

View File

@@ -149,6 +149,88 @@ class SettingsPopup(Popup):
# Restart the control hide timer
self.player.schedule_hide_controls()
def test_connection(self):
"""Test connection to server with current credentials"""
# Update status label to show testing
self.ids.connection_status.text = 'Testing connection...'
self.ids.connection_status.color = (1, 0.7, 0, 1) # Orange
# Run test in background thread to avoid blocking UI
def run_test():
try:
from player_auth import PlayerAuth
import re
# Get current values from inputs
server_ip = self.ids.server_input.text.strip()
screen_name = self.ids.screen_input.text.strip()
quickconnect = self.ids.quickconnect_input.text.strip()
port = self.player.config.get('port', '443')
if not all([server_ip, screen_name, quickconnect]):
Clock.schedule_once(lambda dt: self.update_connection_status(
'Error: Fill all fields', False
))
return
# Build server URL
if server_ip.startswith('http://') or server_ip.startswith('https://'):
server_url = server_ip
if not ':' in server_ip.replace('https://', '').replace('http://', ''):
if port and port != '443' and port != '80':
server_url = f"{server_ip}:{port}"
else:
protocol = "https" if port == "443" else "http"
server_url = f"{protocol}://{server_ip}:{port}"
Logger.info(f"SettingsPopup: Testing connection to {server_url}")
# Create temporary auth instance (don't save)
auth = PlayerAuth('/tmp/temp_auth_test.json')
# Try to authenticate
success, error = auth.authenticate(
server_url=server_url,
hostname=screen_name,
quickconnect_code=quickconnect
)
# Clean up temp file
try:
import os
if os.path.exists('/tmp/temp_auth_test.json'):
os.remove('/tmp/temp_auth_test.json')
except:
pass
# Update UI on main thread
if success:
player_name = auth.get_player_name()
Clock.schedule_once(lambda dt: self.update_connection_status(
f'✓ Connected: {player_name}', True
))
else:
Clock.schedule_once(lambda dt: self.update_connection_status(
f'✗ Failed: {error}', False
))
except Exception as e:
Logger.error(f"SettingsPopup: Connection test error: {e}")
Clock.schedule_once(lambda dt: self.update_connection_status(
f'✗ Error: {str(e)}', False
))
# Run in thread
threading.Thread(target=run_test, daemon=True).start()
def update_connection_status(self, message, success):
"""Update connection status label"""
self.ids.connection_status.text = message
if success:
self.ids.connection_status.color = (0, 1, 0, 1) # Green
else:
self.ids.connection_status.color = (1, 0, 0, 1) # Red
def save_and_close(self):
"""Save configuration and close popup"""
# Update config
@@ -195,6 +277,7 @@ class SignagePlayer(Widget):
self.playlist_version = None
self.consecutive_errors = 0 # Track consecutive playback errors
self.max_consecutive_errors = 10 # Maximum errors before stopping
self.intro_played = False # Track if intro has been played
# Paths
self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.config_dir = os.path.join(self.base_dir, 'config')
@@ -229,15 +312,15 @@ class SignagePlayer(Widget):
# Load configuration
self.load_config()
# Play intro video first
self.play_intro_video()
# Start async server tasks (non-blocking)
asyncio.ensure_future(self.async_playlist_update_loop())
Logger.info("SignagePlayer: Async server tasks started")
# Start media playback
Clock.schedule_interval(self.check_playlist_and_play, 30) # Check every 30 seconds
# Initial playlist check
self.check_playlist_and_play(None)
def load_config(self):
"""Load configuration from file"""
@@ -364,8 +447,63 @@ class SignagePlayer(Widget):
Logger.error(f"SignagePlayer: Error loading playlist: {e}")
self.show_error(f"Failed to load playlist: {e}")
def play_intro_video(self):
"""Play intro video on startup"""
intro_path = os.path.join(self.resources_path, 'intro1.mp4')
if not os.path.exists(intro_path):
Logger.warning(f"SignagePlayer: Intro video not found at {intro_path}")
# Skip intro and load playlist
self.intro_played = True
self.check_playlist_and_play(None)
return
try:
Logger.info("SignagePlayer: Playing intro video...")
self.ids.status_label.opacity = 0 # Hide status label
# Create video widget for intro
intro_video = Video(
source=intro_path,
state='play',
options={'eos': 'stop'},
allow_stretch=True,
keep_ratio=True,
size=self.size,
pos=(0, 0)
)
# Bind to video end event
def on_intro_end(instance, value):
if value == 'stop':
Logger.info("SignagePlayer: Intro video finished")
# Remove intro video
if intro_video in self.ids.content_area.children:
self.ids.content_area.remove_widget(intro_video)
# Mark intro as played
self.intro_played = True
# Start normal playlist
self.check_playlist_and_play(None)
intro_video.bind(state=on_intro_end)
# Add intro video to content area
self.ids.content_area.add_widget(intro_video)
except Exception as e:
Logger.error(f"SignagePlayer: Error playing intro video: {e}")
# Skip intro and load playlist
self.intro_played = True
self.check_playlist_and_play(None)
def check_playlist_and_play(self, dt):
"""Check for playlist updates and ensure playback is running"""
# Don't start playlist until intro is done
if not self.intro_played:
return
if not self.playlist:
self.load_playlist()

View File

@@ -283,7 +283,30 @@
hint_text: '1920x1080 or auto'
Widget:
size_hint_y: 0.1
size_hint_y: 0.05
# Test Connection Button
Button:
id: test_connection_btn
text: 'Test Server Connection'
size_hint_y: None
height: dp(50)
background_color: 0.2, 0.4, 0.8, 1
on_press: root.test_connection()
# Connection Status Label
Label:
id: connection_status
text: 'Click button to test connection'
size_hint_y: None
height: dp(40)
text_size: self.size
halign: 'center'
valign: 'middle'
color: 0.7, 0.7, 0.7, 1
Widget:
size_hint_y: 0.05
# Status information
Label: