updated player with playlist
This commit is contained in:
144
src/main.py
144
src/main.py
@@ -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()
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user