editor / src /file_handler.py
Vo Hoang Minh
up
ed85b4d
import os
from pathlib import Path
from PIL import Image
from typing import List, Optional, Union, Any, Dict, Tuple
from .utils import IMG_EXTS, VID_EXTS, is_media, size_mb, unique_name
class FileHandler:
def __init__(self) -> None:
self.temp_dir = self._setup_temp()
def _setup_temp(self) -> str:
temp = os.path.join(os.getcwd(), 'temp_processing')
os.makedirs(temp, exist_ok=True)
return temp
def cleanup(self) -> None:
if os.path.exists(self.temp_dir):
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
def info(self, path: str) -> Dict[str, Any]:
return {
'path': path,
'name': os.path.basename(path),
'size_mb': size_mb(path),
'type': self._type(path),
'dims': self._dims(path)
}
def _type(self, path: str) -> str:
ext = Path(path).suffix.lower()
if ext in IMG_EXTS:
return 'image'
elif ext in VID_EXTS:
return 'video'
return 'unknown'
def _dims(self, path: str) -> Optional[str]:
if not os.path.exists(path):
return None
if Path(path).suffix.lower() in IMG_EXTS:
with Image.open(path) as img:
return f"{img.width}x{img.height}"
return None
def get_files(self, input: Union[str, List[Any], None]) -> List[str]:
if not input:
return []
if not isinstance(input, list):
input = [input]
# Handle folder
if (len(input) == 1 and
isinstance(input[0], str) and
os.path.isdir(input[0])):
return self._from_folder(input[0])
return self._extract_paths(input)
def _from_folder(self, folder: str) -> List[str]:
return [str(p) for p in Path(folder).rglob('*')
if p.is_file() and is_media(str(p))]
def _extract_paths(self, files: List[Any]) -> List[str]:
result = []
for f in files:
if f is None:
continue
path = None
if hasattr(f, 'name') and f.name:
path = f.name
elif hasattr(f, 'path') and f.path:
path = f.path
elif isinstance(f, str):
path = f
if path and os.path.exists(path) and is_media(path):
result.append(path)
return result
def preview(self, files: List[str], max_items: int = 6) -> Optional[str]:
if not files:
return None
imgs = [f for f in files[:max_items]
if os.path.exists(f) and Path(f).suffix.lower() in IMG_EXTS]
if not imgs:
return None
# Load and resize
images = []
for path in imgs:
with Image.open(path) as img:
copy = img.copy()
copy.thumbnail((120, 120))
images.append(copy)
# Create grid
cols = min(3, len(images))
rows = (len(images) + cols - 1) // cols
grid = Image.new('RGB', (cols * 120, rows * 120), 'white')
for i, img in enumerate(images):
x, y = (i % cols) * 120, (i // cols) * 120
grid.paste(img, (x, y))
path = os.path.join(self.temp_dir, unique_name('preview', '.jpg'))
grid.save(path, 'JPEG', quality=85)
return path
def files_info(self, input: Union[str, List[Any], None]) -> Tuple[List[str], Dict[str, Any]]:
files = self.get_files(input)
info = {
'total': len(files),
'size_mb': 0,
'images': 0,
'videos': 0,
'details': []
}
for path in files:
detail = self.info(path)
info['details'].append(detail)
info['size_mb'] += detail['size_mb']
if detail['type'] == 'image':
info['images'] += 1
elif detail['type'] == 'video':
info['videos'] += 1
info['size_mb'] = round(info['size_mb'], 2)
return files, info
def temp_path(self, name: str) -> str:
return os.path.join(self.temp_dir, name)