2015-10-07 10:48:01 +02:00
|
|
|
"""
|
|
|
|
Author: Jaisen Mathai <jaisen@jmathai.com>
|
|
|
|
Photo package that handles all photo operations
|
|
|
|
"""
|
|
|
|
|
|
|
|
# load modules
|
|
|
|
from sys import argv
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
import mimetypes
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import time
|
|
|
|
|
|
|
|
from elodie.media.media import Media
|
|
|
|
|
|
|
|
"""
|
|
|
|
Video class for general photo operations
|
|
|
|
"""
|
|
|
|
class Photo(Media):
|
|
|
|
# class / static variable accessible through get_valid_extensions()
|
2015-10-14 09:39:30 +02:00
|
|
|
__valid_extensions = ('jpg', 'jpeg', 'nef', 'dng')
|
2015-10-07 10:48:01 +02:00
|
|
|
|
|
|
|
"""
|
|
|
|
@param, source, string, The fully qualified path to the photo file
|
|
|
|
"""
|
|
|
|
def __init__(self, source=None):
|
|
|
|
super(Photo, self).__init__(source)
|
|
|
|
|
|
|
|
# We only want to parse EXIF once so we store it here
|
|
|
|
self.exif = None
|
|
|
|
|
|
|
|
"""
|
|
|
|
Get the date which the photo was taken.
|
|
|
|
The date value returned is defined by the min() of mtime and ctime.
|
|
|
|
|
|
|
|
@returns, time object or None for non-photo files or 0 timestamp
|
|
|
|
"""
|
|
|
|
def get_date_taken(self):
|
|
|
|
if(not self.is_valid()):
|
|
|
|
return None
|
|
|
|
|
|
|
|
source = self.source
|
|
|
|
seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source))
|
|
|
|
# We need to parse a string from EXIF into a timestamp.
|
|
|
|
# EXIF DateTimeOriginal and EXIF DateTime are both stored in %Y:%m:%d %H:%M:%S format
|
|
|
|
# we use date.strptime -> .timetuple -> time.mktime to do the conversion in the local timezone
|
|
|
|
# EXIF DateTime is already stored as a timestamp
|
|
|
|
# Sourced from https://github.com/photo/frontend/blob/master/src/libraries/models/Photo.php#L500
|
|
|
|
exif = self.get_exif()
|
2015-10-14 09:39:30 +02:00
|
|
|
for key in self.exif_map['date_taken']:
|
|
|
|
try:
|
|
|
|
if(key in exif):
|
|
|
|
seconds_since_epoch = time.mktime(datetime.strptime(str(exif[key]), '%Y:%m:%d %H:%M:%S').timetuple())
|
|
|
|
break;
|
|
|
|
except:
|
|
|
|
pass
|
2015-10-07 10:48:01 +02:00
|
|
|
|
|
|
|
if(seconds_since_epoch == 0):
|
|
|
|
return None
|
|
|
|
|
|
|
|
return time.gmtime(seconds_since_epoch)
|
|
|
|
|
|
|
|
"""
|
|
|
|
Get the duration of a photo in seconds.
|
|
|
|
Uses ffmpeg/ffprobe
|
|
|
|
|
|
|
|
@returns, string or None for a non-photo file
|
|
|
|
"""
|
|
|
|
def get_duration(self):
|
|
|
|
if(not self.is_valid()):
|
|
|
|
return None
|
|
|
|
|
|
|
|
source = self.source
|
|
|
|
result = subprocess.Popen(['ffprobe', source],
|
|
|
|
stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
|
|
|
for key in result.stdout.readlines():
|
|
|
|
if 'Duration' in key:
|
|
|
|
return re.search('(\d{2}:\d{2}.\d{2})', key).group(1).replace('.', ':')
|
|
|
|
return None
|
|
|
|
|
|
|
|
"""
|
|
|
|
Static method to access static __valid_extensions variable.
|
|
|
|
|
|
|
|
@returns, tuple
|
|
|
|
"""
|
|
|
|
@classmethod
|
2015-10-14 05:26:55 +02:00
|
|
|
def get_valid_extensions(Photo):
|
|
|
|
return Photo.__valid_extensions
|