Fix so it's possible to get multiple reports per day
Also translate comments to english
This commit is contained in:
parent
76676839f0
commit
47349e68cd
1 changed files with 97 additions and 114 deletions
|
@ -1,147 +1,130 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
#thanks to goodhobak from https://www.clien.net/
|
|
||||||
#requre: requests Pillow piexif
|
|
||||||
#use:
|
|
||||||
#1. get json from api in webpage
|
|
||||||
#2. save json
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
import os
|
import os
|
||||||
import requests
|
import sys
|
||||||
from PIL import Image
|
import json
|
||||||
from PIL.ExifTags import TAGS, GPSTAGS
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import requests
|
||||||
|
from pathlib import Path
|
||||||
|
from PIL import Image
|
||||||
import piexif
|
import piexif
|
||||||
from xml.etree import ElementTree as ET
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
STORAGE_PATH = os.getenv("KIDSNOTE_STORAGE_PATH")
|
STORAGE_PATH = os.getenv("KIDSNOTE_STORAGE_PATH")
|
||||||
|
|
||||||
if not STORAGE_PATH:
|
if not STORAGE_PATH:
|
||||||
print("Error: KIDSNOTE_STORAGE_PATH is not set.")
|
print("Error: KIDSNOTE_STORAGE_PATH is not set.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def convert_to_degrees(value):
|
def convert_to_degrees(value):
|
||||||
"""Convert decimal coordinate to degrees, minutes, and seconds tuple."""
|
|
||||||
degrees = int(value)
|
degrees = int(value)
|
||||||
minutes = int((value - degrees) * 60)
|
minutes = int((value - degrees) * 60)
|
||||||
seconds = (value - degrees - minutes / 60) * 3600
|
seconds = (value - degrees - minutes / 60) * 3600
|
||||||
seconds_numerator = int(seconds * 100)
|
return ((degrees, 1), (minutes, 1), (int(seconds * 100), 100))
|
||||||
seconds_denominator = 100
|
|
||||||
|
|
||||||
return ((degrees, 1), (minutes, 1), (seconds_numerator, seconds_denominator))
|
def add_exif_data(image_path, title, content, location_str=None):
|
||||||
|
try:
|
||||||
def add_exif_data(image_path, title, content, location):
|
|
||||||
# Load the image
|
|
||||||
img = Image.open(image_path)
|
img = Image.open(image_path)
|
||||||
|
|
||||||
# Check if the image has 'exif' data
|
|
||||||
if 'exif' in img.info:
|
if 'exif' in img.info:
|
||||||
exif_dict = piexif.load(img.info['exif'])
|
exif_dict = piexif.load(img.info['exif'])
|
||||||
else:
|
else:
|
||||||
exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "1st": {}, "thumbnail": None}
|
exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "1st": {}, "thumbnail": None}
|
||||||
|
|
||||||
|
if location_str:
|
||||||
# GPS coordinates
|
try:
|
||||||
latitude, longitude = map(float, location.split(','))
|
latitude, longitude = map(float, location_str.split(','))
|
||||||
exif_dict['GPS'][piexif.GPSIFD.GPSLatitudeRef] = 'N' if latitude >= 0 else 'S'
|
exif_dict['GPS'][piexif.GPSIFD.GPSLatitudeRef] = 'N' if latitude >= 0 else 'S'
|
||||||
exif_dict['GPS'][piexif.GPSIFD.GPSLongitudeRef] = 'E' if longitude >= 0 else 'W'
|
exif_dict['GPS'][piexif.GPSIFD.GPSLongitudeRef] = 'E' if longitude >= 0 else 'W'
|
||||||
exif_dict['GPS'][piexif.GPSIFD.GPSLatitude] = convert_to_degrees(abs(latitude))
|
exif_dict['GPS'][piexif.GPSIFD.GPSLatitude] = convert_to_degrees(abs(latitude))
|
||||||
exif_dict['GPS'][piexif.GPSIFD.GPSLongitude] = convert_to_degrees(abs(longitude))
|
exif_dict['GPS'][piexif.GPSIFD.GPSLongitude] = convert_to_degrees(abs(longitude))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Invalid location format '{location_str}': {e}")
|
||||||
|
|
||||||
# User comment
|
comment = f"Title: {title}\nContent: {content}"
|
||||||
user_comment = f"Title: {title}\nContent: {content}"
|
encoded_comment = b'ASCII\x00\x00\x00' + comment.encode('utf-8')
|
||||||
encoded_comment = user_comment.encode('utf-8')
|
exif_dict['Exif'][piexif.ExifIFD.UserComment] = encoded_comment
|
||||||
exif_dict['0th'][piexif.ImageIFD.ImageDescription] = encoded_comment
|
|
||||||
|
|
||||||
# Convert EXIF data to bytes and save the image
|
|
||||||
exif_bytes = piexif.dump(exif_dict)
|
exif_bytes = piexif.dump(exif_dict)
|
||||||
img.save(image_path, exif=exif_bytes)
|
img.save(image_path, exif=exif_bytes)
|
||||||
|
|
||||||
# Close the image
|
|
||||||
img.close()
|
img.close()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"EXIF error for {image_path}: {e}")
|
||||||
|
|
||||||
def create_xmp_data(title, content, location):
|
def get_creation_datetime(image_path):
|
||||||
xmp_template = f"""
|
try:
|
||||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
|
||||||
<rdf:Description rdf:about=""
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
||||||
<dc:title>{title}</dc:title>
|
|
||||||
<dc:description>{content}</dc:description>
|
|
||||||
<dc:location>{location}</dc:location>
|
|
||||||
</rdf:Description>
|
|
||||||
</rdf:RDF>
|
|
||||||
"""
|
|
||||||
return xmp_template
|
|
||||||
|
|
||||||
def add_xmp_data(image_path, title, content, location):
|
|
||||||
# Open the image
|
|
||||||
img = Image.open(image_path)
|
img = Image.open(image_path)
|
||||||
|
exif_bytes = img.info.get('exif')
|
||||||
|
if not exif_bytes:
|
||||||
|
return None
|
||||||
|
exif_dict = piexif.load(exif_bytes)
|
||||||
|
dt_bytes = exif_dict['Exif'].get(piexif.ExifIFD.DateTimeOriginal)
|
||||||
|
if not dt_bytes:
|
||||||
|
return None
|
||||||
|
dt_str = dt_bytes.decode('utf-8') # e.g. "2025:07:12 14:32:45"
|
||||||
|
dt = datetime.datetime.strptime(dt_str, "%Y:%m:%d %H:%M:%S")
|
||||||
|
return dt
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
xmp_data = create_xmp_data(title, content, location)
|
|
||||||
xmp_bytes = xmp_data.encode('utf-8')
|
|
||||||
|
|
||||||
# Check if the image has existing metadata and append XMP data
|
|
||||||
if "APP1" in img.info:
|
|
||||||
existing_metadata = img.info["APP1"]
|
|
||||||
new_metadata = existing_metadata + b'\n' + xmp_bytes
|
|
||||||
else:
|
|
||||||
new_metadata = xmp_bytes
|
|
||||||
|
|
||||||
|
|
||||||
# Save the image with new metadata
|
|
||||||
img.save(image_path, "jpeg", exif=new_metadata)
|
|
||||||
|
|
||||||
# Close the image
|
|
||||||
img.close()
|
|
||||||
|
|
||||||
# 파일 읽기
|
|
||||||
with open("report.json", "r", encoding='utf-8') as file:
|
with open("report.json", "r", encoding='utf-8') as file:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
|
|
||||||
# 앨범 처리
|
# Group reports by date
|
||||||
|
reports_by_date = {}
|
||||||
for report in data['results']:
|
for report in data['results']:
|
||||||
# 폴더 생성
|
date = datetime.datetime.strptime(report['created'], "%Y-%m-%dT%H:%M:%S.%fZ").date()
|
||||||
date = datetime.datetime.strptime(report['created'], "%Y-%m-%dT%H:%M:%S.%fZ")
|
reports_by_date.setdefault(date, []).append(report)
|
||||||
date_str = date.date()
|
|
||||||
folder_name = Path(STORAGE_PATH).expanduser() / f"{date.year:04d}" / f"{date.month:02d}" / f"{date.day:02d}"
|
|
||||||
folder_name.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
# 앨범 설명 저장
|
for date, reports in sorted(reports_by_date.items()):
|
||||||
description_path = os.path.join(folder_name, "report-description.txt")
|
folder = Path(STORAGE_PATH).expanduser() / f"{date.year:04d}" / f"{date.month:02d}" / f"{date.day:02d}"
|
||||||
if os.path.exists(description_path):
|
folder.mkdir(parents=True, exist_ok=True)
|
||||||
print (f"'{date_str}' exists");
|
|
||||||
|
for report_index, report in enumerate(reports, start=1):
|
||||||
|
desc_path = folder / f"report-{report_index}-description.txt"
|
||||||
|
if desc_path.exists():
|
||||||
|
print(f"'{desc_path.name}' exists")
|
||||||
continue
|
continue
|
||||||
with open(os.path.join(description_path), "w", encoding='utf-8') as file:
|
|
||||||
file.write(f"Title: {report['class_name']}-{report['child_name']}\n")
|
|
||||||
file.write(f"Weather: {report['weather']}\n")
|
|
||||||
file.write(f"Content: {report['content']}\n")
|
|
||||||
|
|
||||||
# 비디오 처리
|
with open(desc_path, "w", encoding='utf-8') as f:
|
||||||
if report['attached_video']:
|
f.write(f"Title: {report['class_name']}-{report['child_name']}\n")
|
||||||
video_url = report['attached_video']
|
f.write(f"Weather: {report['weather']}\n")
|
||||||
video_response = requests.get(video_url)
|
f.write(f"Content: {report['content']}\n")
|
||||||
video_path = os.path.join(folder_name, f"V_{report['id']}.MP4")
|
|
||||||
with open(video_path, "wb") as file:
|
|
||||||
file.write(video_response.content)
|
|
||||||
|
|
||||||
# 이미지 처리
|
if report.get('attached_video'):
|
||||||
for index, image in enumerate(report['attached_images'], start=1):
|
|
||||||
image_url = image['original']
|
|
||||||
image_response = requests.get(image_url)
|
|
||||||
image_path = os.path.join(folder_name, f"P_{date_str}-{index}.jpg")
|
|
||||||
with open(image_path, "wb") as file:
|
|
||||||
file.write(image_response.content)
|
|
||||||
try:
|
try:
|
||||||
# EXIF 데이터 추가
|
r = requests.get(report['attached_video'])
|
||||||
add_exif_data(image_path, report['child_name'], report['content'], "55.55555, 555.5555")
|
r.raise_for_status()
|
||||||
# XMP 데이터 추가
|
with open(folder / f"V_{report_index}.MP4", "wb") as f:
|
||||||
#add_xmp_data(image_path, report['child_name'], report['content'], "55.5555, 555.555555")
|
f.write(r.content)
|
||||||
except:
|
except requests.RequestException as e:
|
||||||
print(f"'{folder_name}' : exif error")
|
print(f"Video download failed: {e}")
|
||||||
print(f"Report '{folder_name}' processed.")
|
|
||||||
|
for img_index, image in enumerate(report.get('attached_images', []), start=1):
|
||||||
|
try:
|
||||||
|
r = requests.get(image['original'])
|
||||||
|
r.raise_for_status()
|
||||||
|
temp_path = folder / f"temp_{report_index}_{img_index}.jpg"
|
||||||
|
with open(temp_path, "wb") as f:
|
||||||
|
f.write(r.content)
|
||||||
|
|
||||||
|
add_exif_data(temp_path, report['child_name'], report['content'], report.get('location'))
|
||||||
|
|
||||||
|
dt = get_creation_datetime(temp_path)
|
||||||
|
if dt:
|
||||||
|
date_str = dt.strftime("%Y-%m-%d_%H-%M")
|
||||||
|
else:
|
||||||
|
date_str = date.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
final_name = f"P{report_index}_{date_str}.jpg"
|
||||||
|
final_path = folder / final_name
|
||||||
|
|
||||||
|
temp_path.rename(final_path)
|
||||||
|
|
||||||
|
except requests.RequestException as e:
|
||||||
|
print(f"Image download failed: {e}")
|
||||||
|
|
||||||
|
print(f"Report {report_index} (ID: {report['id']}) saved in '{folder}'")
|
||||||
|
|
||||||
print("All reports have been processed.")
|
print("All reports have been processed.")
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue