Added FileSystem.process_file and adjust.py
This commit is contained in:
		
							parent
							
								
									35de02ba6f
								
							
						
					
					
						commit
						ad62b0d61d
					
				
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@ -6,3 +6,15 @@ pip install requests
 | 
				
			|||||||
brew install exiftool
 | 
					brew install exiftool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Need config.ini for reverse lookup
 | 
					Need config.ini for reverse lookup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Need pyexiv2. Here's how to install on OS X using homebrew...on your own to use other tools.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sourced from http://stackoverflow.com/a/18817419/1318758
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					May need to run these.
 | 
				
			||||||
 | 
					brew rm $(brew deps pyexiv2)
 | 
				
			||||||
 | 
					brew rm pyexiv2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Definietly need to run these
 | 
				
			||||||
 | 
					brew install boost --build-from-source
 | 
				
			||||||
 | 
					brew install pyexiv2
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										106
									
								
								adjust.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										106
									
								
								adjust.py
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import pyexiv2
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from elodie import arguments
 | 
				
			||||||
 | 
					from elodie import geolocation
 | 
				
			||||||
 | 
					from elodie.media.photo import Media
 | 
				
			||||||
 | 
					from elodie.media.photo import Photo
 | 
				
			||||||
 | 
					from elodie.media.video import Video
 | 
				
			||||||
 | 
					from elodie.filesystem import FileSystem
 | 
				
			||||||
 | 
					from elodie.localstorage import Db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parse_arguments(args):
 | 
				
			||||||
 | 
					    config = {
 | 
				
			||||||
 | 
					        'time': None,
 | 
				
			||||||
 | 
					        'location': None,
 | 
				
			||||||
 | 
					        'process': 'yes'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    config.update(args)
 | 
				
			||||||
 | 
					    return config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main(config, args):
 | 
				
			||||||
 | 
					    for arg in args:
 | 
				
			||||||
 | 
					        if(arg[:2] == '--'):
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        elif(not os.path.exists(arg)):
 | 
				
			||||||
 | 
					            print 'Could not find %s' % arg
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        file_path = arg
 | 
				
			||||||
 | 
					        destination = os.path.dirname(os.path.dirname(os.path.dirname(file_path)))
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        _class = None
 | 
				
			||||||
 | 
					        extension = os.path.splitext(file_path)[1][1:].lower()
 | 
				
			||||||
 | 
					        if(extension in Photo.get_valid_extensions()):
 | 
				
			||||||
 | 
					            _class = Photo
 | 
				
			||||||
 | 
					        elif(extension in Video.get_valid_extensions()):
 | 
				
			||||||
 | 
					            _class = Video
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(_class is None):
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        write = False
 | 
				
			||||||
 | 
					        exif_metadata = pyexiv2.ImageMetadata(file_path)
 | 
				
			||||||
 | 
					        exif_metadata.read()
 | 
				
			||||||
 | 
					        if(config['location'] is not None):
 | 
				
			||||||
 | 
					            location_coords = geolocation.coordinates_by_name(config['location'])
 | 
				
			||||||
 | 
					            if(location_coords is not None and 'latitude' in location_coords and 'longitude' in location_coords):
 | 
				
			||||||
 | 
					                print 'Queueing location to exif ...',
 | 
				
			||||||
 | 
					                exif_metadata['Exif.GPSInfo.GPSLatitude'] = geolocation.decimal_to_dms(location_coords['latitude'])
 | 
				
			||||||
 | 
					                exif_metadata['Exif.GPSInfo.GPSLatitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLatitudeRef', 'N' if location_coords['latitude'] >= 0 else 'S')
 | 
				
			||||||
 | 
					                exif_metadata['Exif.GPSInfo.GPSLongitude'] = geolocation.decimal_to_dms(location_coords['longitude'])
 | 
				
			||||||
 | 
					                exif_metadata['Exif.GPSInfo.GPSLongitudeRef'] = pyexiv2.ExifTag('Exif.GPSInfo.GPSLongitudeRef', 'E' if location_coords['longitude'] >= 0 else 'W')
 | 
				
			||||||
 | 
					                write = True
 | 
				
			||||||
 | 
					                print 'OK'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(config['time'] is not None):
 | 
				
			||||||
 | 
					            time_string = config['time']
 | 
				
			||||||
 | 
					            print '%r' % time_string
 | 
				
			||||||
 | 
					            time_format = '%Y-%m-%d %H:%M:%S'
 | 
				
			||||||
 | 
					            if(re.match('^\d{4}-\d{2}-\d{2}$', time_string)):
 | 
				
			||||||
 | 
					                time_string = '%s 00:00:00' % time_string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(re.match('^\d{4}-\d{2}-\d{2}$', time_string) is None and re.match('^\d{4}-\d{2}-\d{2} \d{2}:\d{2}\d{2}$', time_string)):
 | 
				
			||||||
 | 
					                print 'Invalid time format. Use YYYY-mm-dd hh:ii:ss or YYYY-mm-dd'
 | 
				
			||||||
 | 
					                sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(time_format is not None):
 | 
				
			||||||
 | 
					                print 'Queueing time to exif ...',
 | 
				
			||||||
 | 
					                exif_metadata['Exif.Photo.DateTimeOriginal'].value = datetime.strptime(time_string, time_format)
 | 
				
			||||||
 | 
					                exif_metadata['Exif.Image.DateTime'].value = datetime.strptime(time_string, time_format)
 | 
				
			||||||
 | 
					                print '%r' % datetime.strptime(time_string, time_format)
 | 
				
			||||||
 | 
					                write = True
 | 
				
			||||||
 | 
					                print 'OK'
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        if(write == True):
 | 
				
			||||||
 | 
					            exif_metadata.write()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            exif_metadata = pyexiv2.ImageMetadata(file_path)
 | 
				
			||||||
 | 
					            exif_metadata.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            media = _class(file_path)
 | 
				
			||||||
 | 
					            dest_path = filesystem.process_file(file_path, destination, media, move=True, allowDuplicate=True)
 | 
				
			||||||
 | 
					            print '%s ...' % dest_path,
 | 
				
			||||||
 | 
					            print 'OK'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # If the folder we moved the file out of or its parent are empty we delete it.
 | 
				
			||||||
 | 
					            filesystem.delete_directory_if_empty(os.path.dirname(file_path))
 | 
				
			||||||
 | 
					            filesystem.delete_directory_if_empty(os.path.dirname(os.path.dirname(file_path)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					db = Db()
 | 
				
			||||||
 | 
					filesystem = FileSystem()
 | 
				
			||||||
 | 
					args = arguments.parse(sys.argv[1:], None, ['time=','location=','process='], './adjust.py --time=<string time> --location=<string location> --process=no file1 file2...fileN')
 | 
				
			||||||
 | 
					config = parse_arguments(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main(config, sys.argv)
 | 
				
			||||||
 | 
					    sys.exit(0)
 | 
				
			||||||
@ -4,21 +4,18 @@ import sys, getopt
 | 
				
			|||||||
from re import sub
 | 
					from re import sub
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse(argv, options, long_options, usage):
 | 
					def parse(argv, options, long_options, usage):
 | 
				
			||||||
    def help():
 | 
					 | 
				
			||||||
        print 'Usage: %s' % usage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        opts, args = getopt.getopt(argv, options, long_options)
 | 
					        opts, args = getopt.getopt(argv, options, long_options)
 | 
				
			||||||
    except getopt.GetoptError:
 | 
					    except getopt.GetoptError:
 | 
				
			||||||
        print 'Unknown arguments'
 | 
					        print usage
 | 
				
			||||||
        help()
 | 
					 | 
				
			||||||
        sys.exit(2)
 | 
					        sys.exit(2)
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    return_arguments = {}
 | 
					    return_arguments = {}
 | 
				
			||||||
    for opt, arg in opts:
 | 
					    for opt, arg in opts:
 | 
				
			||||||
        if opt == '-h':
 | 
					        if opt == '-h':
 | 
				
			||||||
            help()
 | 
					            print usage
 | 
				
			||||||
            sys.exit()
 | 
					            sys.exit()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return_arguments[sub('^-+', '', opt)] = arg
 | 
					            return_arguments[sub('^-+', '', opt)] = arg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return return_arguments
 | 
					    return return_arguments
 | 
				
			||||||
 | 
				
			|||||||
@ -4,9 +4,11 @@ Video package that handles all video operations
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from elodie import geolocation
 | 
					from elodie import geolocation
 | 
				
			||||||
 | 
					from elodie.localstorage import Db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
General file system methods
 | 
					General file system methods
 | 
				
			||||||
@ -21,6 +23,18 @@ class FileSystem:
 | 
				
			|||||||
        if not os.path.exists(directory_path):
 | 
					        if not os.path.exists(directory_path):
 | 
				
			||||||
            os.makedirs(directory_path)
 | 
					            os.makedirs(directory_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @param, directory_name, string, A fully qualified path of the directory to delete.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def delete_directory_if_empty(self, directory_path):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            os.rmdir(directory_path)
 | 
				
			||||||
 | 
					        except OSError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Recursively get all files which match a path and extension.
 | 
					    Recursively get all files which match a path and extension.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -99,6 +113,46 @@ class FileSystem:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return '/'.join(path)
 | 
					        return '/'.join(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def process_file(self, _file, destination, media, **kwargs):
 | 
				
			||||||
 | 
					        move = False
 | 
				
			||||||
 | 
					        if('move' in kwargs):
 | 
				
			||||||
 | 
					            move = kwargs['move']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        allowDuplicate = False
 | 
				
			||||||
 | 
					        if('allowDuplicate' in kwargs):
 | 
				
			||||||
 | 
					            allowDuplicate = kwargs['allowDuplicate']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        metadata = media.get_metadata()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        directory_name = self.get_folder_path(date=metadata['date_taken'], latitude=metadata['latitude'], longitude=metadata['longitude'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dest_directory = '%s/%s' % (destination, directory_name)
 | 
				
			||||||
 | 
					        file_name = self.get_file_name(media)
 | 
				
			||||||
 | 
					        dest_path = '%s/%s' % (dest_directory, file_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db = Db()
 | 
				
			||||||
 | 
					        checksum = db.checksum(_file)
 | 
				
			||||||
 | 
					        if(checksum == None):
 | 
				
			||||||
 | 
					            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):
 | 
				
			||||||
 | 
					            print '%s already exists at %s. Skipping...' % (_file, db.get_hash(checksum))
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.create_directory(dest_directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(move == True):
 | 
				
			||||||
 | 
					            shutil.move(_file, dest_path)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            shutil.copy2(_file, dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db.add_hash(checksum, dest_path)
 | 
				
			||||||
 | 
					        db.update_hash_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return dest_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Set the modification time on the file based on the file path.
 | 
					    Set the modification time on the file based on the file path.
 | 
				
			||||||
    Noop if the path doesn't match the format YYYY-MM/DD-IMG_0001.JPG.
 | 
					    Noop if the path doesn't match the format YYYY-MM/DD-IMG_0001.JPG.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,77 @@
 | 
				
			|||||||
from os import path
 | 
					from os import path
 | 
				
			||||||
from ConfigParser import ConfigParser
 | 
					from ConfigParser import ConfigParser
 | 
				
			||||||
 | 
					import fractions
 | 
				
			||||||
 | 
					import pyexiv2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import math
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					import urllib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reverse_lookup(lat, lon):
 | 
					class Fraction(fractions.Fraction):
 | 
				
			||||||
    if(lat is None or lon is None):
 | 
					    """Only create Fractions from floats.
 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    >>> Fraction(0.3)
 | 
				
			||||||
 | 
					    Fraction(3, 10)
 | 
				
			||||||
 | 
					    >>> Fraction(1.1)
 | 
				
			||||||
 | 
					    Fraction(11, 10)
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __new__(cls, value, ignore=None):
 | 
				
			||||||
 | 
					        """Should be compatible with Python 2.6, though untested."""
 | 
				
			||||||
 | 
					        return fractions.Fraction.from_float(value).limit_denominator(99999)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # 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.
 | 
				
			||||||
 | 
					            # 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'):
 | 
				
			||||||
 | 
					                    use_location = location['latLng']
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                    'latitude': use_location['lat'],
 | 
				
			||||||
 | 
					                    'longitude': use_location['lng']
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def decimal_to_dms(decimal):
 | 
				
			||||||
 | 
					    """Convert decimal degrees into degrees, minutes, seconds.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    >>> decimal_to_dms(50.445891)
 | 
				
			||||||
 | 
					    [Fraction(50, 1), Fraction(26, 1), Fraction(113019, 2500)]
 | 
				
			||||||
 | 
					    >>> decimal_to_dms(-125.976893)
 | 
				
			||||||
 | 
					    [Fraction(125, 1), Fraction(58, 1), Fraction(92037, 2500)]
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    remainder, degrees = math.modf(abs(decimal))
 | 
				
			||||||
 | 
					    remainder, minutes = math.modf(remainder * 60)
 | 
				
			||||||
 | 
					    # @TODO figure out a better and more proper way to do seconds
 | 
				
			||||||
 | 
					    return (pyexiv2.Rational(degrees, 1), pyexiv2.Rational(minutes, 1), pyexiv2.Rational(int(remainder*1000000000), 1000000000))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def dms_to_decimal(degrees, minutes, seconds, sign=' '):
 | 
				
			||||||
 | 
					    """Convert degrees, minutes, seconds into decimal degrees.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    >>> dms_to_decimal(10, 10, 10)
 | 
				
			||||||
 | 
					    10.169444444444444
 | 
				
			||||||
 | 
					    >>> dms_to_decimal(8, 9, 10, 'S')
 | 
				
			||||||
 | 
					    -8.152777777777779
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    return (-1 if sign[0] in 'SWsw' else 1) * (
 | 
				
			||||||
 | 
					        float(degrees)        +
 | 
				
			||||||
 | 
					        float(minutes) / 60   +
 | 
				
			||||||
 | 
					        float(seconds) / 3600
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_key():
 | 
				
			||||||
    config_file = '%s/config.ini' % path.dirname(path.dirname(path.abspath(__file__)))
 | 
					    config_file = '%s/config.ini' % path.dirname(path.dirname(path.abspath(__file__)))
 | 
				
			||||||
    if not path.exists(config_file):
 | 
					    if not path.exists(config_file):
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
@ -16,19 +81,7 @@ def reverse_lookup(lat, lon):
 | 
				
			|||||||
    if('MapQuest' not in config.sections()):
 | 
					    if('MapQuest' not in config.sections()):
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    key = config.get('MapQuest', 'key')
 | 
					    return config.get('MapQuest', 'key')
 | 
				
			||||||
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        r = requests.get('https://open.mapquestapi.com/nominatim/v1/reverse.php?key=%s&lat=%s&lon=%s&format=json' % (key, lat, lon))
 | 
					 | 
				
			||||||
        return r.json()
 | 
					 | 
				
			||||||
    except requests.exceptions.RequestException as e:
 | 
					 | 
				
			||||||
        print e
 | 
					 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
    except ValueError as e:
 | 
					 | 
				
			||||||
        print r.text
 | 
					 | 
				
			||||||
        print e
 | 
					 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def place_name(lat, lon):
 | 
					def place_name(lat, lon):
 | 
				
			||||||
    geolocation_info = reverse_lookup(lat, lon)
 | 
					    geolocation_info = reverse_lookup(lat, lon)
 | 
				
			||||||
@ -42,3 +95,41 @@ def place_name(lat, lon):
 | 
				
			|||||||
            elif('country' in address):
 | 
					            elif('country' in address):
 | 
				
			||||||
                return address['country']
 | 
					                return address['country']
 | 
				
			||||||
    return None
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def reverse_lookup(lat, lon):
 | 
				
			||||||
 | 
					    if(lat is None or lon is None):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = get_key()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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))
 | 
				
			||||||
 | 
					        return r.json()
 | 
				
			||||||
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
 | 
					        print e
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    except ValueError as e:
 | 
				
			||||||
 | 
					        print r.text
 | 
				
			||||||
 | 
					        print e
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def lookup(name):
 | 
				
			||||||
 | 
					    if(name is None or len(name) == 0):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = get_key()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        params = {'format': 'json', 'key': key, 'location': name}
 | 
				
			||||||
 | 
					        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))
 | 
				
			||||||
 | 
					        return r.json()
 | 
				
			||||||
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
 | 
					        print e
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    except ValueError as e:
 | 
				
			||||||
 | 
					        print r.text
 | 
				
			||||||
 | 
					        print e
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					from media import Media
 | 
				
			||||||
 | 
					from photo import Photo
 | 
				
			||||||
 | 
					from video import Video
 | 
				
			||||||
@ -66,3 +66,13 @@ class Media(object):
 | 
				
			|||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return mimetype[0]
 | 
					        return mimetype[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_class_by_file(Media, _file):
 | 
				
			||||||
 | 
					        extension = os.path.splitext(_file)[1][1:].lower()
 | 
				
			||||||
 | 
					        if(extension in Photo.get_valid_extensions()):
 | 
				
			||||||
 | 
					            return Photo
 | 
				
			||||||
 | 
					        elif(extension in Video.get_valid_extensions()):
 | 
				
			||||||
 | 
					            return Video
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -161,5 +161,5 @@ class Photo(Media):
 | 
				
			|||||||
    @returns, tuple
 | 
					    @returns, tuple
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_valid_extensions(Video):
 | 
					    def get_valid_extensions(Photo):
 | 
				
			||||||
        return Video.__valid_extensions
 | 
					        return Photo.__valid_extensions
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										60
									
								
								import.py
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								import.py
									
									
									
									
									
								
							@ -10,8 +10,31 @@ from elodie.media.video import Video
 | 
				
			|||||||
from elodie.filesystem import FileSystem
 | 
					from elodie.filesystem import FileSystem
 | 
				
			||||||
from elodie.localstorage import Db
 | 
					from elodie.localstorage import Db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
db = Db()
 | 
					def help():
 | 
				
			||||||
filesystem = FileSystem()
 | 
					    return """
 | 
				
			||||||
 | 
					    usage: ./import.py --type=photo --source=/path/to/photos --destination=/path/to/destination
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    --type          Valid values are 'photo' or 'video'. Only files of *type* are imported.
 | 
				
			||||||
 | 
					    --file          Full path to a photo or video to be imported. The --type argument should match the file type of the file.
 | 
				
			||||||
 | 
					                    @TODO: Automatically determine *type* from *file*
 | 
				
			||||||
 | 
					    --source        Full path to a directory which will be recursively crawled for files of *type*.
 | 
				
			||||||
 | 
					    --destination   Full path to a directory where organized photos will be placed.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parse_arguments(args):
 | 
				
			||||||
 | 
					    config = {
 | 
				
			||||||
 | 
					        'type': 'photo',
 | 
				
			||||||
 | 
					        'file': None,
 | 
				
			||||||
 | 
					        'source': None,
 | 
				
			||||||
 | 
					        'destination': None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if('destination' not in args):
 | 
				
			||||||
 | 
					        help()
 | 
				
			||||||
 | 
					        sys.exit(2)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    config.update(args)
 | 
				
			||||||
 | 
					    return config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def process_file(_file, destination, media):
 | 
					def process_file(_file, destination, media):
 | 
				
			||||||
    checksum = db.checksum(_file)
 | 
					    checksum = db.checksum(_file)
 | 
				
			||||||
@ -35,25 +58,20 @@ def process_file(_file, destination, media):
 | 
				
			|||||||
    filesystem.create_directory(dest_directory)
 | 
					    filesystem.create_directory(dest_directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print '%s -> %s' % (_file, dest_path)
 | 
					    print '%s -> %s' % (_file, dest_path)
 | 
				
			||||||
    shutil.copy2(_file, dest_path)
 | 
					    #shutil.copy2(_file, dest_path)
 | 
				
			||||||
    #shutil.move(_file, dest_path)
 | 
					    shutil.move(_file, dest_path)
 | 
				
			||||||
    db.add_hash(checksum, dest_path)
 | 
					    db.add_hash(checksum, dest_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main(argv):
 | 
					def main(argv):
 | 
				
			||||||
    args = arguments.parse(argv, None, ['file=','type=','source=','destination='], './import.py --type=<photo or video> --source=<source directory> -destination=<destination directory>')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if('destination' not in args):
 | 
					    destination = config['destination']
 | 
				
			||||||
        print 'No destination passed in'
 | 
					    if(config['type'] == 'photo'):
 | 
				
			||||||
        sys.exit(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    destination = args['destination']
 | 
					 | 
				
			||||||
    if('type' in args and args['type'] == 'photo'):
 | 
					 | 
				
			||||||
        media_type = Photo
 | 
					        media_type = Photo
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        media_type = Video
 | 
					        media_type = Video
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if('source' in args):
 | 
					    if(config['source'] is not None):
 | 
				
			||||||
        source = args['source']
 | 
					        source = config['source']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        write_counter = 0
 | 
					        write_counter = 0
 | 
				
			||||||
        for current_file in filesystem.get_all_files(source, media_type.get_valid_extensions()):
 | 
					        for current_file in filesystem.get_all_files(source, media_type.get_valid_extensions()):
 | 
				
			||||||
@ -71,15 +89,21 @@ def main(argv):
 | 
				
			|||||||
        # If there's anything we haven't written to the hash database then write it now
 | 
					        # If there's anything we haven't written to the hash database then write it now
 | 
				
			||||||
        if(write_counter % 10 != 10):
 | 
					        if(write_counter % 10 != 10):
 | 
				
			||||||
            db.update_hash_db()
 | 
					            db.update_hash_db()
 | 
				
			||||||
    elif('file' in args):
 | 
					    elif(config['file'] is not None):
 | 
				
			||||||
        media = media_type(args['file'])
 | 
					        media = media_type(config['file'])
 | 
				
			||||||
        if(media_type.__name__ == 'Video'):
 | 
					        if(media_type.__name__ == 'Video'):
 | 
				
			||||||
            filesystem.set_date_from_path_video(media)
 | 
					            filesystem.set_date_from_path_video(media)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        process_file(args['file'], destination, media)
 | 
					        process_file(config['file'], destination, media)
 | 
				
			||||||
        db.update_hash_db()
 | 
					        db.update_hash_db()
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        help()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					db = Db()
 | 
				
			||||||
 | 
					filesystem = FileSystem()
 | 
				
			||||||
 | 
					args = arguments.parse(sys.argv[1:], None, ['file=','type=','source=','destination='], help())
 | 
				
			||||||
 | 
					config = parse_arguments(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    main(sys.argv[1:])
 | 
					    main(config)
 | 
				
			||||||
    sys.exit(0)
 | 
					    sys.exit(0)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										32
									
								
								tests/scripts/datetime.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/scripts/datetime.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from elodie import arguments
 | 
				
			||||||
 | 
					from elodie.media.photo import Photo
 | 
				
			||||||
 | 
					from elodie.media.video import Video
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main(argv):
 | 
				
			||||||
 | 
					    args = arguments.parse(argv, None, ['file=','type='], './import.py --type=<photo or video> --file=<path to file>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if('file' not in args):
 | 
				
			||||||
 | 
					        print 'No file specified'
 | 
				
			||||||
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if('type' in args and args['type'] == 'photo'):
 | 
				
			||||||
 | 
					        media_type = Photo
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        media_type = Video
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    media = media_type(args['file'])
 | 
				
			||||||
 | 
					    metadata = media.get_metadata()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = {'date_taken': metadata['date_taken']}
 | 
				
			||||||
 | 
					    print '%r' % output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main(sys.argv[1:])
 | 
				
			||||||
 | 
					    sys.exit(0)
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user