Compare commits
2 Commits
a321458f59
...
af8c3edc96
| Author | SHA1 | Date | |
|---|---|---|---|
| af8c3edc96 | |||
| 54a83cead5 |
@ -5,40 +5,39 @@ import pandas as pd
|
||||
|
||||
file_directory = Path("../downloads")
|
||||
files_to_check = [
|
||||
p for p in file_directory.iterdir()
|
||||
p
|
||||
for p in file_directory.iterdir()
|
||||
if p.is_file() and p.suffix.lower() in [".jpg", ".mp4"]
|
||||
]
|
||||
|
||||
file_df = pd.DataFrame(data=files_to_check, columns=["file"])
|
||||
|
||||
|
||||
def get_metadata(row: pd.Series) -> pd.Series:
|
||||
|
||||
|
||||
file_path = row["file"]
|
||||
command = [
|
||||
"exiftool",
|
||||
"-T",
|
||||
"-T",
|
||||
"-createdate",
|
||||
"-gpslatitude",
|
||||
"-gpslongitude",
|
||||
# *tags_to_check,
|
||||
str(file_path)
|
||||
# *tags_to_check,
|
||||
str(file_path),
|
||||
]
|
||||
result = subprocess.run(
|
||||
command,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
timeout=30
|
||||
command, capture_output=True, text=True, check=False, timeout=30
|
||||
)
|
||||
metadata = result.stdout.strip().split('\n')[0].split('\t')
|
||||
|
||||
metadata = result.stdout.strip().split("\n")[0].split("\t")
|
||||
|
||||
if len(metadata) < 3:
|
||||
metadata = metadata + ['-'] * (3 - len(metadata))
|
||||
metadata = metadata + ["-"] * (3 - len(metadata))
|
||||
row["createdate"] = metadata[0]
|
||||
row["gpslatitude"] = metadata[1]
|
||||
row["gpslongitude"] = metadata[2]
|
||||
return row
|
||||
|
||||
|
||||
df = file_df.apply(get_metadata, axis=1)
|
||||
|
||||
|
||||
|
||||
114
main.py
114
main.py
@ -70,7 +70,7 @@ def add_exif_data(image_path: Path, memory: Memory):
|
||||
|
||||
utc = pytz.utc
|
||||
# Use the 'America/Chicago' zone which handles both CST (-6) and CDT (-5) automatically
|
||||
central_timezone = pytz.timezone('America/Chicago')
|
||||
central_timezone = pytz.timezone("America/Chicago")
|
||||
utc_dt = memory.date.replace(tzinfo=utc)
|
||||
local_dt = utc_dt.astimezone(central_timezone)
|
||||
dt_str = local_dt.strftime("%Y:%m:%d %H:%M:%S")
|
||||
@ -87,10 +87,10 @@ def add_exif_data(image_path: Path, memory: Memory):
|
||||
minutes = int(minutes_decimal)
|
||||
seconds = (minutes_decimal - minutes) * 60
|
||||
return (degrees, minutes, seconds)
|
||||
|
||||
|
||||
lat_dms = decimal_to_dms(memory.latitude)
|
||||
lon_dms = decimal_to_dms(memory.longitude)
|
||||
|
||||
|
||||
img.gps_latitude = lat_dms
|
||||
img.gps_latitude_ref = "N" if memory.latitude >= 0 else "S"
|
||||
img.gps_longitude = lon_dms
|
||||
@ -103,108 +103,23 @@ def add_exif_data(image_path: Path, memory: Memory):
|
||||
|
||||
|
||||
def add_metadata_mp4(video_path: Path, memory: Memory):
|
||||
"""
|
||||
Adds metadata (Date and GPS) to MP4 files by calling ExifTool
|
||||
via the subprocess module.
|
||||
"""
|
||||
try:
|
||||
dt_str = memory.date.strftime("%Y:%m:%d %H:%M:%S")
|
||||
dt_str = memory.date.strftime("%Y:%m:%d %H:%M:%S")
|
||||
|
||||
command = [
|
||||
"exiftool",
|
||||
"-P", # Preserve file modification date
|
||||
"-P", # Preserve file modification date
|
||||
"-overwrite_original",
|
||||
"-m", # Allow minor warnings
|
||||
|
||||
"-m", # Allow minor warnings
|
||||
# QuickTime Date/Time tags
|
||||
f"-QuickTime:DateTimeOriginal={dt_str}",
|
||||
f"-QuickTime:CreateDate={dt_str}",
|
||||
f"-QuickTime:ModifyDate={dt_str}",
|
||||
|
||||
f"-QuickTime:CreateDate={dt_str}",
|
||||
f"-QuickTime:ModifyDate={dt_str}",
|
||||
# QuickTime TimeZone is often required for the date to be recognized
|
||||
f"-QuickTime:TimeZone=+00:00",
|
||||
|
||||
# # Final path argument
|
||||
# str(video_path)
|
||||
]
|
||||
# dt_str = memory.date.strftime("%Y:%m:%d %H:%M:%S")
|
||||
# dt_str_utc = memory.date.strftime("%Y:%m:%d %H:%M:%S-06:00") # ISO format with UTC offset
|
||||
# tz = "-06:00" # Central Time Zone offset
|
||||
|
||||
# # 1. Start with the base command, including date tags (ALWAYS written)
|
||||
# command = [
|
||||
# "exiftool",
|
||||
# "-overwrite_original",
|
||||
# ]
|
||||
|
||||
# # 2. Conditionally add GPS tags to the command list
|
||||
# if memory.latitude is not None and memory.longitude is not None:
|
||||
# lat = memory.latitude
|
||||
# lon = memory.longitude
|
||||
|
||||
# coord_str = f"{lat} {lon}"
|
||||
|
||||
# command.extend([
|
||||
# # Use the standard GPS tags instead of the specific QuickTime ones
|
||||
# f"-Keys:GPSCoordinates={coord_str}",
|
||||
# # Keep DateTimeOriginal and TimeZone, but ensure you also use the correct TimeZone tag
|
||||
# f"-QuickTime:DateTimeOriginal={dt_str}",
|
||||
# f"-QuickTime:TimeZone={tz}",
|
||||
# ])
|
||||
|
||||
# # command.extend([
|
||||
# # # Generic Composite Tag (Tries to create necessary atoms)
|
||||
# # f"-GPSCoordinates={coord_str}",
|
||||
|
||||
# # # EXIF
|
||||
# # f"-EXIF:GPSLatitude={lat}",
|
||||
# # f"-EXIF:GPSLongitude={lon}",
|
||||
# # f"-EXIF:GPSLatitudeRef={'N' if lat >= 0 else 'S'}",
|
||||
# # f"-EXIF:GPSLongitudeRef={'E' if lon >= 0 else 'W'}",
|
||||
|
||||
# # # Highly prioritized XMP Tag (Often read first by Adobe/Google)
|
||||
# # f"-XMP:GPSLatitude={lat}",
|
||||
# # f"-XMP:GPSLongitude={lon}",
|
||||
|
||||
# # # QuickTime Location tags (Apple/iOS compatibility)
|
||||
# # f"-QuickTime:LocationLatitude={lat}",
|
||||
# # f"-QuickTime:LocationLongitude={lon}",
|
||||
|
||||
# # # # Generic GPS tags (For broad compatibility)
|
||||
# # # f"-GPSLatitude={lat}",
|
||||
# # # f"-GPSLongitude={lon}",
|
||||
# # # f"-GPSLatitudeRef={'N' if lat >= 0 else 'S'}",
|
||||
# # # f"-GPSLongitudeRef={'E' if lon >= 0 else 'W'}",
|
||||
# # ])
|
||||
|
||||
# # command.extend([
|
||||
# # # Generic Composite Tag (Tries to create necessary atoms)
|
||||
# # # f"-GPSCoordinates={coord_str}",
|
||||
|
||||
# # # EXIF
|
||||
# # f"-exif:gpslatitude={lat}",
|
||||
# # f"-exif:gpslongitude={lon}",
|
||||
# # # f"-gpslatituderef={'N' if lat >= 0 else 'S'}",
|
||||
# # # f"-gpslongituderef={'E' if lon >= 0 else 'W'}",
|
||||
|
||||
# # # Highly prioritized XMP Tag (Often read first by Adobe/Google)
|
||||
# # f"-xmp:gpslatitude={lat}",
|
||||
# # f"-xmp:gpslongitude={lon}",
|
||||
|
||||
# # f"-gpslatituderef={'N' if lat >= 0 else 'S'}",
|
||||
# # f"-gpslongituderef={'E' if lon >= 0 else 'W'}",
|
||||
|
||||
# # # QuickTime Location tags (Apple/iOS compatibility)
|
||||
# # f"-QuickTime:LocationLatitude={lat}",
|
||||
# # f"-QuickTime:LocationLongitude={lon}",
|
||||
|
||||
# # # # Generic GPS tags (For broad compatibility)
|
||||
# # # f"-GPSLatitude={lat}",
|
||||
# # # f"-GPSLongitude={lon}",
|
||||
# # # f"-GPSLatitudeRef={'N' if lat >= 0 else 'S'}",
|
||||
# # # f"-GPSLongitudeRef={'E' if lon >= 0 else 'W'}",
|
||||
# # ])
|
||||
# # command.extend(["-overwrite_original"])
|
||||
|
||||
# # 3. Add the target file path at the end
|
||||
command.append(str(video_path))
|
||||
@ -212,25 +127,26 @@ def add_metadata_mp4(video_path: Path, memory: Memory):
|
||||
# 4. Execute the command
|
||||
# We use check=True to raise an error if ExifTool fails.
|
||||
subprocess.run(
|
||||
command,
|
||||
command,
|
||||
check=True,
|
||||
capture_output=True, # Captures stdout/stderr
|
||||
text=True
|
||||
capture_output=True, # Captures stdout/stderr
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Handle cases where ExifTool runs but returns an error (e.g., file corrupted)
|
||||
print(f"\nError: ExifTool failed for {video_path.name}: {e.stderr.strip()}")
|
||||
except FileNotFoundError:
|
||||
# Handle case where the 'exiftool' executable cannot be found
|
||||
print("\nError: ExifTool not found. Please install ExifTool and ensure it's in your system PATH.")
|
||||
print(
|
||||
"\nError: ExifTool not found. Please install ExifTool and ensure it's in your system PATH."
|
||||
)
|
||||
except Exception as e:
|
||||
# Catch all other exceptions
|
||||
print(f"\nWarning: Failed to add metadata to {video_path.name}: {e}")
|
||||
pass
|
||||
|
||||
|
||||
|
||||
async def download_memory(
|
||||
memory: Memory, output_dir: Path, add_exif: bool, semaphore: asyncio.Semaphore
|
||||
) -> tuple[bool, int]:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,8 @@
|
||||
"file_directory = Path(\"../downloads\")\n",
|
||||
"\n",
|
||||
"files_to_check = [\n",
|
||||
" p for p in file_directory.iterdir() \n",
|
||||
" p\n",
|
||||
" for p in file_directory.iterdir()\n",
|
||||
" if p.is_file() and p.suffix.lower() in [\".jpg\", \".mp4\"]\n",
|
||||
"]"
|
||||
]
|
||||
@ -138,28 +139,24 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_metadata(row: pd.Series) -> pd.Series:\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" file_path = row[\"file\"]\n",
|
||||
" command = [\n",
|
||||
" \"exiftool\",\n",
|
||||
" \"-T\", \n",
|
||||
" \"-T\",\n",
|
||||
" \"-createdate\",\n",
|
||||
" \"-gpslatitude\",\n",
|
||||
" \"-gpslongitude\",\n",
|
||||
" # *tags_to_check, \n",
|
||||
" str(file_path)\n",
|
||||
" # *tags_to_check,\n",
|
||||
" str(file_path),\n",
|
||||
" ]\n",
|
||||
" result = subprocess.run(\n",
|
||||
" command,\n",
|
||||
" capture_output=True,\n",
|
||||
" text=True,\n",
|
||||
" check=False,\n",
|
||||
" timeout=30\n",
|
||||
" command, capture_output=True, text=True, check=False, timeout=30\n",
|
||||
" )\n",
|
||||
" metadata = result.stdout.strip().split('\\n')[0].split('\\t')\n",
|
||||
" \n",
|
||||
" metadata = result.stdout.strip().split(\"\\n\")[0].split(\"\\t\")\n",
|
||||
"\n",
|
||||
" if len(metadata) < 3:\n",
|
||||
" metadata = metadata + ['-'] * (3 - len(metadata))\n",
|
||||
" metadata = metadata + [\"-\"] * (3 - len(metadata))\n",
|
||||
" row[\"createdate\"] = metadata[0]\n",
|
||||
" row[\"gpslatitude\"] = metadata[1]\n",
|
||||
" row[\"gpslongitude\"] = metadata[2]\n",
|
||||
|
||||
@ -8,4 +8,6 @@ timezonefinder
|
||||
|
||||
# For development
|
||||
jupyter
|
||||
pandas
|
||||
pandas
|
||||
black
|
||||
black[jupyter]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user