Marwan
Restructure + add reverse face search (PimEyes-style)
f5eeb1c
Raw
History Blame Contribute Delete
2.19 kB
"""
EXIF metadata provider.
Delegates all parsing to cores.metadata.extractor — no duplicated
Pillow open / EXIF tag walk / GPS conversion logic.
"""
from __future__ import annotations
from config.settings import Settings, settings as _default_settings
from cores.metadata import extract_all
from pipeline.feature_extraction import PipelineOutput
from providers.base import BaseProvider, ProviderCapability
class EXIFProvider(BaseProvider):
name = "exif"
capability = ProviderCapability.METADATA
def __init__(self, settings: Settings | None = None) -> None:
super().__init__(settings=settings or _default_settings)
def is_available(self) -> bool:
try:
import PIL # noqa: F401
return True
except ImportError:
return False
def _run(self, pipeline_output: PipelineOutput) -> tuple[dict, dict]:
original = pipeline_output.original_bytes
if not original:
raw = {"error": "No original bytes available for EXIF extraction"}
normalized = {
"format": pipeline_output.original_format,
"exif": {}, "xmp": {}, "iptc": {},
}
return raw, normalized
data = extract_all(original)
raw = {
"format": data["format"],
"exif_tags_count": len(data["exif"]),
"gps_tags_count": len(data["gps"]),
"exif": data["exif"],
"gps": data["gps"],
"camera_make": data["camera_make"],
"camera_model": data["camera_model"],
"software": data["software"],
"capture_time": data["capture_time"],
"error": data["error"],
}
normalized = {
"format": data["format"],
"exif": data["exif"],
"xmp": {} if not data["xmp"] else {"raw_length": len(data["xmp"])},
"iptc": data["iptc"],
"gps": data["gps_coords"],
"camera_make": data["camera_make"],
"camera_model": data["camera_model"],
"software": data["software"],
"capture_time": data["capture_time"],
}
return raw, normalized