Enhance media API with video file validation and Docker configuration update
- Added a function to check if video files are complete and valid using ffprobe, preventing errors during thumbnail generation. - Updated thumbnail generation logic to skip incomplete or corrupted files, improving robustness. - Modified docker-compose.yml to include a restart policy for the camera management API service, ensuring better container reliability.
This commit is contained in:
@@ -5,6 +5,7 @@ services:
|
||||
context: ./camera-management-api
|
||||
dockerfile: Dockerfile
|
||||
working_dir: /app
|
||||
restart: unless-stopped # Automatically restart container if it fails or exits
|
||||
volumes:
|
||||
- ./camera-management-api:/app
|
||||
- /mnt/nfs_share:/mnt/nfs_share
|
||||
|
||||
@@ -138,13 +138,45 @@ def file_id_from_path(p: pathlib.Path) -> str:
|
||||
|
||||
|
||||
def path_from_file_id(fid: str) -> pathlib.Path:
|
||||
rel = urllib.parse.unquote_plus(fid)
|
||||
# Handle double-encoding: decode until no more changes
|
||||
rel = fid
|
||||
while True:
|
||||
decoded = urllib.parse.unquote_plus(rel)
|
||||
if decoded == rel:
|
||||
break
|
||||
rel = decoded
|
||||
p = (MEDIA_DIR / rel).resolve()
|
||||
if not p.is_file() or MEDIA_DIR not in p.parents:
|
||||
raise HTTPException(status_code=404, detail="Video not found")
|
||||
return p
|
||||
|
||||
|
||||
def is_video_file_complete(p: pathlib.Path) -> bool:
|
||||
"""
|
||||
Check if video file is complete and valid using ffprobe.
|
||||
Returns True if file is complete and can be processed, False otherwise.
|
||||
"""
|
||||
try:
|
||||
# Quick check: use ffprobe to verify file is valid
|
||||
cmd = [
|
||||
"ffprobe",
|
||||
"-v", "error",
|
||||
"-show_entries", "format=duration",
|
||||
"-of", "default=noprint_wrappers=1:nokey=1",
|
||||
str(p)
|
||||
]
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
timeout=5
|
||||
)
|
||||
# If ffprobe succeeds, file is valid
|
||||
return result.returncode == 0
|
||||
except (subprocess.TimeoutExpired, subprocess.CalledProcessError, Exception):
|
||||
return False
|
||||
|
||||
|
||||
def generate_thumbnail_background(p: pathlib.Path, width: int = 320, height: int = 180) -> bool:
|
||||
"""
|
||||
Generate thumbnail in background (non-blocking, doesn't raise exceptions).
|
||||
@@ -188,13 +220,19 @@ def generate_thumbnail_background(p: pathlib.Path, width: int = 320, height: int
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
# Check if video file is complete and valid before attempting thumbnail generation
|
||||
# This prevents errors with incomplete/corrupted files
|
||||
if not is_video_file_complete(p):
|
||||
return False # File is incomplete or corrupted, skip
|
||||
|
||||
# Try to generate thumbnail - try 1s first, then 0s if that fails
|
||||
for seek_time in [1.0, 0.0]:
|
||||
cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-ss", str(seek_time),
|
||||
"-i", str(p),
|
||||
"-vframes", "1",
|
||||
"-frames:v", "1",
|
||||
"-update", "1", # Required for single image output with image2 muxer
|
||||
"-vf", f"scale='min({width},iw)':-2,scale={width}:{height}:force_original_aspect_ratio=decrease,pad={width}:{height}:(ow-iw)/2:(oh-ih)/2",
|
||||
str(out)
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user