channels
This commit is contained in:
159
video_player.py
159
video_player.py
@@ -14,6 +14,7 @@ import queue
|
||||
import subprocess
|
||||
import argparse
|
||||
import random
|
||||
import socket
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
import vlc
|
||||
@@ -60,6 +61,11 @@ class VideoPlayer:
|
||||
# Channel refresh tracking
|
||||
self.last_channel_refresh = time.time()
|
||||
|
||||
# Control socket for external commands
|
||||
self.control_socket_path = "/tmp/video_player_control.sock"
|
||||
self.control_socket = None
|
||||
self.control_thread = None
|
||||
|
||||
self.logger.info("Video Player initialized")
|
||||
|
||||
def load_config(self) -> Dict:
|
||||
@@ -143,6 +149,10 @@ class VideoPlayer:
|
||||
self.vlc_instance = vlc.Instance(all_vlc_options)
|
||||
self.vlc_player = self.vlc_instance.media_player_new()
|
||||
|
||||
# Set up event manager for video end detection
|
||||
self.vlc_event_manager = self.vlc_player.event_manager()
|
||||
self.vlc_event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, self.on_video_end)
|
||||
|
||||
# Set fullscreen and always on top
|
||||
if '--fullscreen' in vlc_options:
|
||||
self.vlc_player.set_fullscreen(True)
|
||||
@@ -472,6 +482,116 @@ class VideoPlayer:
|
||||
self.logger.info("Power toggle - shutting down")
|
||||
self.running = False
|
||||
|
||||
def setup_control_socket(self):
|
||||
"""Setup Unix socket for external control commands"""
|
||||
try:
|
||||
# Remove existing socket file if it exists
|
||||
if os.path.exists(self.control_socket_path):
|
||||
os.unlink(self.control_socket_path)
|
||||
|
||||
# Create Unix socket
|
||||
self.control_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.control_socket.bind(self.control_socket_path)
|
||||
self.control_socket.listen(1)
|
||||
|
||||
# Start control thread
|
||||
self.control_thread = threading.Thread(target=self.handle_control_commands, daemon=True)
|
||||
self.control_thread.start()
|
||||
|
||||
self.logger.info(f"Control socket setup at {self.control_socket_path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to setup control socket: {e}")
|
||||
return False
|
||||
|
||||
def handle_control_commands(self):
|
||||
"""Handle control commands from external clients"""
|
||||
while self.running:
|
||||
try:
|
||||
# Accept connection
|
||||
client_socket, _ = self.control_socket.accept()
|
||||
|
||||
# Receive command
|
||||
data = client_socket.recv(1024).decode('utf-8')
|
||||
command = json.loads(data)
|
||||
|
||||
# Process command
|
||||
response = self.process_control_command(command)
|
||||
|
||||
# Send response
|
||||
response_data = json.dumps(response).encode('utf-8')
|
||||
client_socket.send(response_data)
|
||||
|
||||
client_socket.close()
|
||||
|
||||
except Exception as e:
|
||||
if self.running: # Only log if we're still supposed to be running
|
||||
self.logger.error(f"Error handling control command: {e}")
|
||||
time.sleep(0.1)
|
||||
|
||||
def process_control_command(self, command):
|
||||
"""Process a control command and return response"""
|
||||
action = command.get("action")
|
||||
|
||||
try:
|
||||
if action == "change_channel":
|
||||
channel = command.get("channel")
|
||||
if channel and channel in self.channels:
|
||||
success = self.play_channel(channel)
|
||||
if success:
|
||||
return {
|
||||
"success": True,
|
||||
"channel": channel,
|
||||
"channel_name": self.channels[channel]["name"]
|
||||
}
|
||||
else:
|
||||
return {"success": False, "error": "Failed to play channel"}
|
||||
else:
|
||||
return {"success": False, "error": f"Invalid channel: {channel}"}
|
||||
|
||||
elif action == "random_channel":
|
||||
success = self.play_random_video()
|
||||
if success:
|
||||
return {
|
||||
"success": True,
|
||||
"channel": self.current_channel,
|
||||
"channel_name": self.channels[self.current_channel]["name"] if self.current_channel else "Unknown"
|
||||
}
|
||||
else:
|
||||
return {"success": False, "error": "Failed to play random channel"}
|
||||
|
||||
elif action == "list_channels":
|
||||
return {
|
||||
"success": True,
|
||||
"channels": self.channels
|
||||
}
|
||||
|
||||
elif action == "get_current_channel":
|
||||
if self.current_channel and self.current_channel in self.channels:
|
||||
return {
|
||||
"success": True,
|
||||
"channel": self.current_channel,
|
||||
"channel_name": self.channels[self.current_channel]["name"]
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": True,
|
||||
"channel": None,
|
||||
"channel_name": None
|
||||
}
|
||||
|
||||
elif action == "stop":
|
||||
self.logger.info("Stop command received via control socket")
|
||||
self.running = False
|
||||
return {"success": True}
|
||||
|
||||
else:
|
||||
return {"success": False, "error": f"Unknown action: {action}"}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error processing control command: {e}")
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
def start(self, startup_mode: str = "default", channel_number: int = None, video_index: int = None):
|
||||
"""Start the video player with specified mode
|
||||
|
||||
@@ -509,6 +629,10 @@ class VideoPlayer:
|
||||
else:
|
||||
self.logger.info("IR remote control disabled, skipping IR processing thread")
|
||||
|
||||
# Setup control socket for external commands
|
||||
if not self.setup_control_socket():
|
||||
self.logger.warning("Failed to setup control socket, external commands will not work")
|
||||
|
||||
# Play based on startup mode
|
||||
success = False
|
||||
if startup_mode == "random":
|
||||
@@ -566,17 +690,21 @@ class VideoPlayer:
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
||||
def on_video_end(self, event):
|
||||
"""Callback for when a video ends - start a random channel"""
|
||||
self.logger.info("Video ended, starting random channel")
|
||||
if self.channels:
|
||||
self.play_random_video()
|
||||
else:
|
||||
self.logger.error("No channels available to play after video end")
|
||||
|
||||
def ensure_video_playing(self):
|
||||
"""Ensure a video is always playing"""
|
||||
if not self.vlc_player or not self.vlc_player.is_playing():
|
||||
if self.current_channel and self.current_channel in self.channels:
|
||||
self.logger.info(f"Restarting current channel {self.current_channel}")
|
||||
self.play_channel(self.current_channel)
|
||||
elif self.channels:
|
||||
# Play the first available channel
|
||||
first_channel = min(self.channels.keys())
|
||||
self.logger.info(f"No current channel, playing first available channel {first_channel}")
|
||||
self.play_channel(first_channel)
|
||||
if self.channels:
|
||||
# Play a random channel instead of restarting current or first channel
|
||||
self.logger.info("No video playing, starting random channel")
|
||||
self.play_random_video()
|
||||
else:
|
||||
self.logger.error("No channels available to play")
|
||||
|
||||
@@ -600,6 +728,21 @@ class VideoPlayer:
|
||||
|
||||
if self.enable_ir:
|
||||
GPIO.cleanup()
|
||||
|
||||
# Cleanup control socket
|
||||
if self.control_socket:
|
||||
try:
|
||||
self.control_socket.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Remove socket file
|
||||
if os.path.exists(self.control_socket_path):
|
||||
try:
|
||||
os.unlink(self.control_socket_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.logger.info("Cleanup complete")
|
||||
|
||||
def parse_arguments():
|
||||
|
||||
Reference in New Issue
Block a user