|
|
def execute_python_script(script_code, context=None): |
|
|
""" |
|
|
Safely execute Python script with limited context |
|
|
Returns script output or error message |
|
|
""" |
|
|
import io |
|
|
import sys |
|
|
from contextlib import redirect_stdout, redirect_stderr |
|
|
|
|
|
if context is None: |
|
|
context = { |
|
|
'video_path': None, |
|
|
'frame_data': None, |
|
|
'metadata': None |
|
|
} |
|
|
|
|
|
|
|
|
output = io.StringIO() |
|
|
error = io.StringIO() |
|
|
|
|
|
try: |
|
|
with redirect_stdout(output), redirect_stderr(error): |
|
|
|
|
|
exec_globals = { |
|
|
'__builtins__': { |
|
|
'print': print, |
|
|
'str': str, |
|
|
'int': int, |
|
|
'float': float, |
|
|
'list': list, |
|
|
'dict': dict, |
|
|
'tuple': tuple, |
|
|
'range': range, |
|
|
'len': len, |
|
|
'enumerate': enumerate, |
|
|
'zip': zip, |
|
|
'min': min, |
|
|
'max': max, |
|
|
'sum': sum, |
|
|
'abs': abs, |
|
|
'round': round |
|
|
}, |
|
|
'context': context |
|
|
} |
|
|
|
|
|
exec(script_code, exec_globals) |
|
|
|
|
|
if error.getvalue(): |
|
|
return f"Error: {error.getvalue()}" |
|
|
else: |
|
|
return output.getvalue() |
|
|
|
|
|
except Exception as e: |
|
|
return f"Error executing script: {str(e)}" |
|
|
|
|
|
def validate_python_script(script_code): |
|
|
""" |
|
|
Validate Python script syntax and restricted functions |
|
|
Returns (is_valid, error_message) |
|
|
""" |
|
|
import ast |
|
|
|
|
|
try: |
|
|
|
|
|
tree = ast.parse(script_code) |
|
|
|
|
|
|
|
|
for node in ast.walk(tree): |
|
|
if isinstance(node, ast.Import): |
|
|
return (False, "Import statements are not allowed") |
|
|
if isinstance(node, ast.ImportFrom): |
|
|
return (False, "Import statements are not allowed") |
|
|
if isinstance(node, ast.Call): |
|
|
if isinstance(node.func, ast.Name): |
|
|
if node.func.id in ['eval', 'exec', 'open', 'execfile']: |
|
|
return (False, f"Function {node.func.id}() is not allowed") |
|
|
|
|
|
return (True, "Script is valid") |
|
|
except SyntaxError as e: |
|
|
return (False, f"Syntax error: {str(e)}") |
|
|
|
|
|
|
|
|
def extract_video_metadata(video_path): |
|
|
""" |
|
|
Extract technical metadata from video file |
|
|
Returns dictionary of metadata |
|
|
""" |
|
|
import cv2 |
|
|
from datetime import datetime |
|
|
import os |
|
|
|
|
|
cap = cv2.VideoCapture(video_path) |
|
|
|
|
|
if not cap.isOpened(): |
|
|
return None |
|
|
|
|
|
|
|
|
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) |
|
|
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
|
|
fps = cap.get(cv2.CAP_PROP_FPS) |
|
|
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) |
|
|
duration = frame_count / fps |
|
|
|
|
|
|
|
|
file_stats = os.stat(video_path) |
|
|
created = datetime.fromtimestamp(file_stats.st_ctime) |
|
|
modified = datetime.fromtimestamp(file_stats.st_mtime) |
|
|
|
|
|
cap.release() |
|
|
|
|
|
return { |
|
|
'filename': os.path.basename(video_path), |
|
|
'path': video_path, |
|
|
'resolution': f"{width}x{height}", |
|
|
'fps': fps, |
|
|
'duration': duration, |
|
|
'frame_count': frame_count, |
|
|
'size': file_stats.st_size, |
|
|
'created': created, |
|
|
'modified': modified |
|
|
} |
|
|
|
|
|
def extract_audio_metadata(audio_path): |
|
|
""" |
|
|
Extract technical metadata from audio file |
|
|
Returns dictionary of metadata |
|
|
""" |
|
|
import wave |
|
|
from datetime import datetime |
|
|
import os |
|
|
|
|
|
try: |
|
|
with wave.open(audio_path, 'rb') as audio_file: |
|
|
channels = audio_file.getnchannels() |
|
|
sample_width = audio_file.getsampwidth() |
|
|
framerate = audio_file.getframerate() |
|
|
frames = audio_file.getnframes() |
|
|
duration = frames / float(framerate) |
|
|
|
|
|
file_stats = os.stat(audio_path) |
|
|
created = datetime.fromtimestamp(file_stats.st_ctime) |
|
|
modified = datetime.fromtimestamp(file_stats.st_mtime) |
|
|
|
|
|
return { |
|
|
'filename': os.path.basename(audio_path), |
|
|
'path': audio_path, |
|
|
'channels': channels, |
|
|
'sample_width': sample_width, |
|
|
'sample_rate': framerate, |
|
|
'duration': duration, |
|
|
'size': file_stats.st_size, |
|
|
'created': created, |
|
|
'modified': modified |
|
|
} |
|
|
except: |
|
|
return None |
|
|
|
|
|
def extract_exif_data(image_path): |
|
|
""" |
|
|
Extract EXIF metadata from image file |
|
|
Returns dictionary of EXIF data |
|
|
""" |
|
|
from PIL import Image, ExifTags |
|
|
from datetime import datetime |
|
|
import os |
|
|
|
|
|
try: |
|
|
img = Image.open(image_path) |
|
|
exif_data = img._getexif() |
|
|
|
|
|
if not exif_data: |
|
|
return None |
|
|
|
|
|
exif = {} |
|
|
for tag, value in exif_data.items(): |
|
|
decoded = ExifTags.TAGS.get(tag, tag) |
|
|
exif[decoded] = value |
|
|
|
|
|
|
|
|
file_stats = os.stat(image_path) |
|
|
created = datetime.fromtimestamp(file_stats.st_ctime) |
|
|
modified = datetime.fromtimestamp(file_stats.st_mtime) |
|
|
|
|
|
exif['filename'] = os.path.basename(image_path) |
|
|
exif['path'] = image_path |
|
|
exif['size'] = file_stats.st_size |
|
|
exif['created'] = created |
|
|
exif['modified'] = modified |
|
|
|
|
|
return exif |
|
|
except: |
|
|
return None |
|
|
|
|
|
|
|
|
def detect_faces(frame, min_confidence=0.7): |
|
|
""" |
|
|
Detect faces in a frame using OpenCV DNN |
|
|
Returns list of face bounding boxes and confidence scores |
|
|
""" |