Refactor OAuth provider linking and unlinking logic into a dedicated service; enhance error handling and logging throughout the application; improve sound management and scanning services with better file handling and unique naming; implement centralized error and logging services for consistent API responses and application-wide logging configuration.
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
"""VLC service for playing sounds using subprocess."""
|
||||
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from app.database import db
|
||||
from app.models.sound import Sound
|
||||
from app.models.sound_played import SoundPlayed
|
||||
from app.services.logging_service import LoggingService
|
||||
|
||||
logger = LoggingService.get_logger(__name__)
|
||||
|
||||
|
||||
class VLCService:
|
||||
@@ -17,7 +17,7 @@ class VLCService:
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize VLC service."""
|
||||
self.processes: Dict[str, subprocess.Popen] = {}
|
||||
self.processes: dict[str, subprocess.Popen] = {}
|
||||
self.lock = threading.Lock()
|
||||
|
||||
def play_sound(self, sound_id: int, user_id: int | None = None) -> bool:
|
||||
@@ -38,7 +38,9 @@ class VLCService:
|
||||
)
|
||||
else:
|
||||
sound_path = os.path.join(
|
||||
"sounds", "soundboard", sound.filename
|
||||
"sounds",
|
||||
"soundboard",
|
||||
sound.filename,
|
||||
)
|
||||
|
||||
# Check if file exists
|
||||
@@ -73,8 +75,9 @@ class VLCService:
|
||||
with self.lock:
|
||||
self.processes[process_id] = process
|
||||
|
||||
print(
|
||||
f"Started VLC process {process.pid} ({process_id}) for sound {sound.name}. Total processes: {len(self.processes)}"
|
||||
logger.info(
|
||||
f"Started VLC process {process.pid} for sound '{sound.name}'. "
|
||||
f"Total active processes: {len(self.processes)}",
|
||||
)
|
||||
|
||||
# Increment play count
|
||||
@@ -89,7 +92,7 @@ class VLCService:
|
||||
commit=True,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error recording play event: {e}")
|
||||
logger.error(f"Error recording play event: {e}")
|
||||
|
||||
# Schedule cleanup after sound duration
|
||||
threading.Thread(
|
||||
@@ -101,7 +104,9 @@ class VLCService:
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error starting VLC process for sound {sound_id}: {e}")
|
||||
logger.error(
|
||||
f"Error starting VLC process for sound {sound_id}: {e}"
|
||||
)
|
||||
return False
|
||||
|
||||
def _cleanup_after_playback(self, process_id: str, duration: int) -> None:
|
||||
@@ -111,13 +116,13 @@ class VLCService:
|
||||
|
||||
with self.lock:
|
||||
if process_id in self.processes:
|
||||
print(f"Cleaning up process {process_id} after playback")
|
||||
logger.debug(f"Cleaning up process {process_id} after playback")
|
||||
process = self.processes[process_id]
|
||||
|
||||
try:
|
||||
# Check if process is still running
|
||||
if process.poll() is None:
|
||||
print(
|
||||
logger.debug(
|
||||
f"Process {process.pid} still running, terminating"
|
||||
)
|
||||
process.terminate()
|
||||
@@ -125,62 +130,58 @@ class VLCService:
|
||||
try:
|
||||
process.wait(timeout=2)
|
||||
except subprocess.TimeoutExpired:
|
||||
print(
|
||||
logger.debug(
|
||||
f"Process {process.pid} didn't terminate, killing"
|
||||
)
|
||||
process.kill()
|
||||
|
||||
print(f"Successfully cleaned up process {process_id}")
|
||||
logger.debug(
|
||||
f"Successfully cleaned up process {process_id}"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error during cleanup of {process_id}: {e}")
|
||||
logger.warning(f"Error during cleanup of {process_id}: {e}")
|
||||
finally:
|
||||
# Always remove from tracking
|
||||
del self.processes[process_id]
|
||||
print(
|
||||
f"Removed process {process_id}. Remaining processes: {len(self.processes)}"
|
||||
logger.debug(
|
||||
f"Removed process {process_id}. Remaining processes: {len(self.processes)}",
|
||||
)
|
||||
else:
|
||||
print(f"Process {process_id} not found during cleanup")
|
||||
|
||||
def stop_all(self) -> None:
|
||||
"""Stop all playing sounds by killing VLC processes."""
|
||||
with self.lock:
|
||||
processes_copy = dict(self.processes)
|
||||
print(
|
||||
f"Stopping {len(processes_copy)} VLC processes: {list(processes_copy.keys())}"
|
||||
)
|
||||
if processes_copy:
|
||||
logger.info(f"Stopping {len(processes_copy)} VLC processes")
|
||||
|
||||
for process_id, process in processes_copy.items():
|
||||
try:
|
||||
if process.poll() is None: # Process is still running
|
||||
print(
|
||||
f"Terminating process {process.pid} ({process_id})"
|
||||
)
|
||||
logger.debug(f"Terminating process {process.pid}")
|
||||
process.terminate()
|
||||
|
||||
# Give it a moment to terminate gracefully
|
||||
try:
|
||||
process.wait(timeout=1)
|
||||
print(
|
||||
logger.debug(
|
||||
f"Process {process.pid} terminated gracefully"
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
print(
|
||||
logger.debug(
|
||||
f"Process {process.pid} didn't terminate, killing forcefully"
|
||||
)
|
||||
process.kill()
|
||||
process.wait() # Wait for it to be killed
|
||||
else:
|
||||
print(
|
||||
f"Process {process.pid} ({process_id}) already finished"
|
||||
)
|
||||
logger.debug(f"Process {process.pid} already finished")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error stopping process {process_id}: {e}")
|
||||
logger.warning(f"Error stopping process {process_id}: {e}")
|
||||
|
||||
# Clear all processes
|
||||
self.processes.clear()
|
||||
print(f"Cleared all processes. Remaining: {len(self.processes)}")
|
||||
if processes_copy:
|
||||
logger.info("All VLC processes stopped")
|
||||
|
||||
def get_playing_count(self) -> int:
|
||||
"""Get number of currently playing sounds."""
|
||||
@@ -201,34 +202,20 @@ class VLCService:
|
||||
"""Force stop all sounds by killing VLC processes aggressively."""
|
||||
with self.lock:
|
||||
stopped_count = len(self.processes)
|
||||
print(f"Force stopping {stopped_count} VLC processes")
|
||||
|
||||
# # Kill all VLC processes aggressively
|
||||
# for process_id, process in list(self.processes.items()):
|
||||
# try:
|
||||
# if process.poll() is None: # Process is still running
|
||||
# print(f"Force killing process {process.pid} ({process_id})")
|
||||
# process.kill()
|
||||
# process.wait() # Wait for it to be killed
|
||||
# print(f"Process {process.pid} killed")
|
||||
# else:
|
||||
# print(f"Process {process.pid} ({process_id}) already finished")
|
||||
|
||||
# except Exception as e:
|
||||
# print(f"Error force-stopping process {process_id}: {e}")
|
||||
if stopped_count > 0:
|
||||
logger.warning(f"Force stopping {stopped_count} VLC processes")
|
||||
|
||||
# Also try to kill any remaining VLC processes system-wide
|
||||
try:
|
||||
subprocess.run(["pkill", "-f", "vlc"], check=False)
|
||||
print("Killed any remaining VLC processes system-wide")
|
||||
logger.info("Killed any remaining VLC processes system-wide")
|
||||
except Exception as e:
|
||||
print(f"Error killing system VLC processes: {e}")
|
||||
logger.error(f"Error killing system VLC processes: {e}")
|
||||
|
||||
# Clear all processes
|
||||
self.processes.clear()
|
||||
print(
|
||||
f"Force stop completed. Processes remaining: {len(self.processes)}"
|
||||
)
|
||||
if stopped_count > 0:
|
||||
logger.info("Force stop completed")
|
||||
return stopped_count
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user