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
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nosetests -w elodie/tests
 | 
					nosetests -w elodie/tests && pep8 elodie --exclude=tests
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,10 @@
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import sys, getopt
 | 
					import getopt
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
from re import sub
 | 
					from re import sub
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse(argv, options, long_options, usage):
 | 
					def parse(argv, options, long_options, usage):
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        opts, args = getopt.getopt(argv, options, long_options)
 | 
					        opts, args = getopt.getopt(argv, options, long_options)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
Author: Jaisen Mathai <jaisen@jmathai.com>
 | 
					Author: Jaisen Mathai <jaisen@jmathai.com>
 | 
				
			||||||
Video package that handles all video operations
 | 
					General file system methods
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
@ -11,14 +11,13 @@ from elodie import geolocation
 | 
				
			|||||||
from elodie import constants
 | 
					from elodie import constants
 | 
				
			||||||
from elodie.localstorage import Db
 | 
					from elodie.localstorage import Db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					
 | 
				
			||||||
General file system methods
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
class FileSystem:
 | 
					class FileSystem:
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create a directory if it does not already exist..
 | 
					    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):
 | 
					    def create_directory(self, directory_path):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
@ -35,10 +34,11 @@ class FileSystem:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Delete a directory only if it's empty.
 | 
					    Delete a directory only if it's empty.
 | 
				
			||||||
    Instead of checking first using `len([name for name in os.listdir(directory_path)]) == 0` 
 | 
					    Instead of checking first using `len([name for name in
 | 
				
			||||||
        we catch the OSError exception.
 | 
					        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):
 | 
					    def delete_directory_if_empty(self, directory_path):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
@ -60,7 +60,10 @@ class FileSystem:
 | 
				
			|||||||
        for dirname, dirnames, filenames in os.walk(path):
 | 
					        for dirname, dirnames, filenames in os.walk(path):
 | 
				
			||||||
            # print path to all filenames.
 | 
					            # print path to all filenames.
 | 
				
			||||||
            for filename in 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))
 | 
					                    files.append('%s/%s' % (dirname, filename))
 | 
				
			||||||
        return files
 | 
					        return files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -75,7 +78,8 @@ class FileSystem:
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    Generate file name for a photo or video using its metadata.
 | 
					    Generate file name for a photo or video using its metadata.
 | 
				
			||||||
    We use an ISO8601-like format for the file name prefix.
 | 
					    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
 | 
					    https://en.wikipedia.org/wiki/ISO_8601#General_principles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @param, media, Photo|Video, A Photo or Video instance
 | 
					    @param, media, Photo|Video, A Photo or Video instance
 | 
				
			||||||
@ -86,21 +90,39 @@ class FileSystem:
 | 
				
			|||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        metadata = media.get_metadata()
 | 
					        metadata = media.get_metadata()
 | 
				
			||||||
        if(metadata == None):
 | 
					        if(metadata is None):
 | 
				
			||||||
            return 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.
 | 
					        # 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. 
 | 
					        # This helps when re-running the program on file which were already
 | 
				
			||||||
        base_name = re.sub('^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}-', '', metadata['base_name'])
 | 
					        #   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):
 | 
					        if(len(base_name) == 0):
 | 
				
			||||||
            base_name = metadata['base_name']
 | 
					            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())
 | 
					            title_sanitized = re.sub('\W+', '-', metadata['title'].strip())
 | 
				
			||||||
            base_name = base_name.replace('-%s' % title_sanitized, '')
 | 
					            base_name = base_name.replace('-%s' % title_sanitized, '')
 | 
				
			||||||
            base_name = '%s-%s' % (base_name, 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()
 | 
					        return file_name.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -125,8 +147,14 @@ class FileSystem:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if(metadata['album'] is not None):
 | 
					        if(metadata['album'] is not None):
 | 
				
			||||||
            path.append(metadata['album'])
 | 
					            path.append(metadata['album'])
 | 
				
			||||||
        elif(metadata['latitude'] is not None and metadata['longitude'] is not None):
 | 
					        elif(
 | 
				
			||||||
            place_name = geolocation.place_name(metadata['latitude'], metadata['longitude'])
 | 
					            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):
 | 
					            if(place_name is not None):
 | 
				
			||||||
                path.append(place_name)
 | 
					                path.append(place_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -134,7 +162,7 @@ class FileSystem:
 | 
				
			|||||||
        if(len(path) < 2):
 | 
					        if(len(path) < 2):
 | 
				
			||||||
            path.append('Unknown Location')
 | 
					            path.append('Unknown Location')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #return '/'.join(path[::-1])
 | 
					        # return '/'.join(path[::-1])
 | 
				
			||||||
        return '/'.join(path)
 | 
					        return '/'.join(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def process_file(self, _file, destination, media, **kwargs):
 | 
					    def process_file(self, _file, destination, media, **kwargs):
 | 
				
			||||||
@ -156,20 +184,24 @@ class FileSystem:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        db = Db()
 | 
					        db = Db()
 | 
				
			||||||
        checksum = db.checksum(_file)
 | 
					        checksum = db.checksum(_file)
 | 
				
			||||||
        if(checksum == None):
 | 
					        if(checksum is None):
 | 
				
			||||||
            if(constants.debug == True):
 | 
					            if(constants.debug is True):
 | 
				
			||||||
                print 'Could not get checksum for %s. Skipping...' % _file
 | 
					                print 'Could not get checksum for %s. Skipping...' % _file
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If duplicates are not allowed and this hash exists in the db then we return
 | 
					        # If duplicates are not allowed and this hash exists in the db then we
 | 
				
			||||||
        if(allowDuplicate == False and db.check_hash(checksum) == True):
 | 
					        #   return
 | 
				
			||||||
            if(constants.debug == True):
 | 
					        if(allowDuplicate is False and db.check_hash(checksum) is True):
 | 
				
			||||||
                print '%s already exists at %s. Skipping...' % (_file, db.get_hash(checksum))
 | 
					            if(constants.debug is True):
 | 
				
			||||||
 | 
					                print '%s already exists at %s. Skipping...' % (
 | 
				
			||||||
 | 
					                    _file,
 | 
				
			||||||
 | 
					                    db.get_hash(checksum)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.create_directory(dest_directory)
 | 
					        self.create_directory(dest_directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(move == True):
 | 
					        if(move is True):
 | 
				
			||||||
            stat = os.stat(_file)
 | 
					            stat = os.stat(_file)
 | 
				
			||||||
            shutil.move(_file, dest_path)
 | 
					            shutil.move(_file, dest_path)
 | 
				
			||||||
            os.utime(dest_path, (stat.st_atime, stat.st_mtime))
 | 
					            os.utime(dest_path, (stat.st_atime, stat.st_mtime))
 | 
				
			||||||
@ -191,22 +223,34 @@ class FileSystem:
 | 
				
			|||||||
        video_file_path = video.get_file_path()
 | 
					        video_file_path = video.get_file_path()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Initialize date taken to what's returned from the metadata function.
 | 
					        # 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
 | 
					        (year, month, day) = [None] * 3
 | 
				
			||||||
        directory = os.path.dirname(video_file_path)
 | 
					        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)
 | 
					        year_month_match = re.search('(\d{4})-(\d{2})', directory)
 | 
				
			||||||
        if(year_month_match is not None):
 | 
					        if(year_month_match is not None):
 | 
				
			||||||
            (year, month) = year_month_match.groups()
 | 
					            (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):
 | 
					        if(day_match is not None):
 | 
				
			||||||
            day = day_match.group(1)
 | 
					            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(year is not None and month is not None):
 | 
				
			||||||
            if(day 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:
 | 
					            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)))
 | 
					            os.utime(video_file_path, (time.time(), time.mktime(date_taken)))
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import urllib
 | 
				
			|||||||
from elodie import constants
 | 
					from elodie import constants
 | 
				
			||||||
from elodie.localstorage import Db
 | 
					from elodie.localstorage import Db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Fraction(fractions.Fraction):
 | 
					class Fraction(fractions.Fraction):
 | 
				
			||||||
    """Only create Fractions from floats.
 | 
					    """Only create Fractions from floats.
 | 
				
			||||||
    >>> Fraction(0.3)
 | 
					    >>> Fraction(0.3)
 | 
				
			||||||
@ -22,6 +23,7 @@ class Fraction(fractions.Fraction):
 | 
				
			|||||||
        """Should be compatible with Python 2.6, though untested."""
 | 
					        """Should be compatible with Python 2.6, though untested."""
 | 
				
			||||||
        return fractions.Fraction.from_float(value).limit_denominator(99999)
 | 
					        return fractions.Fraction.from_float(value).limit_denominator(99999)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def coordinates_by_name(name):
 | 
					def coordinates_by_name(name):
 | 
				
			||||||
    # Try to get cached location first
 | 
					    # Try to get cached location first
 | 
				
			||||||
    db = Db()
 | 
					    db = Db()
 | 
				
			||||||
@ -36,15 +38,27 @@ def coordinates_by_name(name):
 | 
				
			|||||||
    geolocation_info = lookup(name)
 | 
					    geolocation_info = lookup(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(geolocation_info is not None):
 | 
					    if(geolocation_info is not None):
 | 
				
			||||||
        if('results' in geolocation_info and len(geolocation_info['results']) != 0 and 
 | 
					        if(
 | 
				
			||||||
                'locations' in geolocation_info['results'][0] and len(geolocation_info['results'][0]['locations']) != 0):
 | 
					            '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.
 | 
					            # By default we use the first entry unless we find one with
 | 
				
			||||||
            use_location = geolocation_info['results'][0]['locations'][0]['latLng']
 | 
					            #   geocodeQuality=city.
 | 
				
			||||||
            # Loop over the locations to see if we come accross a 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
 | 
					            # If we find a city we set that to the use_location and break
 | 
				
			||||||
            for location in geolocation_info['results'][0]['locations']:
 | 
					            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'):
 | 
					                if(
 | 
				
			||||||
 | 
					                    'latLng' in location and
 | 
				
			||||||
 | 
					                    'lat' in location['latLng'] and
 | 
				
			||||||
 | 
					                    'lng' in location['latLng'] and
 | 
				
			||||||
 | 
					                    location['geocodeQuality'].lower() == 'city'
 | 
				
			||||||
 | 
					                ):
 | 
				
			||||||
                    use_location = location['latLng']
 | 
					                    use_location = location['latLng']
 | 
				
			||||||
                    break
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -55,33 +69,42 @@ def coordinates_by_name(name):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return None
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def decimal_to_dms(decimal, signed=True):
 | 
					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
 | 
					    sign = 1
 | 
				
			||||||
    if(decimal < 0):
 | 
					    if(decimal < 0):
 | 
				
			||||||
        sign = -1
 | 
					        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)
 | 
					    degrees = int(decimal)
 | 
				
			||||||
    subminutes = abs((decimal - int(decimal)) * 60)
 | 
					    subminutes = abs((decimal - int(decimal)) * 60)
 | 
				
			||||||
    minutes = int(subminutes) * sign
 | 
					    minutes = int(subminutes) * sign
 | 
				
			||||||
    subseconds = abs((subminutes - int(subminutes)) * 60) * sign
 | 
					    subseconds = abs((subminutes - int(subminutes)) * 60) * sign
 | 
				
			||||||
    subseconds_fraction = Fraction(subseconds)
 | 
					    subseconds_fraction = Fraction(subseconds)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(signed == False):
 | 
					    if(signed is False):
 | 
				
			||||||
        degrees = abs(degrees)
 | 
					        degrees = abs(degrees)
 | 
				
			||||||
        minutes = abs(minutes)
 | 
					        minutes = abs(minutes)
 | 
				
			||||||
        subseconds_fraction = Fraction(abs(subseconds))
 | 
					        subseconds_fraction = Fraction(abs(subseconds))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (pyexiv2.Rational(degrees, 1), pyexiv2.Rational(minutes, 1), pyexiv2.Rational(subseconds_fraction.numerator, subseconds_fraction.denominator))
 | 
					    return (
 | 
				
			||||||
 | 
					        pyexiv2.Rational(degrees, 1),
 | 
				
			||||||
def dms_to_decimal(degrees, minutes, seconds, sign=' '):
 | 
					        pyexiv2.Rational(minutes, 1),
 | 
				
			||||||
    return (-1 if sign[0] in 'SWsw' else 1) * (
 | 
					        pyexiv2.Rational(subseconds_fraction.numerator, subseconds_fraction.denominator)  # noqa
 | 
				
			||||||
        float(degrees)        +
 | 
					 | 
				
			||||||
        float(minutes) / 60   +
 | 
					 | 
				
			||||||
        float(seconds) / 3600
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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():
 | 
					def get_key():
 | 
				
			||||||
    config_file = '%s/config.ini' % constants.application_directory
 | 
					    config_file = '%s/config.ini' % constants.application_directory
 | 
				
			||||||
    if not path.exists(config_file):
 | 
					    if not path.exists(config_file):
 | 
				
			||||||
@ -94,16 +117,17 @@ def get_key():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return config.get('MapQuest', 'key')
 | 
					    return config.get('MapQuest', 'key')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def place_name(lat, lon):
 | 
					def place_name(lat, lon):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Try to get cached location first
 | 
					    # Try to get cached location first
 | 
				
			||||||
    db = Db()
 | 
					    db = Db()
 | 
				
			||||||
    # 3km distace radious for a match
 | 
					    # 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):
 | 
					    if(cached_place_name is not None):
 | 
				
			||||||
        return cached_place_name
 | 
					        return cached_place_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    lookup_place_name = None;
 | 
					    lookup_place_name = None
 | 
				
			||||||
    geolocation_info = reverse_lookup(lat, lon)
 | 
					    geolocation_info = reverse_lookup(lat, lon)
 | 
				
			||||||
    if(geolocation_info is not None):
 | 
					    if(geolocation_info is not None):
 | 
				
			||||||
        if('address' in geolocation_info):
 | 
					        if('address' in geolocation_info):
 | 
				
			||||||
@ -130,18 +154,22 @@ def reverse_lookup(lat, lon):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        params = {'format': 'json', 'key': key, 'lat': lat, 'lon': lon}
 | 
					        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()
 | 
					        return r.json()
 | 
				
			||||||
    except requests.exceptions.RequestException as e:
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
        if(constants.debug == True):
 | 
					        if(constants.debug is True):
 | 
				
			||||||
            print e
 | 
					            print e
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
    except ValueError as e:
 | 
					    except ValueError as e:
 | 
				
			||||||
        if(constants.debug == True):
 | 
					        if(constants.debug is True):
 | 
				
			||||||
            print r.text
 | 
					            print r.text
 | 
				
			||||||
            print e
 | 
					            print e
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def lookup(name):
 | 
					def lookup(name):
 | 
				
			||||||
    if(name is None or len(name) == 0):
 | 
					    if(name is None or len(name) == 0):
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
@ -150,16 +178,19 @@ def lookup(name):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        params = {'format': 'json', 'key': key, 'location': name}
 | 
					        params = {'format': 'json', 'key': key, 'location': name}
 | 
				
			||||||
        if(constants.debug == True):
 | 
					        if(constants.debug is True):
 | 
				
			||||||
            print 'http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params)
 | 
					            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))
 | 
					        r = requests.get(
 | 
				
			||||||
 | 
					            'http://open.mapquestapi.com/geocoding/v1/address?%s' %
 | 
				
			||||||
 | 
					            urllib.urlencode(params)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        return r.json()
 | 
					        return r.json()
 | 
				
			||||||
    except requests.exceptions.RequestException as e:
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
        if(constants.debug == True):
 | 
					        if(constants.debug is True):
 | 
				
			||||||
            print e
 | 
					            print e
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
    except ValueError as e:
 | 
					    except ValueError as e:
 | 
				
			||||||
        if(constants.debug == True):
 | 
					        if(constants.debug is True):
 | 
				
			||||||
            print r.text
 | 
					            print r.text
 | 
				
			||||||
            print e
 | 
					            print e
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
				
			|||||||
@ -6,9 +6,11 @@ import sys
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from elodie import constants
 | 
					from elodie import constants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Db(object):
 | 
					class Db(object):
 | 
				
			||||||
    def __init__(self):
 | 
					    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):
 | 
					        if not os.path.exists(constants.application_directory):
 | 
				
			||||||
            os.makedirs(constants.application_directory)
 | 
					            os.makedirs(constants.application_directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -20,7 +22,8 @@ class Db(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.hash_db = {}
 | 
					        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:
 | 
					        with open(constants.hash_db, 'r') as f:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                self.hash_db = json.load(f)
 | 
					                self.hash_db = json.load(f)
 | 
				
			||||||
@ -35,7 +38,8 @@ class Db(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.location_db = []
 | 
					        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:
 | 
					        with open(constants.location_db, 'r') as f:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                self.location_db = json.load(f)
 | 
					                self.location_db = json.load(f)
 | 
				
			||||||
@ -44,14 +48,14 @@ class Db(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def add_hash(self, key, value, write=False):
 | 
					    def add_hash(self, key, value, write=False):
 | 
				
			||||||
        self.hash_db[key] = value
 | 
					        self.hash_db[key] = value
 | 
				
			||||||
        if(write == True):
 | 
					        if(write is True):
 | 
				
			||||||
            self.update_hash_db()
 | 
					            self.update_hash_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_hash(self, key):
 | 
					    def check_hash(self, key):
 | 
				
			||||||
        return key in self.hash_db
 | 
					        return key in self.hash_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_hash(self, key):
 | 
					    def get_hash(self, key):
 | 
				
			||||||
        if(self.check_hash(key) == True):
 | 
					        if(self.check_hash(key) is True):
 | 
				
			||||||
            return self.hash_db[key]
 | 
					            return self.hash_db[key]
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -88,27 +92,29 @@ class Db(object):
 | 
				
			|||||||
        data['long'] = longitude
 | 
					        data['long'] = longitude
 | 
				
			||||||
        data['name'] = place
 | 
					        data['name'] = place
 | 
				
			||||||
        self.location_db.append(data)
 | 
					        self.location_db.append(data)
 | 
				
			||||||
        if(write == True):
 | 
					        if(write is True):
 | 
				
			||||||
            self.update_location_db()
 | 
					            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
 | 
					        last_d = sys.maxint
 | 
				
			||||||
        name = None
 | 
					        name = None
 | 
				
			||||||
        for data in self.location_db:
 | 
					        for data in self.location_db:
 | 
				
			||||||
            # As threshold is quite smal use simple math
 | 
					            # 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
 | 
					            # 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
 | 
					            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
 | 
					            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
 | 
					            # Use if closer then threshold_km reuse lookup
 | 
				
			||||||
            if(d <= threshold_m and d < last_d):
 | 
					            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
 | 
					            last_d = d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return name
 | 
					        return name
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
Author: Jaisen Mathai <jaisen@jmathai.com>
 | 
					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
 | 
					# load modules
 | 
				
			||||||
@ -17,9 +17,7 @@ import re
 | 
				
			|||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					
 | 
				
			||||||
Media class for general video operations
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
class Media(object):
 | 
					class Media(object):
 | 
				
			||||||
    # class / static variable accessible through get_valid_extensions()
 | 
					    # class / static variable accessible through get_valid_extensions()
 | 
				
			||||||
    __name__ = 'Media'
 | 
					    __name__ = 'Media'
 | 
				
			||||||
@ -30,7 +28,7 @@ class Media(object):
 | 
				
			|||||||
    def __init__(self, source=None):
 | 
					    def __init__(self, source=None):
 | 
				
			||||||
        self.source = source
 | 
					        self.source = source
 | 
				
			||||||
        self.exif_map = {
 | 
					        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': 'Exif.GPSInfo.GPSLatitude',
 | 
				
			||||||
            'latitude_ref': 'Exif.GPSInfo.GPSLatitudeRef',
 | 
					            'latitude_ref': 'Exif.GPSInfo.GPSLatitudeRef',
 | 
				
			||||||
            'longitude': 'Exif.GPSInfo.GPSLongitude',
 | 
					            'longitude': 'Exif.GPSInfo.GPSLongitude',
 | 
				
			||||||
@ -65,12 +63,11 @@ class Media(object):
 | 
				
			|||||||
        # If exiftool wasn't found we try to brute force the homebrew location
 | 
					        # If exiftool wasn't found we try to brute force the homebrew location
 | 
				
			||||||
        if(exiftool is None):
 | 
					        if(exiftool is None):
 | 
				
			||||||
            exiftool = '/usr/local/bin/exiftool'
 | 
					            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 None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return exiftool
 | 
					        return exiftool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Get the full path to the video.
 | 
					    Get the full path to the video.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -88,7 +85,8 @@ class Media(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Read EXIF from a photo file.
 | 
					    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
 | 
					    @returns, list or none for a non-photo file
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -114,7 +112,11 @@ class Media(object):
 | 
				
			|||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        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()
 | 
					        output = process_output.stdout.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Get album from exiftool output
 | 
					        # Get album from exiftool output
 | 
				
			||||||
@ -131,7 +133,7 @@ class Media(object):
 | 
				
			|||||||
                title_return = title_regex.group(1).strip()
 | 
					                title_return = title_regex.group(1).strip()
 | 
				
			||||||
                if(len(title_return) > 0):
 | 
					                if(len(title_return) > 0):
 | 
				
			||||||
                    title = title_return
 | 
					                    title = title_return
 | 
				
			||||||
                    break;
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.exiftool_attributes = {
 | 
					        self.exiftool_attributes = {
 | 
				
			||||||
            'album': album,
 | 
					            'album': album,
 | 
				
			||||||
@ -140,7 +142,6 @@ class Media(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return self.exiftool_attributes
 | 
					        return self.exiftool_attributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Get the file extension as a lowercased string.
 | 
					    Get the file extension as a lowercased string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -163,7 +164,7 @@ class Media(object):
 | 
				
			|||||||
        if(not self.is_valid()):
 | 
					        if(not self.is_valid()):
 | 
				
			||||||
            return None
 | 
					            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
 | 
					            return self.metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
@ -193,7 +194,7 @@ class Media(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
        mimetype = mimetypes.guess_type(source)
 | 
					        mimetype = mimetypes.guess_type(source)
 | 
				
			||||||
        if(mimetype == None):
 | 
					        if(mimetype is None):
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mimetype[0]
 | 
					        return mimetype[0]
 | 
				
			||||||
@ -232,9 +233,14 @@ class Media(object):
 | 
				
			|||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
        stat = os.stat(source)
 | 
					        stat = os.stat(source)
 | 
				
			||||||
        exiftool_config = constants.exiftool_config
 | 
					        exiftool_config = constants.exiftool_config
 | 
				
			||||||
        if(constants.debug == True):
 | 
					        if(constants.debug is True):
 | 
				
			||||||
            print '%s -config "%s" -xmp-elodie:Album="%s" "%s"' % (exiftool, exiftool_config, name, source)
 | 
					            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)
 | 
					        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]
 | 
					        streamdata = process_output.communicate()[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(process_output.returncode != 0):
 | 
					        if(process_output.returncode != 0):
 | 
				
			||||||
@ -266,14 +272,16 @@ class Media(object):
 | 
				
			|||||||
        self.set_album(folder)
 | 
					        self.set_album(folder)
 | 
				
			||||||
        return True
 | 
					        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.
 | 
					    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
 | 
					    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):
 | 
					    def set_metadata_basename(self, new_basename):
 | 
				
			||||||
        self.get_metadata()
 | 
					        self.get_metadata()
 | 
				
			||||||
 | 
				
			|||||||
@ -20,9 +20,7 @@ from elodie import constants
 | 
				
			|||||||
from media import Media
 | 
					from media import Media
 | 
				
			||||||
from elodie import geolocation
 | 
					from elodie import geolocation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					
 | 
				
			||||||
Photo class for general photo operations
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
class Photo(Media):
 | 
					class Photo(Media):
 | 
				
			||||||
    __name__ = 'Photo'
 | 
					    __name__ = 'Photo'
 | 
				
			||||||
    extensions = ('jpg', 'jpeg', 'nef', 'dng', 'gif')
 | 
					    extensions = ('jpg', 'jpeg', 'nef', 'dng', 'gif')
 | 
				
			||||||
@ -47,11 +45,17 @@ class Photo(Media):
 | 
				
			|||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
        result = subprocess.Popen(['ffprobe', source],
 | 
					        result = subprocess.Popen(
 | 
				
			||||||
            stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
 | 
					            ['ffprobe', source],
 | 
				
			||||||
 | 
					            stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					            stderr=subprocess.STDOUT
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        for key in result.stdout.readlines():
 | 
					        for key in result.stdout.readlines():
 | 
				
			||||||
            if 'Duration' in key:
 | 
					            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
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -63,26 +67,40 @@ class Photo(Media):
 | 
				
			|||||||
        if(not self.is_valid()):
 | 
					        if(not self.is_valid()):
 | 
				
			||||||
            return None
 | 
					            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()
 | 
					        exif = self.get_exif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(key not in exif):
 | 
					        if(key not in exif):
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        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
 | 
					            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
 | 
					                latdir = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            londir = 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
 | 
					                londir = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            coords = exif[key].value
 | 
					            coords = exif[key].value
 | 
				
			||||||
            if(type == 'latitude'):
 | 
					            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:
 | 
					            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:
 | 
					        except KeyError:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,21 +115,23 @@ class Photo(Media):
 | 
				
			|||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        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.
 | 
					        # 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
 | 
					        # EXIF DateTimeOriginal and EXIF DateTime are both stored
 | 
				
			||||||
        # we use date.strptime -> .timetuple -> time.mktime to do the conversion in the local timezone
 | 
					        #   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
 | 
					        # 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()
 | 
					        exif = self.get_exif()
 | 
				
			||||||
        for key in self.exif_map['date_taken']:
 | 
					        for key in self.exif_map['date_taken']:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                if(key in exif):
 | 
					                if(key in exif):
 | 
				
			||||||
                    if(re.match('\d{4}(-|:)\d{2}(-|:)\d{2}', str(exif[key].value)) is not None):
 | 
					                    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())
 | 
					                        seconds_since_epoch = time.mktime(exif[key].value.timetuple())  # noqa
 | 
				
			||||||
                        break;
 | 
					                        break
 | 
				
			||||||
            except BaseException as e:
 | 
					            except BaseException as e:
 | 
				
			||||||
                if(constants.debug == True):
 | 
					                if(constants.debug is True):
 | 
				
			||||||
                    print e
 | 
					                    print e
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,7 +141,8 @@ class Photo(Media):
 | 
				
			|||||||
        return time.gmtime(seconds_since_epoch)
 | 
					        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
 | 
					    @returns, boolean
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -131,7 +152,7 @@ class Photo(Media):
 | 
				
			|||||||
        # gh-4 This checks if the source file is an image.
 | 
					        # gh-4 This checks if the source file is an image.
 | 
				
			||||||
        # It doesn't validate against the list of supported types.
 | 
					        # It doesn't validate against the list of supported types.
 | 
				
			||||||
        if(imghdr.what(source) is None):
 | 
					        if(imghdr.what(source) is None):
 | 
				
			||||||
            return False;
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return os.path.splitext(source)[1][1:].lower() in self.extensions
 | 
					        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 = pyexiv2.ImageMetadata(source)
 | 
				
			||||||
        exif_metadata.read()
 | 
					        exif_metadata.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        exif_metadata['Exif.GPSInfo.GPSLatitude'] = geolocation.decimal_to_dms(latitude, False)
 | 
					        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')
 | 
					        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)
 | 
					        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')
 | 
					        exif_metadata['Exif.GPSInfo.GPSLongitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLongitudeRef', 'E' if longitude >= 0 else 'W')  # noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        exif_metadata.write()
 | 
					        exif_metadata.write()
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
				
			|||||||
@ -20,12 +20,10 @@ from elodie import constants
 | 
				
			|||||||
from elodie import plist_parser
 | 
					from elodie import plist_parser
 | 
				
			||||||
from media import Media
 | 
					from media import Media
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					
 | 
				
			||||||
Video class for general video operations
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
class Video(Media):
 | 
					class Video(Media):
 | 
				
			||||||
    __name__ = 'Video'
 | 
					    __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
 | 
					    @param, source, string, The fully qualified path to the video file
 | 
				
			||||||
@ -43,12 +41,11 @@ class Video(Media):
 | 
				
			|||||||
        avmetareadwrite = find_executable('avmetareadwrite')
 | 
					        avmetareadwrite = find_executable('avmetareadwrite')
 | 
				
			||||||
        if(avmetareadwrite is None):
 | 
					        if(avmetareadwrite is None):
 | 
				
			||||||
            avmetareadwrite = '/usr/bin/avmetareadwrite'
 | 
					            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 None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return avmetareadwrite
 | 
					        return avmetareadwrite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Get latitude or longitude of photo from EXIF
 | 
					    Get latitude or longitude of photo from EXIF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -71,7 +68,7 @@ class Video(Media):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        direction = direction.group(0)
 | 
					        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'):
 | 
					        if(direction == 'S' or direction == 'W'):
 | 
				
			||||||
            decimal_degrees = decimal_degrees * -1
 | 
					            decimal_degrees = decimal_degrees * -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,9 +86,10 @@ class Video(Media):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
        # We need to parse a string from EXIF into a timestamp.
 | 
					        # 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
 | 
					        # 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
 | 
					        time_found_in_exif = False
 | 
				
			||||||
        exif_data = self.get_exif()
 | 
					        exif_data = self.get_exif()
 | 
				
			||||||
        for key in ['Creation Date', 'Media Create Date']:
 | 
					        for key in ['Creation Date', 'Media Create Date']:
 | 
				
			||||||
@ -99,7 +97,12 @@ class Video(Media):
 | 
				
			|||||||
            if(date is not None):
 | 
					            if(date is not None):
 | 
				
			||||||
                date_string = date.group(1)
 | 
					                date_string = date.group(1)
 | 
				
			||||||
                try:
 | 
					                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):
 | 
					                    if(exif_seconds_since_epoch < seconds_since_epoch):
 | 
				
			||||||
                        seconds_since_epoch = exif_seconds_since_epoch
 | 
					                        seconds_since_epoch = exif_seconds_since_epoch
 | 
				
			||||||
                        time_found_in_exif = True
 | 
					                        time_found_in_exif = True
 | 
				
			||||||
@ -123,16 +126,23 @@ class Video(Media):
 | 
				
			|||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
        result = subprocess.Popen(['ffprobe', source],
 | 
					        result = subprocess.Popen(
 | 
				
			||||||
            stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
 | 
					            ['ffprobe', source],
 | 
				
			||||||
 | 
					            stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					            stderr=subprocess.STDOUT
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        for key in result.stdout.readlines():
 | 
					        for key in result.stdout.readlines():
 | 
				
			||||||
            if 'Duration' in key:
 | 
					            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
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Get exif data from video file.
 | 
					    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
 | 
					    @returns, string or None if exiftool is not found
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -142,11 +152,16 @@ class Video(Media):
 | 
				
			|||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        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()
 | 
					        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
 | 
					    @returns, boolean
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -168,8 +183,14 @@ class Video(Media):
 | 
				
			|||||||
        source = self.source
 | 
					        source = self.source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = self.__update_using_plist(time=date_taken_as_datetime)
 | 
					        result = self.__update_using_plist(time=date_taken_as_datetime)
 | 
				
			||||||
        if(result == True):
 | 
					        if(result is True):
 | 
				
			||||||
            os.utime(source, (int(time.time()), time.mktime(date_taken_as_datetime.timetuple())))
 | 
					            os.utime(
 | 
				
			||||||
 | 
					                source,
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    int(time.time()),
 | 
				
			||||||
 | 
					                    time.mktime(date_taken_as_datetime.timetuple())
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return result
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -185,7 +206,7 @@ class Video(Media):
 | 
				
			|||||||
        if(latitude is None or longitude is None):
 | 
					        if(latitude is None or longitude is None):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = self.__update_using_plist(latitude=latitude, longitude=longitude)
 | 
					        result = self.__update_using_plist(latitude=latitude, longitude=longitude)  # noqa
 | 
				
			||||||
        return result
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@ -210,9 +231,11 @@ class Video(Media):
 | 
				
			|||||||
    1) Check if avmetareadwrite is installed
 | 
					    1) Check if avmetareadwrite is installed
 | 
				
			||||||
    2) Export a plist file to a temporary location from the source file
 | 
					    2) Export a plist file to a temporary location from the source file
 | 
				
			||||||
    3) Regex replace values in the plist 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
 | 
					    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
 | 
					    7) Move the temporary file to overwrite the source file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @param, latitude, float, Latitude of the file
 | 
					    @param, latitude, float, Latitude of the file
 | 
				
			||||||
@ -221,33 +244,49 @@ class Video(Media):
 | 
				
			|||||||
    @returns, boolean
 | 
					    @returns, boolean
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def __update_using_plist(self, **kwargs):
 | 
					    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(
 | 
				
			||||||
            if(constants.debug == True):
 | 
					            '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'
 | 
					                print 'No lat/lon passed into __create_plist'
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        avmetareadwrite = self.get_avmetareadwrite()
 | 
					        avmetareadwrite = self.get_avmetareadwrite()
 | 
				
			||||||
        if(avmetareadwrite is None):
 | 
					        if(avmetareadwrite is None):
 | 
				
			||||||
            if(constants.debug == True):
 | 
					            if(constants.debug is True):
 | 
				
			||||||
                print 'Could not find avmetareadwrite'
 | 
					                print 'Could not find avmetareadwrite'
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        source = self.source
 | 
					        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:
 | 
					        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
 | 
					            # http://stackoverflow.com/a/5631819/1318758
 | 
				
			||||||
            avmetareadwrite_generate_plist_command = '%s -p "%s" "%s"' % (avmetareadwrite, plist_temp.name, source)
 | 
					            avmetareadwrite_generate_plist_command = '%s -p "%s" "%s"' % (
 | 
				
			||||||
            write_process = subprocess.Popen([avmetareadwrite_generate_plist_command], stdout=subprocess.PIPE, shell=True)
 | 
					                avmetareadwrite,
 | 
				
			||||||
 | 
					                plist_temp.name,
 | 
				
			||||||
 | 
					                source
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            write_process = subprocess.Popen(
 | 
				
			||||||
 | 
					                [avmetareadwrite_generate_plist_command],
 | 
				
			||||||
 | 
					                stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					                shell=True
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            streamdata = write_process.communicate()[0]
 | 
					            streamdata = write_process.communicate()[0]
 | 
				
			||||||
            if(write_process.returncode != 0):
 | 
					            if(write_process.returncode != 0):
 | 
				
			||||||
                if(constants.debug == True):
 | 
					                if(constants.debug is True):
 | 
				
			||||||
                    print 'Failed to generate plist file'
 | 
					                    print 'Failed to generate plist file'
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            plist = plist_parser.Plist(plist_temp.name)
 | 
					            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
 | 
					            plist_should_be_written = False
 | 
				
			||||||
            if('latitude' in kwargs and 'longitude' in kwargs):
 | 
					            if('latitude' in kwargs and 'longitude' in kwargs):
 | 
				
			||||||
                latitude = str(abs(kwargs['latitude'])).lstrip('0')
 | 
					                latitude = str(abs(kwargs['latitude'])).lstrip('0')
 | 
				
			||||||
@ -258,10 +297,16 @@ class Video(Media):
 | 
				
			|||||||
                lat_sign = '+' if latitude > 0 else '-'
 | 
					                lat_sign = '+' if latitude > 0 else '-'
 | 
				
			||||||
                # We need to zeropad the longitude.
 | 
					                # We need to zeropad the longitude.
 | 
				
			||||||
                # No clue why - ask Apple.
 | 
					                # 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 '-'
 | 
					                lon_sign = '+' if longitude > 0 else '-'
 | 
				
			||||||
                longitude_str = '{:9.5f}'.format(abs(longitude)).replace(' ', '0')
 | 
					                longitude_str = '{:9.5f}'.format(abs(longitude)).replace(' ', '0')  # noqa
 | 
				
			||||||
                lat_lon_str = '%s%s%s%s' % (lat_sign, latitude, lon_sign, longitude_str)
 | 
					                lat_lon_str = '%s%s%s%s' % (
 | 
				
			||||||
 | 
					                    lat_sign,
 | 
				
			||||||
 | 
					                    latitude,
 | 
				
			||||||
 | 
					                    lon_sign,
 | 
				
			||||||
 | 
					                    longitude_str
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                plist.update_key('common/location', lat_lon_str)
 | 
					                plist.update_key('common/location', lat_lon_str)
 | 
				
			||||||
                plist_should_be_written = True
 | 
					                plist_should_be_written = True
 | 
				
			||||||
@ -277,13 +322,12 @@ class Video(Media):
 | 
				
			|||||||
                        hms = [int(x) for x in time_parts[1].split(':')]
 | 
					                        hms = [int(x) for x in time_parts[1].split(':')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if(hms is not None):
 | 
					                    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:
 | 
					                    else:
 | 
				
			||||||
                        d = datetime(ymd[0], ymd[1], ymd[2], 12, 00, 00)
 | 
					                        d = datetime(ymd[0], ymd[1], ymd[2], 12, 00, 00)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    offset = time.strftime("%z", time.gmtime(time.time()))
 | 
					                    offset = time.strftime("%z", time.gmtime(time.time()))
 | 
				
			||||||
                    time_string = d.strftime('%Y-%m-%dT%H:%M:%S{}'.format(offset))
 | 
					                    time_string = d.strftime('%Y-%m-%dT%H:%M:%S{}'.format(offset))  # noqa
 | 
				
			||||||
                    #2015-10-09T17:11:30-0700
 | 
					 | 
				
			||||||
                    plist.update_key('common/creationDate', time_string)
 | 
					                    plist.update_key('common/creationDate', time_string)
 | 
				
			||||||
                    plist_should_be_written = True
 | 
					                    plist_should_be_written = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -296,13 +340,15 @@ class Video(Media):
 | 
				
			|||||||
                plist_final = plist_temp.name
 | 
					                plist_final = plist_temp.name
 | 
				
			||||||
                plist.write_file(plist_final)
 | 
					                plist.write_file(plist_final)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                if(constants.debug == True):
 | 
					                if(constants.debug is True):
 | 
				
			||||||
                    print 'Nothing to update, plist unchanged'
 | 
					                    print 'Nothing to update, plist unchanged'
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # We create a temporary file to save the modified file to.
 | 
					            # We create a temporary file to save the modified file to.
 | 
				
			||||||
            # If the modification is successful we will update the existing file.
 | 
					            # If the modification is successful we will update the
 | 
				
			||||||
            # We can't call self.get_metadata else we will run into infinite loops
 | 
					            #   existing file.
 | 
				
			||||||
 | 
					            # We can't call self.get_metadata else we will run into
 | 
				
			||||||
 | 
					            #   infinite loops
 | 
				
			||||||
            # metadata = self.get_metadata()
 | 
					            # metadata = self.get_metadata()
 | 
				
			||||||
            temp_movie = None
 | 
					            temp_movie = None
 | 
				
			||||||
            with tempfile.NamedTemporaryFile() as temp_file:
 | 
					            with tempfile.NamedTemporaryFile() as temp_file:
 | 
				
			||||||
@ -310,23 +356,44 @@ class Video(Media):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            # We need to block until the child process completes.
 | 
					            # We need to block until the child process completes.
 | 
				
			||||||
            # http://stackoverflow.com/a/5631819/1318758
 | 
					            # http://stackoverflow.com/a/5631819/1318758
 | 
				
			||||||
            avmetareadwrite_command = '%s -a %s "%s" "%s"' % (avmetareadwrite, plist_final, source, temp_movie)
 | 
					            avmetareadwrite_command = '%s -a %s "%s" "%s"' % (
 | 
				
			||||||
            update_process = subprocess.Popen([avmetareadwrite_command], stdout=subprocess.PIPE, shell=True)
 | 
					                avmetareadwrite,
 | 
				
			||||||
 | 
					                plist_final,
 | 
				
			||||||
 | 
					                source,
 | 
				
			||||||
 | 
					                temp_movie
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            update_process = subprocess.Popen(
 | 
				
			||||||
 | 
					                [avmetareadwrite_command],
 | 
				
			||||||
 | 
					                stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					                shell=True
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            streamdata = update_process.communicate()[0]
 | 
					            streamdata = update_process.communicate()[0]
 | 
				
			||||||
            if(update_process.returncode != 0):
 | 
					            if(update_process.returncode != 0):
 | 
				
			||||||
                if(constants.debug == True):
 | 
					                if(constants.debug is True):
 | 
				
			||||||
                    print '%s did not complete successfully' % avmetareadwrite_command
 | 
					                    print '%s did not complete successfully' % avmetareadwrite_command  # noqa
 | 
				
			||||||
                return False
 | 
					                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_media = Video(temp_movie)
 | 
				
			||||||
            check_metadata = check_media.get_metadata()
 | 
					            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(
 | 
				
			||||||
                if(constants.debug == True):
 | 
					                (
 | 
				
			||||||
 | 
					                    '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'
 | 
					                    print 'Something went wrong updating video metadata'
 | 
				
			||||||
                return False
 | 
					                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)
 | 
					            shutil.copystat(source, temp_movie)
 | 
				
			||||||
            stat = os.stat(source)
 | 
					            stat = os.stat(source)
 | 
				
			||||||
            shutil.move(temp_movie, source)
 | 
					            shutil.move(temp_movie, source)
 | 
				
			||||||
@ -343,6 +410,7 @@ class Video(Media):
 | 
				
			|||||||
    def get_valid_extensions(Video):
 | 
					    def get_valid_extensions(Video):
 | 
				
			||||||
        return Video.extensions
 | 
					        return Video.extensions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Transcode(object):
 | 
					class Transcode(object):
 | 
				
			||||||
    # Constructor takes a video object as it's parameter
 | 
					    # Constructor takes a video object as it's parameter
 | 
				
			||||||
    def __init__(self, video=None):
 | 
					    def __init__(self, video=None):
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
Author: Jaisen Mathai <jaisen@jmathai.com>
 | 
					Author: Jaisen Mathai <jaisen@jmathai.com>
 | 
				
			||||||
Parse OS X plists.
 | 
					Parse OS X plists.
 | 
				
			||||||
Wraps standard lib plistlib (https://docs.python.org/3/library/plistlib.html)
 | 
					Wraps standard lib plistlib (https://docs.python.org/3/library/plistlib.html)
 | 
				
			||||||
 | 
					Plist class to parse and interact with a plist file.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# load modules
 | 
					# load modules
 | 
				
			||||||
@ -9,9 +10,7 @@ from os import path
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import plistlib
 | 
					import plistlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					
 | 
				
			||||||
Plist class to parse and interact with a plist file.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
class Plist(object):
 | 
					class Plist(object):
 | 
				
			||||||
    def __init__(self, source):
 | 
					    def __init__(self, source):
 | 
				
			||||||
        if(path.isfile(source) == False):
 | 
					        if(path.isfile(source) == False):
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user