Add web-enabled MPV main entry point
This commit is contained in:
341
web_mpv_main.py
Normal file
341
web_mpv_main.py
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
# web_mpv_main.py
|
||||||
|
"""
|
||||||
|
MPV Video Player with Web Interface Integration
|
||||||
|
Combines the enhanced debug console with web interface capabilities
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def check_web_requirements():
|
||||||
|
"""Check if web interface requirements are available"""
|
||||||
|
print("Checking Web Interface Requirements...")
|
||||||
|
print("=" * 40)
|
||||||
|
|
||||||
|
# Check Flask and Flask-SocketIO
|
||||||
|
try:
|
||||||
|
import flask
|
||||||
|
print("✓ Flask available")
|
||||||
|
except ImportError:
|
||||||
|
print("✗ Flask not installed")
|
||||||
|
print("Install with: pip install flask")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import flask_socketio
|
||||||
|
print("✓ Flask-SocketIO available")
|
||||||
|
except ImportError:
|
||||||
|
print("✗ Flask-SocketIO not installed")
|
||||||
|
print("Install with: pip install flask-socketio")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check MPV
|
||||||
|
try:
|
||||||
|
import mpv
|
||||||
|
print("✓ python-mpv available")
|
||||||
|
|
||||||
|
# Test MPV functionality
|
||||||
|
try:
|
||||||
|
test_player = mpv.MPV(vo='null', ao='null', video=False, quiet=True)
|
||||||
|
test_player.terminate()
|
||||||
|
print("✓ MPV functionality test passed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ MPV test failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
print("✗ python-mpv not installed")
|
||||||
|
print("Install with: pip install python-mpv")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check other requirements
|
||||||
|
try:
|
||||||
|
from config import Config
|
||||||
|
print("✓ config module available")
|
||||||
|
except ImportError:
|
||||||
|
print("✗ config.py not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from enhanced_debug_console import EnhancedDebugConsoleWithWeb
|
||||||
|
print("✓ enhanced debug console available")
|
||||||
|
except ImportError:
|
||||||
|
print("✗ enhanced_debug_console.py not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from mpv_seamless_player import MPVSeamlessPlayer
|
||||||
|
print("✓ MPV seamless player available")
|
||||||
|
except ImportError:
|
||||||
|
print("✗ mpv_seamless_player.py not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✓ All web interface requirements satisfied")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Import after requirement check
|
||||||
|
from config import Config
|
||||||
|
from enhanced_debug_console import EnhancedDebugConsoleWithWeb
|
||||||
|
from mpv_seamless_player import MPVSeamlessPlayer
|
||||||
|
|
||||||
|
def make_json_safe(data):
|
||||||
|
"""Convert data to be JSON-safe by handling datetime objects"""
|
||||||
|
if isinstance(data, dict):
|
||||||
|
return {key: make_json_safe(value) for key, value in data.items()}
|
||||||
|
elif isinstance(data, list):
|
||||||
|
return [make_json_safe(item) for item in data]
|
||||||
|
elif isinstance(data, datetime):
|
||||||
|
return data.isoformat()
|
||||||
|
elif hasattr(data, 'total_seconds'): # timedelta
|
||||||
|
return str(data)
|
||||||
|
else:
|
||||||
|
return data
|
||||||
|
|
||||||
|
class WebMPVVideoPlayerApp:
|
||||||
|
def __init__(self, web_port=8547):
|
||||||
|
self.config = Config()
|
||||||
|
self.running = True
|
||||||
|
self.debug_console = None
|
||||||
|
self.video_player = None
|
||||||
|
self.video_thread = None
|
||||||
|
self.web_port = web_port
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def initialize_components(self):
|
||||||
|
"""Initialize all components with web interface support"""
|
||||||
|
try:
|
||||||
|
self.logger.info("=== WEB + MPV APPLICATION INITIALIZATION START ===")
|
||||||
|
|
||||||
|
# Create enhanced debug console with web interface (runs in main thread)
|
||||||
|
self.debug_console = EnhancedDebugConsoleWithWeb(
|
||||||
|
enable_web=True,
|
||||||
|
web_port=self.web_port
|
||||||
|
)
|
||||||
|
self.logger.info("Enhanced debug console with web interface created")
|
||||||
|
|
||||||
|
# Create MPV seamless player (runs in separate thread)
|
||||||
|
self.video_player = MPVSeamlessPlayer(self.config, self.debug_console)
|
||||||
|
self.logger.info("MPV seamless player created")
|
||||||
|
|
||||||
|
# Connect components
|
||||||
|
self.debug_console.set_video_player(self.video_player)
|
||||||
|
self.logger.info("Components connected successfully")
|
||||||
|
|
||||||
|
self.logger.info("=== WEB + MPV APPLICATION INITIALIZATION COMPLETE ===")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Web + MPV initialization failed: {e}", exc_info=True)
|
||||||
|
print(f"\nInitialization Error: {e}")
|
||||||
|
print("\nTroubleshooting:")
|
||||||
|
print("1. Ensure MPV is installed and DLL files are present")
|
||||||
|
print("2. Check that python-mpv is installed: pip install python-mpv")
|
||||||
|
print("3. Check that Flask is installed: pip install flask flask-socketio")
|
||||||
|
print("4. Verify video files exist in the trailers folder")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def start_video_player_thread(self):
|
||||||
|
"""Start MPV video player in separate thread"""
|
||||||
|
def mpv_video_player_worker():
|
||||||
|
try:
|
||||||
|
self.logger.info("MPV video player thread starting...")
|
||||||
|
self.video_player.run()
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"MPV video player thread error: {e}", exc_info=True)
|
||||||
|
print(f"Video player error: {e}")
|
||||||
|
finally:
|
||||||
|
self.logger.info("MPV video player thread ended")
|
||||||
|
|
||||||
|
self.video_thread = threading.Thread(
|
||||||
|
target=mpv_video_player_worker,
|
||||||
|
daemon=True,
|
||||||
|
name="MPVVideoPlayerThread"
|
||||||
|
)
|
||||||
|
self.video_thread.start()
|
||||||
|
self.logger.info("MPV video player thread started")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Main application loop with web interface"""
|
||||||
|
self.logger.info("=== WEB + MPV APPLICATION START ===")
|
||||||
|
|
||||||
|
# Get local IP for display
|
||||||
|
try:
|
||||||
|
import socket
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
||||||
|
s.connect(('8.8.8.8', 80))
|
||||||
|
local_ip = s.getsockname()[0]
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
hostname = socket.gethostname()
|
||||||
|
local_ip = socket.gethostbyname(hostname)
|
||||||
|
if local_ip.startswith('127.'):
|
||||||
|
local_ip = 'your-computer-ip'
|
||||||
|
except:
|
||||||
|
local_ip = 'your-computer-ip'
|
||||||
|
|
||||||
|
print("\n" + "="*70)
|
||||||
|
print("🎬 MPV SEAMLESS VIDEO PLAYER WITH WEB INTERFACE")
|
||||||
|
print("="*70)
|
||||||
|
print("🌐 Web interface enabled - modern control dashboard!")
|
||||||
|
print("📱 Mobile responsive design")
|
||||||
|
print("⚡ Real-time status updates")
|
||||||
|
print("🎮 Remote control via web browser")
|
||||||
|
print("✓ All original functionality preserved")
|
||||||
|
print("✓ Global input capture maintained")
|
||||||
|
print("✓ Superior MPV video quality")
|
||||||
|
print("="*70)
|
||||||
|
print(f"\n🔗 WEB INTERFACE ACCESS URLS:")
|
||||||
|
print(f" 📍 Local: http://localhost:{self.web_port}")
|
||||||
|
print(f" 🌐 Network: http://{local_ip}:{self.web_port}")
|
||||||
|
print(f" 📱 Mobile: http://{local_ip}:{self.web_port}")
|
||||||
|
print("="*70)
|
||||||
|
print("📱 MOBILE ACCESS INSTRUCTIONS:")
|
||||||
|
print(f" 1. Connect phone/tablet to same WiFi network")
|
||||||
|
print(f" 2. Open browser on mobile device")
|
||||||
|
print(f" 3. Go to: http://{local_ip}:{self.web_port}")
|
||||||
|
print(f" 4. Bookmark for easy access!")
|
||||||
|
print("="*70)
|
||||||
|
print("\nInitializing components...")
|
||||||
|
|
||||||
|
if not self.initialize_components():
|
||||||
|
self.logger.error("Failed to initialize components - exiting")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start MPV video player in background thread
|
||||||
|
self.start_video_player_thread()
|
||||||
|
|
||||||
|
# Give MPV player time to initialize
|
||||||
|
print("🎬 MPV player starting...")
|
||||||
|
time.sleep(2)
|
||||||
|
print("✓ MPV player ready!")
|
||||||
|
|
||||||
|
print(f"\n🌐 Web interface starting on port {self.web_port}...")
|
||||||
|
time.sleep(1)
|
||||||
|
print("✓ Web interface ready!")
|
||||||
|
|
||||||
|
print("\n🎯 DUAL CONTROL OPTIONS:")
|
||||||
|
print(" 1. 🖥️ Traditional Debug Console (this window)")
|
||||||
|
print(" 2. 🌐 Modern Web Interface (browser)")
|
||||||
|
print(" 3. 📱 Mobile/Remote Control (any device)")
|
||||||
|
|
||||||
|
print("\n🚀 ENHANCED FEATURES:")
|
||||||
|
print(" • Real-time video statistics")
|
||||||
|
print(" • Performance monitoring")
|
||||||
|
print(" • Video history tracking")
|
||||||
|
print(" • Remote NFC input")
|
||||||
|
print(" • System health monitoring")
|
||||||
|
print(" • Hot-reload mappings")
|
||||||
|
print(" • Manual video selection")
|
||||||
|
|
||||||
|
print(f"\n📖 Quick Start:")
|
||||||
|
print(f" 1. Open browser to: http://localhost:{self.web_port}")
|
||||||
|
print(f" 2. Control videos from web dashboard")
|
||||||
|
print(f" 3. NFC cards work globally (even fullscreen)")
|
||||||
|
print(f" 4. Edit mappings and click 'Reload Mappings'")
|
||||||
|
print(f" 5. Close debug window OR web interface to exit")
|
||||||
|
|
||||||
|
print("\n" + "="*70)
|
||||||
|
print("🎬 SYSTEM READY - Access web interface via URLs above!")
|
||||||
|
print("="*70)
|
||||||
|
|
||||||
|
# Run debug console in main thread (blocks until window closes)
|
||||||
|
# The web interface runs in parallel threads
|
||||||
|
self.debug_console.run()
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.logger.info("Web + MPV application interrupted by user")
|
||||||
|
print("\nApplication interrupted by user")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Web + MPV application error: {e}", exc_info=True)
|
||||||
|
print(f"\nApplication error: {e}")
|
||||||
|
finally:
|
||||||
|
self.cleanup()
|
||||||
|
|
||||||
|
self.logger.info("=== WEB + MPV APPLICATION END ===")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""Clean up all resources"""
|
||||||
|
self.logger.info("=== WEB + MPV CLEANUP START ===")
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
print("\nShutting down web + MPV application...")
|
||||||
|
|
||||||
|
if hasattr(self, 'video_player') and self.video_player:
|
||||||
|
try:
|
||||||
|
self.video_player.stop()
|
||||||
|
self.logger.info("MPV video player stopped")
|
||||||
|
print("✓ MPV video player stopped")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error stopping MPV video player: {e}")
|
||||||
|
|
||||||
|
# Wait for video thread to finish
|
||||||
|
if hasattr(self, 'video_thread') and self.video_thread and self.video_thread.is_alive():
|
||||||
|
try:
|
||||||
|
print("Waiting for MPV thread to finish...")
|
||||||
|
self.video_thread.join(timeout=5)
|
||||||
|
if self.video_thread.is_alive():
|
||||||
|
self.logger.warning("MPV video thread did not stop cleanly")
|
||||||
|
print("⚠ MPV thread did not stop cleanly")
|
||||||
|
else:
|
||||||
|
self.logger.info("MPV video thread joined successfully")
|
||||||
|
print("✓ MPV thread stopped")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error joining MPV video thread: {e}")
|
||||||
|
|
||||||
|
if hasattr(self, 'debug_console') and self.debug_console:
|
||||||
|
try:
|
||||||
|
self.debug_console.stop()
|
||||||
|
self.logger.info("Enhanced debug console stopped")
|
||||||
|
print("✓ Debug console and web interface stopped")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error stopping debug console: {e}")
|
||||||
|
|
||||||
|
self.logger.info("=== WEB + MPV CLEANUP COMPLETE ===")
|
||||||
|
print("✓ Cleanup complete - all resources freed")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point with web interface"""
|
||||||
|
print("MPV Seamless Video Player with Web Interface")
|
||||||
|
print("Next-Generation Video Control System")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
# Check requirements first
|
||||||
|
if not check_web_requirements():
|
||||||
|
print("\n✗ Requirements not met. Please install missing components.")
|
||||||
|
print("\nRequired installations:")
|
||||||
|
print("pip install flask flask-socketio python-mpv")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print("\n🚀 Starting web-enabled MPV application...")
|
||||||
|
|
||||||
|
# Allow custom port via command line
|
||||||
|
web_port = 8547
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
try:
|
||||||
|
web_port = int(sys.argv[1])
|
||||||
|
print(f"Using custom port: {web_port}")
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid port number, using default: 8547")
|
||||||
|
|
||||||
|
try:
|
||||||
|
app = WebMPVVideoPlayerApp(web_port=web_port)
|
||||||
|
return app.run()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n✗ Fatal error: {e}")
|
||||||
|
logging.error(f"Fatal application error: {e}", exc_info=True)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Set up basic logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s [%(name)s] %(levelname)s: %(message)s'
|
||||||
|
)
|
||||||
|
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user