feat: support complet des images — arborescence, visionneuse, indexation #108
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""Shared media type constants and helpers.
|
||||
|
||||
Single source of truth for the file extensions and MIME types handled by the
|
||||
image support (roadmap #108) and reused by the audio/video players (#109).
|
||||
Keeping these sets here avoids the previous duplication (``indexer.py``,
|
||||
``attachment_indexer.py`` and ``main.py`` each carried their own copy).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import mimetypes
|
||||
|
||||
# Image extensions viewable in the browser (HEIC/HEIF deliberately excluded —
|
||||
# no browser decodes them natively; see roadmap #108).
|
||||
IMAGE_EXTENSIONS: frozenset[str] = frozenset({
|
||||
".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".bmp", ".ico",
|
||||
})
|
||||
|
||||
# Audio extensions (socle for #109, not wired into the index yet).
|
||||
AUDIO_EXTENSIONS: frozenset[str] = frozenset({
|
||||
".mp3", ".m4a", ".aac", ".wav", ".ogg", ".oga", ".opus", ".flac",
|
||||
})
|
||||
|
||||
# Video extensions (socle for #109, not wired into the index yet).
|
||||
VIDEO_EXTENSIONS: frozenset[str] = frozenset({
|
||||
".mp4", ".webm", ".mov", ".m4v",
|
||||
})
|
||||
|
||||
MEDIA_EXTENSIONS: frozenset[str] = IMAGE_EXTENSIONS | AUDIO_EXTENSIONS | VIDEO_EXTENSIONS
|
||||
|
||||
# Explicit MIME types for extensions ``mimetypes`` gets wrong or does not know.
|
||||
_MIME_OVERRIDES: dict[str, str] = {
|
||||
".jpg": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".svg": "image/svg+xml",
|
||||
".ico": "image/x-icon",
|
||||
".webp": "image/webp",
|
||||
".m4a": "audio/mp4",
|
||||
".oga": "audio/ogg",
|
||||
".opus": "audio/ogg",
|
||||
".mov": "video/quicktime",
|
||||
".m4v": "video/mp4",
|
||||
}
|
||||
|
||||
|
||||
def is_image(ext: str) -> bool:
|
||||
"""Return True when *ext* (with leading dot, any case) is an image."""
|
||||
return ext.lower() in IMAGE_EXTENSIONS
|
||||
|
||||
|
||||
def is_audio(ext: str) -> bool:
|
||||
"""Return True when *ext* is an audio extension."""
|
||||
return ext.lower() in AUDIO_EXTENSIONS
|
||||
|
||||
|
||||
def is_video(ext: str) -> bool:
|
||||
"""Return True when *ext* is a video extension."""
|
||||
return ext.lower() in VIDEO_EXTENSIONS
|
||||
|
||||
|
||||
def is_media(ext: str) -> bool:
|
||||
"""Return True when *ext* is any supported image/audio/video extension."""
|
||||
return ext.lower() in MEDIA_EXTENSIONS
|
||||
|
||||
|
||||
def media_mime_type(path: str) -> str:
|
||||
"""Return the best MIME type for *path* (extension based).
|
||||
|
||||
Falls back to ``application/octet-stream`` when the type is unknown.
|
||||
"""
|
||||
lower = path.lower()
|
||||
for ext, mime in _MIME_OVERRIDES.items():
|
||||
if lower.endswith(ext):
|
||||
return mime
|
||||
guessed, _ = mimetypes.guess_type(path)
|
||||
return guessed or "application/octet-stream"
|
||||
Reference in New Issue
Block a user