from __future__ import annotations from dataclasses import dataclass from enum import Enum from pathlib import Path from typing import Optional class MediaKind(str, Enum): IMAGE = "image" VIDEO = "video" IMAGE_EXTENSIONS = { ".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tif", ".tiff", } VIDEO_EXTENSIONS = { ".mp4", ".mov", ".mkv", ".avi", ".webm", ".m4v", ".mpg", ".mpeg", ".wmv", ".flv", ".ts", ".3gp", ".mts", ".m2ts", } SUPPORTED_EXTENSIONS = IMAGE_EXTENSIONS | VIDEO_EXTENSIONS @dataclass(frozen=True) class MediaInfo: path: Path kind: MediaKind size: int width: int height: int format_name: str duration: float = 0.0 codec: str = "" @dataclass class MediaItem: item_id: str info: MediaInfo output_path: Optional[Path] = None output_size: int = 0 message: str = "" @property def path(self) -> Path: return self.info.path @property def kind(self) -> MediaKind: return self.info.kind @property def size(self) -> int: return self.info.size @dataclass class ImageOptions: output_format: str = "original" # original | jpeg | webp | png quality: int = 82 resize_mode: str = "original" # original | fit | percent max_width: int = 1920 max_height: int = 1080 scale_percent: int = 80 keep_metadata: bool = False @dataclass class VideoOptions: codec: str = "h264" # h264 | h265 | vp9 | av1 quality: int = 68 speed: str = "balanced" # fast | balanced | best resolution: int = 0 # 0 = original, otherwise target short edge audio_bitrate: int = 128 # 0 = mute keep_metadata: bool = False def default_image_options() -> ImageOptions: return ImageOptions() def default_video_options() -> VideoOptions: return VideoOptions()