remove bug for playing videos
This commit is contained in:
@@ -21,7 +21,7 @@ from datetime import datetime, timezone
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
from typing import Optional, Dict, List, IO
|
from typing import Optional, Dict, List, IO
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse, urlsplit, urlunsplit, quote
|
||||||
import requests
|
import requests
|
||||||
import psutil
|
import psutil
|
||||||
import json as _json
|
import json as _json
|
||||||
@@ -450,9 +450,25 @@ class DisplayProcess:
|
|||||||
# python-vlc MediaPlayer: is_playing() returns 1 while playing
|
# python-vlc MediaPlayer: is_playing() returns 1 while playing
|
||||||
if hasattr(self.player, 'is_playing'):
|
if hasattr(self.player, 'is_playing'):
|
||||||
try:
|
try:
|
||||||
return bool(self.player.is_playing())
|
if bool(self.player.is_playing()):
|
||||||
except Exception:
|
return True
|
||||||
|
|
||||||
|
# A plain is_playing()==0 can happen briefly during opening/
|
||||||
|
# buffering on HTTP streams. Treat those states as still alive.
|
||||||
|
state = None
|
||||||
|
if hasattr(self.player, 'get_state'):
|
||||||
|
state = self.player.get_state()
|
||||||
|
if state is not None:
|
||||||
|
import vlc as _vlc
|
||||||
|
return state in (
|
||||||
|
_vlc.State.Opening,
|
||||||
|
_vlc.State.Buffering,
|
||||||
|
_vlc.State.Playing,
|
||||||
|
_vlc.State.Paused,
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
# MediaListPlayer may not have is_playing - try to inspect media player state
|
# MediaListPlayer may not have is_playing - try to inspect media player state
|
||||||
try:
|
try:
|
||||||
state = None
|
state = None
|
||||||
@@ -1144,6 +1160,7 @@ class DisplayManager:
|
|||||||
|
|
||||||
# Normalize file-server host alias (e.g., http://server:8000/...) -> configured FILE_SERVER
|
# Normalize file-server host alias (e.g., http://server:8000/...) -> configured FILE_SERVER
|
||||||
video_url = self._resolve_file_url(video_url)
|
video_url = self._resolve_file_url(video_url)
|
||||||
|
video_url = self._sanitize_media_url(video_url)
|
||||||
logging.info(f"Starting video: {video_url}")
|
logging.info(f"Starting video: {video_url}")
|
||||||
# Prefer using python-vlc (libvlc) for finer control
|
# Prefer using python-vlc (libvlc) for finer control
|
||||||
try:
|
try:
|
||||||
@@ -1355,6 +1372,34 @@ class DisplayManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug(f"Error resolving file url '{url}': {e}")
|
logging.debug(f"Error resolving file url '{url}': {e}")
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
def _sanitize_media_url(self, url: str) -> str:
|
||||||
|
"""Percent-encode media URLs so VLC/ffmpeg handle spaces/unicode reliably.
|
||||||
|
|
||||||
|
Some event payloads include raw spaces or non-ASCII characters in URL paths.
|
||||||
|
Requests usually tolerates that, but VLC/ffmpeg can fail to open those URLs.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not url:
|
||||||
|
return url
|
||||||
|
|
||||||
|
parts = urlsplit(url)
|
||||||
|
if parts.scheme not in ('http', 'https'):
|
||||||
|
return url
|
||||||
|
|
||||||
|
safe_path = quote(parts.path or '/', safe="/%:@!$&'()*+,;=-._~")
|
||||||
|
safe_query = quote(parts.query or '', safe="=&%:@!$'()*+,;/?-._~")
|
||||||
|
sanitized = urlunsplit((parts.scheme, parts.netloc, safe_path, safe_query, parts.fragment))
|
||||||
|
|
||||||
|
if sanitized != url:
|
||||||
|
logging.info("Sanitized media URL for VLC compatibility")
|
||||||
|
logging.debug(f"Media URL before: {url}")
|
||||||
|
logging.debug(f"Media URL after: {sanitized}")
|
||||||
|
|
||||||
|
return sanitized
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"Could not sanitize media URL '{url}': {e}")
|
||||||
|
return url
|
||||||
|
|
||||||
def start_webpage(self, event: Dict, autoscroll_enabled: bool = False) -> Optional[DisplayProcess]:
|
def start_webpage(self, event: Dict, autoscroll_enabled: bool = False) -> Optional[DisplayProcess]:
|
||||||
"""Start webpage display in kiosk mode"""
|
"""Start webpage display in kiosk mode"""
|
||||||
@@ -1654,12 +1699,26 @@ class DisplayManager:
|
|||||||
# Same event - check if process is still running
|
# Same event - check if process is still running
|
||||||
if not self.current_process.is_running():
|
if not self.current_process.is_running():
|
||||||
exit_code = None
|
exit_code = None
|
||||||
|
player_state = None
|
||||||
if getattr(self.current_process, 'process', None):
|
if getattr(self.current_process, 'process', None):
|
||||||
try:
|
try:
|
||||||
exit_code = self.current_process.process.returncode
|
exit_code = self.current_process.process.returncode
|
||||||
except Exception:
|
except Exception:
|
||||||
exit_code = None
|
exit_code = None
|
||||||
|
elif getattr(self.current_process, 'player', None):
|
||||||
|
try:
|
||||||
|
player = self.current_process.player
|
||||||
|
if hasattr(player, 'get_state'):
|
||||||
|
player_state = player.get_state()
|
||||||
|
elif hasattr(player, 'get_media_player'):
|
||||||
|
mp = player.get_media_player()
|
||||||
|
if mp and hasattr(mp, 'get_state'):
|
||||||
|
player_state = mp.get_state()
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"Could not read VLC player state: {e}")
|
||||||
logging.warning(f"Display process exited (exit code: {exit_code})")
|
logging.warning(f"Display process exited (exit code: {exit_code})")
|
||||||
|
if player_state is not None:
|
||||||
|
logging.warning(f"VLC player state at exit detection: {player_state}")
|
||||||
# Try to surface last lines of the related log file, if any
|
# Try to surface last lines of the related log file, if any
|
||||||
if getattr(self.current_process, 'log_path', None):
|
if getattr(self.current_process, 'log_path', None):
|
||||||
try:
|
try:
|
||||||
@@ -2122,6 +2181,7 @@ class DisplayManager:
|
|||||||
video = self.current_event_data.get('video', {}) if isinstance(self.current_event_data, dict) else {}
|
video = self.current_event_data.get('video', {}) if isinstance(self.current_event_data, dict) else {}
|
||||||
source_url = video.get('url') if isinstance(video, dict) else None
|
source_url = video.get('url') if isinstance(video, dict) else None
|
||||||
source_url = self._resolve_file_url(source_url) if source_url else None
|
source_url = self._resolve_file_url(source_url) if source_url else None
|
||||||
|
source_url = self._sanitize_media_url(source_url) if source_url else None
|
||||||
if not source_url:
|
if not source_url:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user