gh-58 Fix all pep8 issues reported in non-test files
This commit is contained in:
parent
3501f2c954
commit
60c4acc1b3
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
nosetests -w elodie/tests
|
||||
nosetests -w elodie/tests && pep8 elodie --exclude=tests
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
"""
|
||||
"""
|
||||
import sys, getopt
|
||||
import getopt
|
||||
import sys
|
||||
from re import sub
|
||||
|
||||
|
||||
def parse(argv, options, long_options, usage):
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, options, long_options)
|
||||
except getopt.GetoptError:
|
||||
print usage
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
return_arguments = {}
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""
|
||||
Author: Jaisen Mathai <jaisen@jmathai.com>
|
||||
Video package that handles all video operations
|
||||
General file system methods
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
@ -11,14 +11,13 @@ from elodie import geolocation
|
|||
from elodie import constants
|
||||
from elodie.localstorage import Db
|
||||
|
||||
"""
|
||||
General file system methods
|
||||
"""
|
||||
|
||||
class FileSystem:
|
||||
"""
|
||||
Create a directory if it does not already exist..
|
||||
|
||||
@param, directory_name, string, A fully qualified path of the directory to create.
|
||||
@param, directory_name, string, A fully qualified path of the
|
||||
directory to create.
|
||||
"""
|
||||
def create_directory(self, directory_path):
|
||||
try:
|
||||
|
@ -35,10 +34,11 @@ class FileSystem:
|
|||
|
||||
"""
|
||||
Delete a directory only if it's empty.
|
||||
Instead of checking first using `len([name for name in os.listdir(directory_path)]) == 0`
|
||||
we catch the OSError exception.
|
||||
Instead of checking first using `len([name for name in
|
||||
os.listdir(directory_path)]) == 0` we catch the OSError exception.
|
||||
|
||||
@param, directory_name, string, A fully qualified path of the directory to delete.
|
||||
@param, directory_name, string, A fully qualified path of the directory
|
||||
to delete.
|
||||
"""
|
||||
def delete_directory_if_empty(self, directory_path):
|
||||
try:
|
||||
|
@ -60,7 +60,10 @@ class FileSystem:
|
|||
for dirname, dirnames, filenames in os.walk(path):
|
||||
# print path to all filenames.
|
||||
for filename in filenames:
|
||||
if(extensions == None or filename.lower().endswith(extensions)):
|
||||
if(
|
||||
extensions is None or
|
||||
filename.lower().endswith(extensions)
|
||||
):
|
||||
files.append('%s/%s' % (dirname, filename))
|
||||
return files
|
||||
|
||||
|
@ -75,7 +78,8 @@ class FileSystem:
|
|||
"""
|
||||
Generate file name for a photo or video using its metadata.
|
||||
We use an ISO8601-like format for the file name prefix.
|
||||
Instead of colons as the separator for hours, minutes and seconds we use a hyphen.
|
||||
Instead of colons as the separator for hours, minutes and seconds we use a
|
||||
hyphen.
|
||||
https://en.wikipedia.org/wiki/ISO_8601#General_principles
|
||||
|
||||
@param, media, Photo|Video, A Photo or Video instance
|
||||
|
@ -86,21 +90,39 @@ class FileSystem:
|
|||
return None
|
||||
|
||||
metadata = media.get_metadata()
|
||||
if(metadata == None):
|
||||
if(metadata is None):
|
||||
return None
|
||||
|
||||
# If the file has EXIF title we use that in the file name (i.e. my-favorite-photo-img_1234.jpg)
|
||||
# If the file has EXIF title we use that in the file name
|
||||
# (i.e. my-favorite-photo-img_1234.jpg)
|
||||
# We want to remove the date prefix we add to the name.
|
||||
# This helps when re-running the program on file which were already processed.
|
||||
base_name = re.sub('^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-', '', metadata['base_name'])
|
||||
# This helps when re-running the program on file which were already
|
||||
# processed.
|
||||
base_name = re.sub(
|
||||
'^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-',
|
||||
'',
|
||||
metadata['base_name']
|
||||
)
|
||||
if(len(base_name) == 0):
|
||||
base_name = metadata['base_name']
|
||||
if('title' in metadata and metadata['title'] is not None and len(metadata['title']) > 0):
|
||||
|
||||
if(
|
||||
'title' in metadata and
|
||||
metadata['title'] is not None and
|
||||
len(metadata['title']) > 0
|
||||
):
|
||||
title_sanitized = re.sub('\W+', '-', metadata['title'].strip())
|
||||
base_name = base_name.replace('-%s' % title_sanitized, '')
|
||||
base_name = '%s-%s' % (base_name, title_sanitized)
|
||||
|
||||
file_name = '%s-%s.%s' % (time.strftime('%Y-%m-%d_%H-%M-%S', metadata['date_taken']), base_name, metadata['extension'])
|
||||
file_name = '%s-%s.%s' % (
|
||||
time.strftime(
|
||||
'%Y-%m-%d_%H-%M-%S',
|
||||
metadata['date_taken']
|
||||
),
|
||||
base_name,
|
||||
metadata['extension']
|
||||
)
|
||||
return file_name.lower()
|
||||
|
||||
"""
|
||||
|
@ -125,8 +147,14 @@ class FileSystem:
|
|||
|
||||
if(metadata['album'] is not None):
|
||||
path.append(metadata['album'])
|
||||
elif(metadata['latitude'] is not None and metadata['longitude'] is not None):
|
||||
place_name = geolocation.place_name(metadata['latitude'], metadata['longitude'])
|
||||
elif(
|
||||
metadata['latitude'] is not None and
|
||||
metadata['longitude'] is not None
|
||||
):
|
||||
place_name = geolocation.place_name(
|
||||
metadata['latitude'],
|
||||
metadata['longitude']
|
||||
)
|
||||
if(place_name is not None):
|
||||
path.append(place_name)
|
||||
|
||||
|
@ -134,7 +162,7 @@ class FileSystem:
|
|||
if(len(path) < 2):
|
||||
path.append('Unknown Location')
|
||||
|
||||
#return '/'.join(path[::-1])
|
||||
# return '/'.join(path[::-1])
|
||||
return '/'.join(path)
|
||||
|
||||
def process_file(self, _file, destination, media, **kwargs):
|
||||
|
@ -156,20 +184,24 @@ class FileSystem:
|
|||
|
||||
db = Db()
|
||||
checksum = db.checksum(_file)
|
||||
if(checksum == None):
|
||||
if(constants.debug == True):
|
||||
if(checksum is None):
|
||||
if(constants.debug is True):
|
||||
print 'Could not get checksum for %s. Skipping...' % _file
|
||||
return
|
||||
|
||||
# If duplicates are not allowed and this hash exists in the db then we return
|
||||
if(allowDuplicate == False and db.check_hash(checksum) == True):
|
||||
if(constants.debug == True):
|
||||
print '%s already exists at %s. Skipping...' % (_file, db.get_hash(checksum))
|
||||
# If duplicates are not allowed and this hash exists in the db then we
|
||||
# return
|
||||
if(allowDuplicate is False and db.check_hash(checksum) is True):
|
||||
if(constants.debug is True):
|
||||
print '%s already exists at %s. Skipping...' % (
|
||||
_file,
|
||||
db.get_hash(checksum)
|
||||
)
|
||||
return
|
||||
|
||||
self.create_directory(dest_directory)
|
||||
|
||||
if(move == True):
|
||||
if(move is True):
|
||||
stat = os.stat(_file)
|
||||
shutil.move(_file, dest_path)
|
||||
os.utime(dest_path, (stat.st_atime, stat.st_mtime))
|
||||
|
@ -191,22 +223,34 @@ class FileSystem:
|
|||
video_file_path = video.get_file_path()
|
||||
|
||||
# Initialize date taken to what's returned from the metadata function.
|
||||
# If the folder and file name follow a time format of YYYY-MM/DD-IMG_0001.JPG then we override the date_taken
|
||||
# If the folder and file name follow a time format of
|
||||
# YYYY-MM/DD-IMG_0001.JPG then we override the date_taken
|
||||
(year, month, day) = [None] * 3
|
||||
directory = os.path.dirname(video_file_path)
|
||||
# If the directory matches we get back a match with groups() = (year, month)
|
||||
# If the directory matches we get back a match with
|
||||
# groups() = (year, month)
|
||||
year_month_match = re.search('(\d{4})-(\d{2})', directory)
|
||||
if(year_month_match is not None):
|
||||
(year, month) = year_month_match.groups()
|
||||
day_match = re.search('^(\d{2})', os.path.basename(video.get_file_path()))
|
||||
day_match = re.search(
|
||||
'^(\d{2})',
|
||||
os.path.basename(video.get_file_path())
|
||||
)
|
||||
if(day_match is not None):
|
||||
day = day_match.group(1)
|
||||
|
||||
# check if the file system path indicated a date and if so we override the metadata value
|
||||
# check if the file system path indicated a date and if so we
|
||||
# override the metadata value
|
||||
if(year is not None and month is not None):
|
||||
if(day is not None):
|
||||
date_taken = time.strptime('{}-{}-{}'.format(year, month, day), '%Y-%m-%d')
|
||||
date_taken = time.strptime(
|
||||
'{}-{}-{}'.format(year, month, day),
|
||||
'%Y-%m-%d'
|
||||
)
|
||||
else:
|
||||
date_taken = time.strptime('{}-{}'.format(year, month), '%Y-%m')
|
||||
|
||||
date_taken = time.strptime(
|
||||
'{}-{}'.format(year, month),
|
||||
'%Y-%m'
|
||||
)
|
||||
|
||||
os.utime(video_file_path, (time.time(), time.mktime(date_taken)))
|
||||
|
|
|
@ -11,6 +11,7 @@ import urllib
|
|||
from elodie import constants
|
||||
from elodie.localstorage import Db
|
||||
|
||||
|
||||
class Fraction(fractions.Fraction):
|
||||
"""Only create Fractions from floats.
|
||||
>>> Fraction(0.3)
|
||||
|
@ -22,6 +23,7 @@ class Fraction(fractions.Fraction):
|
|||
"""Should be compatible with Python 2.6, though untested."""
|
||||
return fractions.Fraction.from_float(value).limit_denominator(99999)
|
||||
|
||||
|
||||
def coordinates_by_name(name):
|
||||
# Try to get cached location first
|
||||
db = Db()
|
||||
|
@ -36,57 +38,78 @@ def coordinates_by_name(name):
|
|||
geolocation_info = lookup(name)
|
||||
|
||||
if(geolocation_info is not None):
|
||||
if('results' in geolocation_info and len(geolocation_info['results']) != 0 and
|
||||
'locations' in geolocation_info['results'][0] and len(geolocation_info['results'][0]['locations']) != 0):
|
||||
if(
|
||||
'results' in geolocation_info and
|
||||
len(geolocation_info['results']) != 0 and
|
||||
'locations' in geolocation_info['results'][0] and
|
||||
len(geolocation_info['results'][0]['locations']) != 0
|
||||
):
|
||||
|
||||
# By default we use the first entry unless we find one with geocodeQuality=city.
|
||||
use_location = geolocation_info['results'][0]['locations'][0]['latLng']
|
||||
# Loop over the locations to see if we come accross a geocodeQuality=city.
|
||||
# By default we use the first entry unless we find one with
|
||||
# geocodeQuality=city.
|
||||
geolocation_result = geolocation_info['results'][0]
|
||||
use_location = geolocation_result['locations'][0]['latLng']
|
||||
# Loop over the locations to see if we come accross a
|
||||
# geocodeQuality=city.
|
||||
# If we find a city we set that to the use_location and break
|
||||
for location in geolocation_info['results'][0]['locations']:
|
||||
if('latLng' in location and 'lat' in location['latLng'] and 'lng' in location['latLng'] and location['geocodeQuality'].lower() == 'city'):
|
||||
for location in geolocation_result['locations']:
|
||||
if(
|
||||
'latLng' in location and
|
||||
'lat' in location['latLng'] and
|
||||
'lng' in location['latLng'] and
|
||||
location['geocodeQuality'].lower() == 'city'
|
||||
):
|
||||
use_location = location['latLng']
|
||||
break
|
||||
|
||||
|
||||
return {
|
||||
'latitude': use_location['lat'],
|
||||
'longitude': use_location['lng']
|
||||
}
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def decimal_to_dms(decimal, signed=True):
|
||||
# if decimal is negative we need to make the degrees and minutes negative also
|
||||
# if decimal is negative we need to make the degrees and minutes
|
||||
# negative also
|
||||
sign = 1
|
||||
if(decimal < 0):
|
||||
sign = -1
|
||||
|
||||
# http://anothergisblog.blogspot.com/2011/11/convert-decimal-degree-to-degrees.html
|
||||
# http://anothergisblog.blogspot.com/2011/11/convert-decimal-degree-to-degrees.html # noqa
|
||||
degrees = int(decimal)
|
||||
subminutes = abs((decimal - int(decimal)) * 60)
|
||||
minutes = int(subminutes) * sign
|
||||
subseconds = abs((subminutes - int(subminutes)) * 60) * sign
|
||||
subseconds_fraction = Fraction(subseconds)
|
||||
|
||||
if(signed == False):
|
||||
if(signed is False):
|
||||
degrees = abs(degrees)
|
||||
minutes = abs(minutes)
|
||||
subseconds_fraction = Fraction(abs(subseconds))
|
||||
|
||||
return (pyexiv2.Rational(degrees, 1), pyexiv2.Rational(minutes, 1), pyexiv2.Rational(subseconds_fraction.numerator, subseconds_fraction.denominator))
|
||||
|
||||
def dms_to_decimal(degrees, minutes, seconds, sign=' '):
|
||||
return (-1 if sign[0] in 'SWsw' else 1) * (
|
||||
float(degrees) +
|
||||
float(minutes) / 60 +
|
||||
float(seconds) / 3600
|
||||
return (
|
||||
pyexiv2.Rational(degrees, 1),
|
||||
pyexiv2.Rational(minutes, 1),
|
||||
pyexiv2.Rational(subseconds_fraction.numerator, subseconds_fraction.denominator) # noqa
|
||||
)
|
||||
|
||||
|
||||
def dms_to_decimal(degrees, minutes, seconds, direction=' '):
|
||||
sign = 1
|
||||
if(direction[0] in 'NEne'):
|
||||
sign = -1
|
||||
return (
|
||||
float(degrees) + float(minutes) / 60 + float(seconds) / 3600
|
||||
) * sign
|
||||
|
||||
|
||||
def get_key():
|
||||
config_file = '%s/config.ini' % constants.application_directory
|
||||
if not path.exists(config_file):
|
||||
return None
|
||||
|
||||
|
||||
config = ConfigParser()
|
||||
config.read(config_file)
|
||||
if('MapQuest' not in config.sections()):
|
||||
|
@ -94,16 +117,17 @@ def get_key():
|
|||
|
||||
return config.get('MapQuest', 'key')
|
||||
|
||||
|
||||
def place_name(lat, lon):
|
||||
|
||||
# Try to get cached location first
|
||||
db = Db()
|
||||
# 3km distace radious for a match
|
||||
cached_place_name = db.get_location_name(lat, lon,3000)
|
||||
cached_place_name = db.get_location_name(lat, lon, 3000)
|
||||
if(cached_place_name is not None):
|
||||
return cached_place_name
|
||||
|
||||
lookup_place_name = None;
|
||||
lookup_place_name = None
|
||||
geolocation_info = reverse_lookup(lat, lon)
|
||||
if(geolocation_info is not None):
|
||||
if('address' in geolocation_info):
|
||||
|
@ -130,18 +154,22 @@ def reverse_lookup(lat, lon):
|
|||
|
||||
try:
|
||||
params = {'format': 'json', 'key': key, 'lat': lat, 'lon': lon}
|
||||
r = requests.get('http://open.mapquestapi.com/nominatim/v1/reverse.php?%s' % urllib.urlencode(params))
|
||||
r = requests.get(
|
||||
'http://open.mapquestapi.com/nominatim/v1/reverse.php?%s' %
|
||||
urllib.urlencode(params)
|
||||
)
|
||||
return r.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print e
|
||||
return None
|
||||
except ValueError as e:
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print r.text
|
||||
print e
|
||||
return None
|
||||
|
||||
|
||||
def lookup(name):
|
||||
if(name is None or len(name) == 0):
|
||||
return None
|
||||
|
@ -150,16 +178,19 @@ def lookup(name):
|
|||
|
||||
try:
|
||||
params = {'format': 'json', 'key': key, 'location': name}
|
||||
if(constants.debug == True):
|
||||
print 'http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params)
|
||||
r = requests.get('http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params))
|
||||
if(constants.debug is True):
|
||||
print 'http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params) # noqa
|
||||
r = requests.get(
|
||||
'http://open.mapquestapi.com/geocoding/v1/address?%s' %
|
||||
urllib.urlencode(params)
|
||||
)
|
||||
return r.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print e
|
||||
return None
|
||||
except ValueError as e:
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print r.text
|
||||
print e
|
||||
return None
|
||||
|
|
|
@ -6,9 +6,11 @@ import sys
|
|||
|
||||
from elodie import constants
|
||||
|
||||
|
||||
class Db(object):
|
||||
def __init__(self):
|
||||
# verify that the application directory (~/.elodie) exists, else create it
|
||||
# verify that the application directory (~/.elodie) exists,
|
||||
# else create it
|
||||
if not os.path.exists(constants.application_directory):
|
||||
os.makedirs(constants.application_directory)
|
||||
|
||||
|
@ -20,7 +22,8 @@ class Db(object):
|
|||
|
||||
self.hash_db = {}
|
||||
|
||||
# We know from above that this file exists so we open it for reading only.
|
||||
# We know from above that this file exists so we open it
|
||||
# for reading only.
|
||||
with open(constants.hash_db, 'r') as f:
|
||||
try:
|
||||
self.hash_db = json.load(f)
|
||||
|
@ -35,7 +38,8 @@ class Db(object):
|
|||
|
||||
self.location_db = []
|
||||
|
||||
# We know from above that this file exists so we open it for reading only.
|
||||
# We know from above that this file exists so we open it
|
||||
# for reading only.
|
||||
with open(constants.location_db, 'r') as f:
|
||||
try:
|
||||
self.location_db = json.load(f)
|
||||
|
@ -44,14 +48,14 @@ class Db(object):
|
|||
|
||||
def add_hash(self, key, value, write=False):
|
||||
self.hash_db[key] = value
|
||||
if(write == True):
|
||||
if(write is True):
|
||||
self.update_hash_db()
|
||||
|
||||
def check_hash(self, key):
|
||||
return key in self.hash_db
|
||||
|
||||
def get_hash(self, key):
|
||||
if(self.check_hash(key) == True):
|
||||
if(self.check_hash(key) is True):
|
||||
return self.hash_db[key]
|
||||
return None
|
||||
|
||||
|
@ -88,27 +92,29 @@ class Db(object):
|
|||
data['long'] = longitude
|
||||
data['name'] = place
|
||||
self.location_db.append(data)
|
||||
if(write == True):
|
||||
if(write is True):
|
||||
self.update_location_db()
|
||||
|
||||
def get_location_name(self, latitude, longitude,threshold_m):
|
||||
def get_location_name(self, latitude, longitude, threshold_m):
|
||||
last_d = sys.maxint
|
||||
name = None
|
||||
for data in self.location_db:
|
||||
# As threshold is quite smal use simple math
|
||||
# From http://stackoverflow.com/questions/15736995/how-can-i-quickly-estimate-the-distance-between-two-latitude-longitude-points
|
||||
# From http://stackoverflow.com/questions/15736995/how-can-i-quickly-estimate-the-distance-between-two-latitude-longitude-points # noqa
|
||||
# convert decimal degrees to radians
|
||||
|
||||
lon1, lat1, lon2, lat2 = map(radians, [longitude, latitude, data['long'], data['lat']])
|
||||
lon1, lat1, lon2, lat2 = map(
|
||||
radians,
|
||||
[longitude, latitude, data['long'], data['lat']]
|
||||
)
|
||||
|
||||
R = 6371000 # radius of the earth in m
|
||||
x = (lon2 - lon1) * cos( 0.5*(lat2+lat1) )
|
||||
x = (lon2 - lon1) * cos(0.5*(lat2+lat1))
|
||||
y = lat2 - lat1
|
||||
d = R * sqrt( x*x + y*y )
|
||||
d = R * sqrt(x*x + y*y)
|
||||
# Use if closer then threshold_km reuse lookup
|
||||
if(d <= threshold_m and d < last_d):
|
||||
#print "Found in cached location dist: %d m" % d
|
||||
name = data['name'];
|
||||
name = data['name']
|
||||
last_d = d
|
||||
|
||||
return name
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""
|
||||
Author: Jaisen Mathai <jaisen@jmathai.com>
|
||||
Media package that handles all video operations
|
||||
Media package that's a parent class for media objects
|
||||
"""
|
||||
|
||||
# load modules
|
||||
|
@ -17,9 +17,7 @@ import re
|
|||
import subprocess
|
||||
import time
|
||||
|
||||
"""
|
||||
Media class for general video operations
|
||||
"""
|
||||
|
||||
class Media(object):
|
||||
# class / static variable accessible through get_valid_extensions()
|
||||
__name__ = 'Media'
|
||||
|
@ -30,7 +28,7 @@ class Media(object):
|
|||
def __init__(self, source=None):
|
||||
self.source = source
|
||||
self.exif_map = {
|
||||
'date_taken': ['Exif.Photo.DateTimeOriginal', 'Exif.Image.DateTime'], #, 'EXIF FileDateTime'],
|
||||
'date_taken': ['Exif.Photo.DateTimeOriginal', 'Exif.Image.DateTime'], # , 'EXIF FileDateTime'], # noqa
|
||||
'latitude': 'Exif.GPSInfo.GPSLatitude',
|
||||
'latitude_ref': 'Exif.GPSInfo.GPSLatitudeRef',
|
||||
'longitude': 'Exif.GPSInfo.GPSLongitude',
|
||||
|
@ -51,7 +49,7 @@ class Media(object):
|
|||
exiftool_attributes = self.get_exiftool_attributes()
|
||||
if(exiftool_attributes is None or 'album' not in exiftool_attributes):
|
||||
return None
|
||||
|
||||
|
||||
return exiftool_attributes['album']
|
||||
|
||||
"""
|
||||
|
@ -65,12 +63,11 @@ class Media(object):
|
|||
# If exiftool wasn't found we try to brute force the homebrew location
|
||||
if(exiftool is None):
|
||||
exiftool = '/usr/local/bin/exiftool'
|
||||
if(not os.path.isfile(exiftool) or not os.access(exiftool, os.X_OK)):
|
||||
if(not os.path.isfile(exiftool) or not os.access(exiftool, os.X_OK)): # noqa
|
||||
return None
|
||||
|
||||
return exiftool
|
||||
|
||||
|
||||
"""
|
||||
Get the full path to the video.
|
||||
|
||||
|
@ -88,14 +85,15 @@ class Media(object):
|
|||
|
||||
"""
|
||||
Read EXIF from a photo file.
|
||||
We store the result in a member variable so we can call get_exif() often without performance degredation
|
||||
We store the result in a member variable so we can call get_exif() often
|
||||
without performance degredation
|
||||
|
||||
@returns, list or none for a non-photo file
|
||||
"""
|
||||
def get_exif(self):
|
||||
if(not self.is_valid()):
|
||||
return None
|
||||
|
||||
|
||||
if(self.exif is not None):
|
||||
return self.exif
|
||||
|
||||
|
@ -114,7 +112,11 @@ class Media(object):
|
|||
return False
|
||||
|
||||
source = self.source
|
||||
process_output = subprocess.Popen(['%s "%s"' % (exiftool, source)], stdout=subprocess.PIPE, shell=True)
|
||||
process_output = subprocess.Popen(
|
||||
['%s "%s"' % (exiftool, source)],
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True
|
||||
)
|
||||
output = process_output.stdout.read()
|
||||
|
||||
# Get album from exiftool output
|
||||
|
@ -131,7 +133,7 @@ class Media(object):
|
|||
title_return = title_regex.group(1).strip()
|
||||
if(len(title_return) > 0):
|
||||
title = title_return
|
||||
break;
|
||||
break
|
||||
|
||||
self.exiftool_attributes = {
|
||||
'album': album,
|
||||
|
@ -140,7 +142,6 @@ class Media(object):
|
|||
|
||||
return self.exiftool_attributes
|
||||
|
||||
|
||||
"""
|
||||
Get the file extension as a lowercased string.
|
||||
|
||||
|
@ -163,7 +164,7 @@ class Media(object):
|
|||
if(not self.is_valid()):
|
||||
return None
|
||||
|
||||
if(self.metadata is not None and update_cache == False):
|
||||
if(self.metadata is not None and update_cache is False):
|
||||
return self.metadata
|
||||
|
||||
source = self.source
|
||||
|
@ -181,7 +182,7 @@ class Media(object):
|
|||
}
|
||||
|
||||
return self.metadata
|
||||
|
||||
|
||||
"""
|
||||
Get the mimetype of the file.
|
||||
|
||||
|
@ -193,11 +194,11 @@ class Media(object):
|
|||
|
||||
source = self.source
|
||||
mimetype = mimetypes.guess_type(source)
|
||||
if(mimetype == None):
|
||||
if(mimetype is None):
|
||||
return None
|
||||
|
||||
return mimetype[0]
|
||||
|
||||
|
||||
"""
|
||||
Get the title for a photo of video
|
||||
|
||||
|
@ -232,9 +233,14 @@ class Media(object):
|
|||
source = self.source
|
||||
stat = os.stat(source)
|
||||
exiftool_config = constants.exiftool_config
|
||||
if(constants.debug == True):
|
||||
print '%s -config "%s" -xmp-elodie:Album="%s" "%s"' % (exiftool, exiftool_config, name, source)
|
||||
process_output = subprocess.Popen(['%s -config "%s" -xmp-elodie:Album="%s" "%s"' % (exiftool, exiftool_config, name, source)], stdout=subprocess.PIPE, shell=True)
|
||||
if(constants.debug is True):
|
||||
print '%s -config "%s" -xmp-elodie:Album="%s" "%s"' % (exiftool, exiftool_config, name, source) # noqa
|
||||
process_output = subprocess.Popen(
|
||||
['%s -config "%s" -xmp-elodie:Album="%s" "%s"' %
|
||||
(exiftool, exiftool_config, name, source)],
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True
|
||||
)
|
||||
streamdata = process_output.communicate()[0]
|
||||
|
||||
if(process_output.returncode != 0):
|
||||
|
@ -266,14 +272,16 @@ class Media(object):
|
|||
self.set_album(folder)
|
||||
return True
|
||||
|
||||
|
||||
"""
|
||||
Specifically update the basename attribute in the metadata dictionary for this instance.
|
||||
Specifically update the basename attribute in the metadata
|
||||
dictionary for this instance.
|
||||
This is used for when we update the EXIF title of a media file.
|
||||
Since that determines the name of a file if we update the title of a file more than once it appends to the file name.
|
||||
Since that determines the name of a file if we update the
|
||||
title of a file more than once it appends to the file name.
|
||||
I.e. 2015-12-31_00-00-00-my-first-title-my-second-title.jpg
|
||||
|
||||
@param, string, new_basename, New basename of file (with the old title removed
|
||||
@param, string, new_basename, New basename of file
|
||||
(with the old title removed)
|
||||
"""
|
||||
def set_metadata_basename(self, new_basename):
|
||||
self.get_metadata()
|
||||
|
|
|
@ -20,9 +20,7 @@ from elodie import constants
|
|||
from media import Media
|
||||
from elodie import geolocation
|
||||
|
||||
"""
|
||||
Photo class for general photo operations
|
||||
"""
|
||||
|
||||
class Photo(Media):
|
||||
__name__ = 'Photo'
|
||||
extensions = ('jpg', 'jpeg', 'nef', 'dng', 'gif')
|
||||
|
@ -35,7 +33,7 @@ class Photo(Media):
|
|||
|
||||
# We only want to parse EXIF once so we store it here
|
||||
self.exif = None
|
||||
|
||||
|
||||
"""
|
||||
Get the duration of a photo in seconds.
|
||||
Uses ffmpeg/ffprobe
|
||||
|
@ -47,11 +45,17 @@ class Photo(Media):
|
|||
return None
|
||||
|
||||
source = self.source
|
||||
result = subprocess.Popen(['ffprobe', source],
|
||||
stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
||||
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 re.search(
|
||||
'(\d{2}:\d{2}.\d{2})',
|
||||
key
|
||||
).group(1).replace('.', ':')
|
||||
return None
|
||||
|
||||
"""
|
||||
|
@ -63,26 +67,40 @@ class Photo(Media):
|
|||
if(not self.is_valid()):
|
||||
return None
|
||||
|
||||
key = self.exif_map['longitude'] if type == 'longitude' else self.exif_map['latitude']
|
||||
key = self.exif_map['latitude']
|
||||
if(type == 'longitude'):
|
||||
key = self.exif_map['longitude']
|
||||
exif = self.get_exif()
|
||||
|
||||
if(key not in exif):
|
||||
return None
|
||||
|
||||
try:
|
||||
# this is a hack to get the proper direction by negating the values for S and W
|
||||
# this is a hack to get the proper direction by negating the
|
||||
# values for S and W
|
||||
latdir = 1
|
||||
if(type == 'latitude' and str(exif[self.exif_map['latitude_ref']].value) == 'S'):
|
||||
if(type == 'latitude' and str(exif[self.exif_map['latitude_ref']].value) == 'S'): # noqa
|
||||
latdir = -1
|
||||
|
||||
londir = 1
|
||||
if(type =='longitude' and str(exif[self.exif_map['longitude_ref']].value) == 'W'):
|
||||
if(type == 'longitude' and str(exif[self.exif_map['longitude_ref']].value) == 'W'): # noqa
|
||||
londir = -1
|
||||
|
||||
coords = exif[key].value
|
||||
if(type == 'latitude'):
|
||||
return float(str(LatLon.Latitude(degree=coords[0], minute=coords[1], second=coords[2]))) * latdir
|
||||
lat_val = LatLon.Latitude(
|
||||
degree=coords[0],
|
||||
minute=coords[1],
|
||||
second=coords[2]
|
||||
)
|
||||
return float(str(lat_val)) * latdir
|
||||
else:
|
||||
return float(str(LatLon.Longitude(degree=coords[0], minute=coords[1], second=coords[2]))) * londir
|
||||
lon_val = LatLon.Longitude(
|
||||
degree=coords[0],
|
||||
minute=coords[1],
|
||||
second=coords[2]
|
||||
)
|
||||
return float(str(lon_val)) * londir
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
@ -97,21 +115,23 @@ class Photo(Media):
|
|||
return None
|
||||
|
||||
source = self.source
|
||||
seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source))
|
||||
seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source)) # noqa
|
||||
# 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 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
|
||||
# Sourced from https://github.com/photo/frontend/blob/master/src/libraries/models/Photo.php#L500 # noqa
|
||||
exif = self.get_exif()
|
||||
for key in self.exif_map['date_taken']:
|
||||
try:
|
||||
if(key in exif):
|
||||
if(re.match('\d{4}(-|:)\d{2}(-|:)\d{2}', str(exif[key].value)) is not None):
|
||||
seconds_since_epoch = time.mktime(exif[key].value.timetuple())
|
||||
break;
|
||||
if(re.match('\d{4}(-|:)\d{2}(-|:)\d{2}', str(exif[key].value)) is not None): # noqa
|
||||
seconds_since_epoch = time.mktime(exif[key].value.timetuple()) # noqa
|
||||
break
|
||||
except BaseException as e:
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print e
|
||||
pass
|
||||
|
||||
|
@ -121,8 +141,9 @@ class Photo(Media):
|
|||
return time.gmtime(seconds_since_epoch)
|
||||
|
||||
"""
|
||||
Check the file extension against valid file extensions as returned by self.extensions
|
||||
|
||||
Check the file extension against valid file extensions as returned
|
||||
by self.extensions
|
||||
|
||||
@returns, boolean
|
||||
"""
|
||||
def is_valid(self):
|
||||
|
@ -131,7 +152,7 @@ class Photo(Media):
|
|||
# gh-4 This checks if the source file is an image.
|
||||
# It doesn't validate against the list of supported types.
|
||||
if(imghdr.what(source) is None):
|
||||
return False;
|
||||
return False
|
||||
|
||||
return os.path.splitext(source)[1][1:].lower() in self.extensions
|
||||
|
||||
|
@ -172,10 +193,10 @@ class Photo(Media):
|
|||
exif_metadata = pyexiv2.ImageMetadata(source)
|
||||
exif_metadata.read()
|
||||
|
||||
exif_metadata['Exif.GPSInfo.GPSLatitude'] = geolocation.decimal_to_dms(latitude, False)
|
||||
exif_metadata['Exif.GPSInfo.GPSLatitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLatitudeRef', 'N' if latitude >= 0 else 'S')
|
||||
exif_metadata['Exif.GPSInfo.GPSLongitude'] = geolocation.decimal_to_dms(longitude, False)
|
||||
exif_metadata['Exif.GPSInfo.GPSLongitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLongitudeRef', 'E' if longitude >= 0 else 'W')
|
||||
exif_metadata['Exif.GPSInfo.GPSLatitude'] = geolocation.decimal_to_dms(latitude, False) # noqa
|
||||
exif_metadata['Exif.GPSInfo.GPSLatitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLatitudeRef', 'N' if latitude >= 0 else 'S') # noqa
|
||||
exif_metadata['Exif.GPSInfo.GPSLongitude'] = geolocation.decimal_to_dms(longitude, False) # noqa
|
||||
exif_metadata['Exif.GPSInfo.GPSLongitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLongitudeRef', 'E' if longitude >= 0 else 'W') # noqa
|
||||
|
||||
exif_metadata.write()
|
||||
return True
|
||||
|
|
|
@ -20,12 +20,10 @@ from elodie import constants
|
|||
from elodie import plist_parser
|
||||
from media import Media
|
||||
|
||||
"""
|
||||
Video class for general video operations
|
||||
"""
|
||||
|
||||
class Video(Media):
|
||||
__name__ = 'Video'
|
||||
extensions = ('avi','m4v','mov','mp4','3gp')
|
||||
extensions = ('avi', 'm4v', 'mov', 'mp4', '3gp')
|
||||
|
||||
"""
|
||||
@param, source, string, The fully qualified path to the video file
|
||||
|
@ -43,12 +41,11 @@ class Video(Media):
|
|||
avmetareadwrite = find_executable('avmetareadwrite')
|
||||
if(avmetareadwrite is None):
|
||||
avmetareadwrite = '/usr/bin/avmetareadwrite'
|
||||
if(not os.path.isfile(avmetareadwrite) or not os.access(avmetareadwrite, os.X_OK)):
|
||||
if(not os.path.isfile(avmetareadwrite) or not os.access(avmetareadwrite, os.X_OK)): # noqa
|
||||
return None
|
||||
|
||||
return avmetareadwrite
|
||||
|
||||
|
||||
"""
|
||||
Get latitude or longitude of photo from EXIF
|
||||
|
||||
|
@ -71,7 +68,7 @@ class Video(Media):
|
|||
|
||||
direction = direction.group(0)
|
||||
|
||||
decimal_degrees = float(coordinate[0]) + float(coordinate[1])/60 + float(coordinate[2])/3600
|
||||
decimal_degrees = float(coordinate[0]) + float(coordinate[1])/60 + float(coordinate[2])/3600 # noqa
|
||||
if(direction == 'S' or direction == 'W'):
|
||||
decimal_degrees = decimal_degrees * -1
|
||||
|
||||
|
@ -89,9 +86,10 @@ class Video(Media):
|
|||
|
||||
source = self.source
|
||||
# We need to parse a string from EXIF into a timestamp.
|
||||
# We use date.strptime -> .timetuple -> time.mktime to do the conversion in the local timezone
|
||||
# We use date.strptime -> .timetuple -> time.mktime to do the
|
||||
# conversion in the local timezone
|
||||
# If the time is not found in EXIF we update EXIF
|
||||
seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source))
|
||||
seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source)) # noqa
|
||||
time_found_in_exif = False
|
||||
exif_data = self.get_exif()
|
||||
for key in ['Creation Date', 'Media Create Date']:
|
||||
|
@ -99,7 +97,12 @@ class Video(Media):
|
|||
if(date is not None):
|
||||
date_string = date.group(1)
|
||||
try:
|
||||
exif_seconds_since_epoch = time.mktime(datetime.strptime(date_string, '%Y:%m:%d %H:%M:%S').timetuple())
|
||||
exif_seconds_since_epoch = time.mktime(
|
||||
datetime.strptime(
|
||||
date_string,
|
||||
'%Y:%m:%d %H:%M:%S'
|
||||
).timetuple()
|
||||
)
|
||||
if(exif_seconds_since_epoch < seconds_since_epoch):
|
||||
seconds_since_epoch = exif_seconds_since_epoch
|
||||
time_found_in_exif = True
|
||||
|
@ -111,7 +114,7 @@ class Video(Media):
|
|||
return None
|
||||
|
||||
return time.gmtime(seconds_since_epoch)
|
||||
|
||||
|
||||
"""
|
||||
Get the duration of a video in seconds.
|
||||
Uses ffmpeg/ffprobe
|
||||
|
@ -123,16 +126,23 @@ class Video(Media):
|
|||
return None
|
||||
|
||||
source = self.source
|
||||
result = subprocess.Popen(['ffprobe', source],
|
||||
stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
||||
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 re.search(
|
||||
'(\d{2}:\d{2}.\d{2})',
|
||||
key
|
||||
).group(1).replace('.', ':')
|
||||
return None
|
||||
|
||||
"""
|
||||
Get exif data from video file.
|
||||
Not all video files have exif and this currently relies on the CLI exiftool program
|
||||
Not all video files have exif and this currently relies on
|
||||
the CLI exiftool program
|
||||
|
||||
@returns, string or None if exiftool is not found
|
||||
"""
|
||||
|
@ -142,12 +152,17 @@ class Video(Media):
|
|||
return None
|
||||
|
||||
source = self.source
|
||||
process_output = subprocess.Popen(['%s "%s"' % (exiftool, source)], stdout=subprocess.PIPE, shell=True)
|
||||
process_output = subprocess.Popen(
|
||||
['%s "%s"' % (exiftool, source)],
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True
|
||||
)
|
||||
return process_output.stdout.read()
|
||||
|
||||
"""
|
||||
Check the file extension against valid file extensions as returned by self.extensions
|
||||
|
||||
Check the file extension against valid file extensions as
|
||||
returned by self.extensions
|
||||
|
||||
@returns, boolean
|
||||
"""
|
||||
def is_valid(self):
|
||||
|
@ -168,8 +183,14 @@ class Video(Media):
|
|||
source = self.source
|
||||
|
||||
result = self.__update_using_plist(time=date_taken_as_datetime)
|
||||
if(result == True):
|
||||
os.utime(source, (int(time.time()), time.mktime(date_taken_as_datetime.timetuple())))
|
||||
if(result is True):
|
||||
os.utime(
|
||||
source,
|
||||
(
|
||||
int(time.time()),
|
||||
time.mktime(date_taken_as_datetime.timetuple())
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
@ -185,7 +206,7 @@ class Video(Media):
|
|||
if(latitude is None or longitude is None):
|
||||
return False
|
||||
|
||||
result = self.__update_using_plist(latitude=latitude, longitude=longitude)
|
||||
result = self.__update_using_plist(latitude=latitude, longitude=longitude) # noqa
|
||||
return result
|
||||
|
||||
"""
|
||||
|
@ -210,9 +231,11 @@ class Video(Media):
|
|||
1) Check if avmetareadwrite is installed
|
||||
2) Export a plist file to a temporary location from the source file
|
||||
3) Regex replace values in the plist file
|
||||
4) Update the source file using the updated plist and save it to a temporary location
|
||||
4) Update the source file using the updated plist and save it to a
|
||||
temporary location
|
||||
5) Validate that the metadata in the updated temorary movie is valid
|
||||
6) Copystat permission and time bits from the source file to the temporary movie
|
||||
6) Copystat permission and time bits from the source file to the
|
||||
temporary movie
|
||||
7) Move the temporary file to overwrite the source file
|
||||
|
||||
@param, latitude, float, Latitude of the file
|
||||
|
@ -221,33 +244,49 @@ class Video(Media):
|
|||
@returns, boolean
|
||||
"""
|
||||
def __update_using_plist(self, **kwargs):
|
||||
if('latitude' not in kwargs and 'longitude' not in kwargs and 'time' not in kwargs and 'title' not in kwargs):
|
||||
if(constants.debug == True):
|
||||
if(
|
||||
'latitude' not in kwargs and
|
||||
'longitude' not in kwargs and
|
||||
'time' not in kwargs and
|
||||
'title' not in kwargs
|
||||
):
|
||||
if(constants.debug is True):
|
||||
print 'No lat/lon passed into __create_plist'
|
||||
return False
|
||||
|
||||
avmetareadwrite = self.get_avmetareadwrite()
|
||||
if(avmetareadwrite is None):
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print 'Could not find avmetareadwrite'
|
||||
return False
|
||||
|
||||
source = self.source
|
||||
|
||||
# First we need to write the plist for an existing file to a temporary location
|
||||
# First we need to write the plist for an existing file
|
||||
# to a temporary location
|
||||
with tempfile.NamedTemporaryFile() as plist_temp:
|
||||
# We need to write the plist file in a child process but also block for it to be complete.
|
||||
# We need to write the plist file in a child process
|
||||
# but also block for it to be complete.
|
||||
# http://stackoverflow.com/a/5631819/1318758
|
||||
avmetareadwrite_generate_plist_command = '%s -p "%s" "%s"' % (avmetareadwrite, plist_temp.name, source)
|
||||
write_process = subprocess.Popen([avmetareadwrite_generate_plist_command], stdout=subprocess.PIPE, shell=True)
|
||||
avmetareadwrite_generate_plist_command = '%s -p "%s" "%s"' % (
|
||||
avmetareadwrite,
|
||||
plist_temp.name,
|
||||
source
|
||||
)
|
||||
write_process = subprocess.Popen(
|
||||
[avmetareadwrite_generate_plist_command],
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True
|
||||
)
|
||||
streamdata = write_process.communicate()[0]
|
||||
if(write_process.returncode != 0):
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print 'Failed to generate plist file'
|
||||
return False
|
||||
|
||||
plist = plist_parser.Plist(plist_temp.name)
|
||||
# Depending on the kwargs that were passed in we regex the plist_text before we write it back.
|
||||
# Depending on the kwargs that were passed in we regex
|
||||
# the plist_text before we write it back.
|
||||
plist_should_be_written = False
|
||||
if('latitude' in kwargs and 'longitude' in kwargs):
|
||||
latitude = str(abs(kwargs['latitude'])).lstrip('0')
|
||||
|
@ -258,10 +297,16 @@ class Video(Media):
|
|||
lat_sign = '+' if latitude > 0 else '-'
|
||||
# We need to zeropad the longitude.
|
||||
# No clue why - ask Apple.
|
||||
# We set the sign to + or - and then we take the absolute value and fill it.
|
||||
# We set the sign to + or - and then we take the absolute value
|
||||
# and fill it.
|
||||
lon_sign = '+' if longitude > 0 else '-'
|
||||
longitude_str = '{:9.5f}'.format(abs(longitude)).replace(' ', '0')
|
||||
lat_lon_str = '%s%s%s%s' % (lat_sign, latitude, lon_sign, longitude_str)
|
||||
longitude_str = '{:9.5f}'.format(abs(longitude)).replace(' ', '0') # noqa
|
||||
lat_lon_str = '%s%s%s%s' % (
|
||||
lat_sign,
|
||||
latitude,
|
||||
lon_sign,
|
||||
longitude_str
|
||||
)
|
||||
|
||||
plist.update_key('common/location', lat_lon_str)
|
||||
plist_should_be_written = True
|
||||
|
@ -277,13 +322,12 @@ class Video(Media):
|
|||
hms = [int(x) for x in time_parts[1].split(':')]
|
||||
|
||||
if(hms is not None):
|
||||
d = datetime(ymd[0], ymd[1], ymd[2], hms[0], hms[1], hms[2])
|
||||
d = datetime(ymd[0], ymd[1], ymd[2], hms[0], hms[1], hms[2]) # noqa
|
||||
else:
|
||||
d = datetime(ymd[0], ymd[1], ymd[2], 12, 00, 00)
|
||||
|
||||
offset = time.strftime("%z", time.gmtime(time.time()))
|
||||
time_string = d.strftime('%Y-%m-%dT%H:%M:%S{}'.format(offset))
|
||||
#2015-10-09T17:11:30-0700
|
||||
time_string = d.strftime('%Y-%m-%dT%H:%M:%S{}'.format(offset)) # noqa
|
||||
plist.update_key('common/creationDate', time_string)
|
||||
plist_should_be_written = True
|
||||
|
||||
|
@ -296,13 +340,15 @@ class Video(Media):
|
|||
plist_final = plist_temp.name
|
||||
plist.write_file(plist_final)
|
||||
else:
|
||||
if(constants.debug == True):
|
||||
if(constants.debug is True):
|
||||
print 'Nothing to update, plist unchanged'
|
||||
return False
|
||||
|
||||
# We create a temporary file to save the modified file to.
|
||||
# If the modification is successful we will update the existing file.
|
||||
# We can't call self.get_metadata else we will run into infinite loops
|
||||
# If the modification is successful we will update the
|
||||
# existing file.
|
||||
# We can't call self.get_metadata else we will run into
|
||||
# infinite loops
|
||||
# metadata = self.get_metadata()
|
||||
temp_movie = None
|
||||
with tempfile.NamedTemporaryFile() as temp_file:
|
||||
|
@ -310,23 +356,44 @@ class Video(Media):
|
|||
|
||||
# We need to block until the child process completes.
|
||||
# http://stackoverflow.com/a/5631819/1318758
|
||||
avmetareadwrite_command = '%s -a %s "%s" "%s"' % (avmetareadwrite, plist_final, source, temp_movie)
|
||||
update_process = subprocess.Popen([avmetareadwrite_command], stdout=subprocess.PIPE, shell=True)
|
||||
avmetareadwrite_command = '%s -a %s "%s" "%s"' % (
|
||||
avmetareadwrite,
|
||||
plist_final,
|
||||
source,
|
||||
temp_movie
|
||||
)
|
||||
update_process = subprocess.Popen(
|
||||
[avmetareadwrite_command],
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True
|
||||
)
|
||||
streamdata = update_process.communicate()[0]
|
||||
if(update_process.returncode != 0):
|
||||
if(constants.debug == True):
|
||||
print '%s did not complete successfully' % avmetareadwrite_command
|
||||
if(constants.debug is True):
|
||||
print '%s did not complete successfully' % avmetareadwrite_command # noqa
|
||||
return False
|
||||
|
||||
# Before we do anything destructive we confirm that the file is in tact.
|
||||
# Before we do anything destructive we confirm that the
|
||||
# file is in tact.
|
||||
check_media = Video(temp_movie)
|
||||
check_metadata = check_media.get_metadata()
|
||||
if(('latitude' in kwargs and 'longitude' in kwargs and check_metadata['latitude'] is None and check_metadata['longitude'] is None) or ('time' in kwargs and check_metadata['date_taken'] is None)):
|
||||
if(constants.debug == True):
|
||||
if(
|
||||
(
|
||||
'latitude' in kwargs and
|
||||
'longitude' in kwargs and
|
||||
check_metadata['latitude'] is None and
|
||||
check_metadata['longitude'] is None
|
||||
) or (
|
||||
'time' in kwargs and
|
||||
check_metadata['date_taken'] is None
|
||||
)
|
||||
):
|
||||
if(constants.debug is True):
|
||||
print 'Something went wrong updating video metadata'
|
||||
return False
|
||||
|
||||
# Copy file information from original source to temporary file before copying back over
|
||||
# Copy file information from original source to temporary file
|
||||
# before copying back over
|
||||
shutil.copystat(source, temp_movie)
|
||||
stat = os.stat(source)
|
||||
shutil.move(temp_movie, source)
|
||||
|
@ -343,6 +410,7 @@ class Video(Media):
|
|||
def get_valid_extensions(Video):
|
||||
return Video.extensions
|
||||
|
||||
|
||||
class Transcode(object):
|
||||
# Constructor takes a video object as it's parameter
|
||||
def __init__(self, video=None):
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Author: Jaisen Mathai <jaisen@jmathai.com>
|
||||
Parse OS X plists.
|
||||
Wraps standard lib plistlib (https://docs.python.org/3/library/plistlib.html)
|
||||
Plist class to parse and interact with a plist file.
|
||||
"""
|
||||
|
||||
# load modules
|
||||
|
@ -9,9 +10,7 @@ from os import path
|
|||
|
||||
import plistlib
|
||||
|
||||
"""
|
||||
Plist class to parse and interact with a plist file.
|
||||
"""
|
||||
|
||||
class Plist(object):
|
||||
def __init__(self, source):
|
||||
if(path.isfile(source) == False):
|
||||
|
|
Loading…
Reference in New Issue