photomk/extract-metadata.py
2025-02-15 02:29:41 +01:00

80 lines
1.9 KiB
Python
Executable File

#!/usr/bin/env python3
import clize
import exif
import json
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Any
def exif_content_to_json(tag, content):
match content:
case Enum() as e:
return e.name
case int() as i:
return i
case float() as f:
return f
case str() as s:
if tag.startswith("datetime"):
dt = datetime.strptime(s, "%Y:%m:%d %H:%M:%S")
return dt.strftime("%Y-%m-%d %H:%M")
return s
case _:
return {"pyType": str(type(content)), "stringified": str(content)}
def extract_exif_data(image_path: Path) -> dict[str, Any]:
with image_path.open("rb") as image_file:
image = exif.Image(image_file)
exif_data = {}
for tag in image.list_all():
try:
content = image[tag]
except:
# Some keys are in list_all() but can't be accessed for my camera :(
# Skip them.
continue
exif_data[tag] = exif_content_to_json(tag, content)
return exif_data
def extract_stat_data(image_path: Path):
FIELDS = ["st_size"]
s = image_path.stat()
stat_data = {}
for field in FIELDS:
stat_data[field] = getattr(s, field)
return stat_data
def extract_metadata(image_path: Path, *, root: Path, dist_path: Path, key: str):
exif_data = extract_exif_data(image_path)
stat_data = extract_stat_data(image_path)
metadata = {
"exif": exif_data,
"stat": stat_data,
"path": {
"name": image_path.name,
"relativeToRoot": str(image_path.relative_to(root)),
"distRelativeToRoot": str(dist_path.relative_to(root)),
},
"key": key,
}
print(json.dumps(metadata, indent=2))
if __name__ == "__main__":
clize.run(extract_metadata)