42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
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) |