from __future__ import annotations import hashlib import os import re from pathlib import Path IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg"} VIDEO_EXTENSIONS = {".mp4", ".mov", ".avi", ".mkv", ".webm", ".flv", ".wmv"} ALLOWED_EXTENSIONS = IMAGE_EXTENSIONS | VIDEO_EXTENSIONS | {".pdf", ".txt", ".json", ".zip", ".rar"} _DEFAULT_MAX_FILE_BYTES = 50 * 1024 * 1024 class FileService: def __init__(self, storage_dir: str | Path, max_file_bytes: int = _DEFAULT_MAX_FILE_BYTES): self.storage_dir = Path(storage_dir) self.storage_dir.mkdir(parents=True, exist_ok=True) self.max_file_bytes = max_file_bytes def classify(self, filename: str) -> str: ext = os.path.splitext(filename)[1].lower() if ext in IMAGE_EXTENSIONS: return "image" if ext in VIDEO_EXTENSIONS: return "video" return "file" def generate_safe_name(self, original_name: str) -> str: name = self._sanitize_filename(original_name) h = hashlib.sha256(name.encode()).hexdigest()[:12] ext = os.path.splitext(original_name)[1].lower() return f"{h}_{name}" async def save_upload(self, content: bytes, safe_name: str) -> Path: dest = self.storage_dir / safe_name dest.write_bytes(content) return dest @staticmethod def _sanitize_filename(filename: str) -> str: return re.sub(r"[^\w.\-]", "_", filename)