add logic for EXIF timestamp not being consistent
This commit is contained in:
parent
25fcfdbb27
commit
827f057989
|
@ -1,21 +1,21 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
'''
|
"""
|
||||||
Import photos from SD card into folder with todays date + nickname
|
Import photos from SD card into folder with today's date + nickname
|
||||||
Use: importphotos (--jpg|--raw|--both) <nickname of folder (optional)>
|
Use: import_media.py (--jpg|--raw|--both) <nickname of folder (optional)>
|
||||||
Add script to path
|
Add script to path
|
||||||
|
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
8. Optinally allow specification of a backup location on another disk
|
8. Optionally allow specification of a backup location on another disk
|
||||||
or NAS to ship a 3rd copy to
|
or NAS to ship a 3rd copy to
|
||||||
10. Every config option has an arg override
|
10. Every config option has an arg override
|
||||||
11. Optionally rename file if EVENT name was passed in
|
11. Optionally rename file if EVENT name was passed in
|
||||||
-- STRETCH --
|
-- STRETCH --
|
||||||
12. Make a graphical interface
|
12. Make a graphical interface
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import argparse
|
import argparse
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -47,6 +47,8 @@ parser.add_argument("-b", "--backup-destination", help = "Create a backup of e
|
||||||
specified location")
|
specified location")
|
||||||
parser.add_argument("-D", "--delete-source-files", help = "Delete files from SD after validating \
|
parser.add_argument("-D", "--delete-source-files", help = "Delete files from SD after validating \
|
||||||
checksum of copied files")
|
checksum of copied files")
|
||||||
|
parser.add_argument("-v", "--verify", help = "[True|False] Verify the checksum of \
|
||||||
|
the copied file")
|
||||||
parser.add_argument("-c", "--config", help = "Load the specified config file instead \
|
parser.add_argument("-c", "--config", help = "Load the specified config file instead \
|
||||||
of the default " + CONFIG_FILE)
|
of the default " + CONFIG_FILE)
|
||||||
parser.add_argument("-g", "--generate-config", help = "Generate config file based on options \
|
parser.add_argument("-g", "--generate-config", help = "Generate config file based on options \
|
||||||
|
@ -62,7 +64,7 @@ if args.source:
|
||||||
config['folders']['source']['base'] = args.source
|
config['folders']['source']['base'] = args.source
|
||||||
if args.destination:
|
if args.destination:
|
||||||
config['folders']['destination']['base'] = args.source
|
config['folders']['destination']['base'] = args.source
|
||||||
#if args.create-oringinals:
|
#if args.create-originals:
|
||||||
# pass
|
# pass
|
||||||
#if args.backup-destination:
|
#if args.backup-destination:
|
||||||
# pass
|
# pass
|
||||||
|
@ -80,10 +82,13 @@ def dump_yaml(dictionary, file):
|
||||||
|
|
||||||
def md5_hash(file):
|
def md5_hash(file):
|
||||||
""" calculates and returns md5 hash """
|
""" calculates and returns md5 hash """
|
||||||
#print("calculating md5 for ", f)
|
if config['verify_checksum']:
|
||||||
md5 = hashlib.md5(open(file, 'rb').read()).hexdigest()
|
#print("calculating md5 for ", f)
|
||||||
#with open(file, 'r') as f:
|
md5 = hashlib.md5(open(file, 'rb').read()).hexdigest()
|
||||||
# md5 = hashlib.md5(f).hexdigest()
|
#with open(file, 'r') as f:
|
||||||
|
# md5 = hashlib.md5(f).hexdigest()
|
||||||
|
else:
|
||||||
|
md5 = 'no_verify'
|
||||||
return md5
|
return md5
|
||||||
|
|
||||||
def cmp_files(file_1,file_2):
|
def cmp_files(file_1,file_2):
|
||||||
|
@ -93,19 +98,45 @@ def cmp_files(file_1,file_2):
|
||||||
def get_capture_date(path, f_type):
|
def get_capture_date(path, f_type):
|
||||||
""" get capture date from meta """
|
""" get capture date from meta """
|
||||||
if f_type == 'image':
|
if f_type == 'image':
|
||||||
with open(path, 'rb') as file:
|
with open(path, "rb") as file:
|
||||||
tags = exifread.process_file(file)
|
tags = exifread.process_file(file)
|
||||||
|
|
||||||
if 'EXIF DateTimeOriginal' in tags:
|
if 'EXIF DateTimeOriginal' in tags:
|
||||||
stamp = datetime.strptime(str(tags['EXIF DateTimeOriginal']), '%Y:%m:%d %H:%M:%S')
|
try:
|
||||||
|
stamp = datetime.strptime(
|
||||||
|
str(tags['EXIF DateTimeOriginal']),
|
||||||
|
'%Y:%m:%d %H:%M:%S')
|
||||||
|
except ValueError as ve_dte:
|
||||||
|
print(f"\nError: {ve_dte}")
|
||||||
|
print("\nTrying digitized")
|
||||||
|
try:
|
||||||
|
stamp = datetime.strptime(
|
||||||
|
str(tags['EXIF DateTimeDigitized']),
|
||||||
|
'%Y:%m:%d %H:%M:%S')
|
||||||
|
except ValueError as ve_dtd:
|
||||||
|
print(f"\nError: {ve_dtd}")
|
||||||
|
print("\nTrying Image DateTime")
|
||||||
|
try:
|
||||||
|
stamp = datetime.strptime(
|
||||||
|
str(tags['Image DateTime']),
|
||||||
|
'%Y:%m:%d %H:%M:%S')
|
||||||
|
except ValueError as ve_idt:
|
||||||
|
print(f"\nError: {ve_idt}")
|
||||||
|
print(f"\nGiving up... Please inspect {path} and try again\n")
|
||||||
|
sys.exit()
|
||||||
elif 'Image DateTime' in tags:
|
elif 'Image DateTime' in tags:
|
||||||
stamp = datetime.strptime(str(tags['Image DateTime']), '%Y:%m:%d %H:%M:%S')
|
stamp = datetime.strptime(
|
||||||
|
str(tags['Image DateTime']), '%Y:%m:%d %H:%M:%S')
|
||||||
else:
|
else:
|
||||||
stamp = datetime.strptime(str('1900:01:01 00:00:00'), '%Y:%m:%d %H:%M:%S')
|
stamp = datetime.strptime(
|
||||||
|
str('1900:01:01 00:00:00'), '%Y:%m:%d %H:%M:%S')
|
||||||
elif f_type == 'video':
|
elif f_type == 'video':
|
||||||
stamp = datetime.strptime(ffmpeg.probe(path)['format']['tags']['creation_time'],
|
stamp = datetime.strptime(
|
||||||
|
ffmpeg.probe(path)['format']['tags']['creation_time'],
|
||||||
'%Y-%m-%dT%H:%M:%S.%f%z')
|
'%Y-%m-%dT%H:%M:%S.%f%z')
|
||||||
elif f_type == 'audio':
|
elif f_type == 'audio':
|
||||||
stamp = datetime.strptime(ffmpeg.probe(path)['format']['tags']['date'], '%Y-%m-%d')
|
stamp = datetime.strptime(
|
||||||
|
ffmpeg.probe(path)['format']['tags']['date'], '%Y-%m-%d')
|
||||||
else:
|
else:
|
||||||
stamp = datetime.fromtimestamp(os.path.getctime(path))
|
stamp = datetime.fromtimestamp(os.path.getctime(path))
|
||||||
|
|
||||||
|
@ -233,7 +264,7 @@ def process_file(path, f_type, f_name, ext):
|
||||||
files[i]['folders']['destination'] = files[i]['folders']['destination'] + '/AUDIO'
|
files[i]['folders']['destination'] = files[i]['folders']['destination'] + '/AUDIO'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print('WARN: ', files[i]['type'], \
|
print('WARN: ', files[i]['type'],
|
||||||
' is not a known type and you never should have landed here.')
|
' is not a known type and you never should have landed here.')
|
||||||
|
|
||||||
def find_files(directory):
|
def find_files(directory):
|
||||||
|
@ -243,11 +274,11 @@ def find_files(directory):
|
||||||
for ext in config['file_types'][f_type]:
|
for ext in config['file_types'][f_type]:
|
||||||
for file in tqdm(filename, desc = 'Finding ' + ext + ' Files', ncols = 100):
|
for file in tqdm(filename, desc = 'Finding ' + ext + ' Files', ncols = 100):
|
||||||
if file.lower().endswith(ext):
|
if file.lower().endswith(ext):
|
||||||
print(file)
|
# print(file)
|
||||||
process_file(folder, f_type, file, ext)
|
process_file(folder, f_type, file, ext)
|
||||||
|
|
||||||
def validate_config_dir_access():
|
def validate_config_dir_access():
|
||||||
""" Validate we can op in the defined directories """
|
""" Validate we can operate in the defined directories """
|
||||||
check = path_access_write(config['folders']['destination']['base'])
|
check = path_access_write(config['folders']['destination']['base'])
|
||||||
if check is False:
|
if check is False:
|
||||||
writable = False
|
writable = False
|
||||||
|
@ -300,19 +331,19 @@ def validate_checksums():
|
||||||
for checksum in files[file]['md5_checksums']:
|
for checksum in files[file]['md5_checksums']:
|
||||||
c[i] = files[file]['md5_checksums'][checksum]
|
c[i] = files[file]['md5_checksums'][checksum]
|
||||||
if i > 0:
|
if i > 0:
|
||||||
P = i - 1
|
p = i - 1
|
||||||
if c[i] == c[P]:
|
if c[i] == c[p]:
|
||||||
files[file]['source_cleanable'] = True
|
files[file]['source_cleanable'] = True
|
||||||
else:
|
else:
|
||||||
files[file]['source_cleanable'] = False
|
files[file]['source_cleanable'] = False
|
||||||
print(f'FATAL: Checksum validation failed for: \
|
print(f'FATAL: Checksum validation failed for: \
|
||||||
{files[file]["name"]} \n{c[i]}\n is not equal to \n{c[P]}\n')
|
{files[file]["name"]} \n{c[i]}\n is not equal to \n{c[p]}\n')
|
||||||
print('\n File Meta:\n')
|
print('\n File Meta:\n')
|
||||||
pprint(files[file])
|
pprint(files[file])
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
def cleanup_sd():
|
def cleanup_sd():
|
||||||
""" If we should cleanup the SD, nuke the copied files. """
|
""" If we should clean up the SD, nuke the copied files. """
|
||||||
if config['cleanup_sd'] is True:
|
if config['cleanup_sd'] is True:
|
||||||
for file in tqdm(files, desc = "Cleaning Up SD:", ncols = 100):
|
for file in tqdm(files, desc = "Cleaning Up SD:", ncols = 100):
|
||||||
if files[file]['source_cleanable'] is True:
|
if files[file]['source_cleanable'] is True:
|
||||||
|
|
Loading…
Reference in New Issue