From 47349e68cd93bc890bdb658005029c2eee8e71ff Mon Sep 17 00:00:00 2001 From: Jeena Date: Mon, 11 Aug 2025 22:41:08 +0900 Subject: [PATCH] Fix so it's possible to get multiple reports per day Also translate comments to english --- report_json_down.py | 211 ++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 114 deletions(-) diff --git a/report_json_down.py b/report_json_down.py index 98922e0..8026a45 100755 --- a/report_json_down.py +++ b/report_json_down.py @@ -1,147 +1,130 @@ #!/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 requests -from PIL import Image -from PIL.ExifTags import TAGS, GPSTAGS +import sys +import json import datetime +import requests +from pathlib import Path +from PIL import Image import piexif -from xml.etree import ElementTree as ET from dotenv import load_dotenv load_dotenv() STORAGE_PATH = os.getenv("KIDSNOTE_STORAGE_PATH") - if not STORAGE_PATH: print("Error: KIDSNOTE_STORAGE_PATH is not set.") sys.exit(1) def convert_to_degrees(value): - """Convert decimal coordinate to degrees, minutes, and seconds tuple.""" degrees = int(value) minutes = int((value - degrees) * 60) seconds = (value - degrees - minutes / 60) * 3600 - seconds_numerator = int(seconds * 100) - seconds_denominator = 100 + return ((degrees, 1), (minutes, 1), (int(seconds * 100), 100)) - return ((degrees, 1), (minutes, 1), (seconds_numerator, seconds_denominator)) +def add_exif_data(image_path, title, content, location_str=None): + try: + img = Image.open(image_path) + if 'exif' in img.info: + exif_dict = piexif.load(img.info['exif']) + else: + exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "1st": {}, "thumbnail": None} -def add_exif_data(image_path, title, content, location): - # Load the image - img = Image.open(image_path) + if location_str: + try: + latitude, longitude = map(float, location_str.split(',')) + 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.GPSLatitude] = convert_to_degrees(abs(latitude)) + exif_dict['GPS'][piexif.GPSIFD.GPSLongitude] = convert_to_degrees(abs(longitude)) + except Exception as e: + print(f"Invalid location format '{location_str}': {e}") - # Check if the image has 'exif' data - if 'exif' in img.info: - exif_dict = piexif.load(img.info['exif']) - else: - exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "1st": {}, "thumbnail": None} + comment = f"Title: {title}\nContent: {content}" + encoded_comment = b'ASCII\x00\x00\x00' + comment.encode('utf-8') + exif_dict['Exif'][piexif.ExifIFD.UserComment] = encoded_comment + exif_bytes = piexif.dump(exif_dict) + img.save(image_path, exif=exif_bytes) + img.close() + except Exception as e: + print(f"EXIF error for {image_path}: {e}") - # GPS coordinates - latitude, longitude = map(float, location.split(',')) - 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.GPSLatitude] = convert_to_degrees(abs(latitude)) - exif_dict['GPS'][piexif.GPSIFD.GPSLongitude] = convert_to_degrees(abs(longitude)) +def get_creation_datetime(image_path): + try: + 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 - # User comment - user_comment = f"Title: {title}\nContent: {content}" - encoded_comment = user_comment.encode('utf-8') - exif_dict['0th'][piexif.ImageIFD.ImageDescription] = encoded_comment - - # Convert EXIF data to bytes and save the image - exif_bytes = piexif.dump(exif_dict) - img.save(image_path, exif=exif_bytes) - - # Close the image - img.close() - -def create_xmp_data(title, content, location): - xmp_template = f""" - - - {title} - {content} - {location} - - - """ - return xmp_template - -def add_xmp_data(image_path, title, content, location): - # Open the image - img = Image.open(image_path) - - 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: data = json.load(file) -# 앨범 처리 +# Group reports by date +reports_by_date = {} for report in data['results']: - # 폴더 생성 - date = datetime.datetime.strptime(report['created'], "%Y-%m-%dT%H:%M:%S.%fZ") - 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) + date = datetime.datetime.strptime(report['created'], "%Y-%m-%dT%H:%M:%S.%fZ").date() + reports_by_date.setdefault(date, []).append(report) - # 앨범 설명 저장 - description_path = os.path.join(folder_name, "report-description.txt") - if os.path.exists(description_path): - print (f"'{date_str}' exists"); - 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") +for date, reports in sorted(reports_by_date.items()): + folder = Path(STORAGE_PATH).expanduser() / f"{date.year:04d}" / f"{date.month:02d}" / f"{date.day:02d}" + folder.mkdir(parents=True, exist_ok=True) - # 비디오 처리 - if report['attached_video']: - video_url = report['attached_video'] - video_response = requests.get(video_url) - video_path = os.path.join(folder_name, f"V_{report['id']}.MP4") - with open(video_path, "wb") as file: - file.write(video_response.content) + 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 - # 이미지 처리 - 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: - # EXIF 데이터 추가 - add_exif_data(image_path, report['child_name'], report['content'], "55.55555, 555.5555") - # XMP 데이터 추가 - #add_xmp_data(image_path, report['child_name'], report['content'], "55.5555, 555.555555") - except: - print(f"'{folder_name}' : exif error") - print(f"Report '{folder_name}' processed.") + with open(desc_path, "w", encoding='utf-8') as f: + f.write(f"Title: {report['class_name']}-{report['child_name']}\n") + f.write(f"Weather: {report['weather']}\n") + f.write(f"Content: {report['content']}\n") + + if report.get('attached_video'): + try: + r = requests.get(report['attached_video']) + r.raise_for_status() + with open(folder / f"V_{report_index}.MP4", "wb") as f: + f.write(r.content) + except requests.RequestException as e: + print(f"Video download failed: {e}") + + 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.") +