diff options
Diffstat (limited to 'app/media/retriever.py')
-rw-r--r-- | app/media/retriever.py | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/app/media/retriever.py b/app/media/retriever.py new file mode 100644 index 0000000..f5cae68 --- /dev/null +++ b/app/media/retriever.py @@ -0,0 +1,323 @@ +import json +import datetime +import os +import io +import urllib.request +import urllib.parse +import urllib.error + +from django.template.defaultfilters import slugify +from django.core.exceptions import ObjectDoesNotExist +from django.utils.encoding import force_text +from django.conf import settings + +from photos.models import Photo, PhotoGallery + +# from https://github.com/alexis-mignon/python-flickr-api +# terribly documented, but offers a good clean OOP approach if you're willing to figure it out... +import flickr_api +import flickrapi + +# Required PIL classes may or may not be available from the root namespace depending on the installation +try: + import Image + import ImageFile +except ImportError: + try: + from PIL import Image + from PIL import ImageFile + except ImportError: + raise ImportError("Could not import the Python Imaging Library.") + +ImageFile.MAXBLOCK = 1000000 + +EXIF_PARAMS = { + "FNumber": 'f/2.8', + "Make": 'Apple', + "Model": 'iPhone', + "ExposureTime": '', + "ISO": '', + "FocalLength": '', + "LensModel": '', + 'DateTimeOriginal': '2013:09:03 22:44:25' +} + +class SyncFlickr(): + + def __init__(self): + self.flickr = flickrapi.FlickrAPI(settings.FLICKR_API_KEY, settings.FLICKR_API_SECRET,format='parsed-json') + + + def sync_sets(self, *args, **kwargs): + p = self.flickr.photosets.getList(user_id='85322932@N00') + disregard = [ + 'POTD 2008', + 'Snow Day', + 'Wedding', + 'Some random stuff', + 'Lilah & Olivia', + '6 months+', + '6-9 months', + '9-18 months', + ] + for photoset in p['photosets']['photoset']: + if photoset['title']['_content'] in disregard: + pass + else: + try: + row = PhotoGallery.objects.get(set_id__exact=photoset['id']) + print(('%s %s %s' % ('already have', row.set_title, 'moving on...'))) + # okay it already exists, but is it up-to-date? + self.get_photos_in_set(photoset['id'],row) + except ObjectDoesNotExist: + s = PhotoGallery.objects.get_or_create( + set_id=force_text(photoset['id']), + set_title=force_text(photoset['title']['_content']), + set_desc=force_text(photoset['description']['_content']), + set_slug=slugify(force_text(photoset['title']['_content'])[:40]), + primary=force_text(photoset['primary']), + pub_date=datetime.datetime.fromtimestamp(float(photoset['date_create'])) + ) + + #get_photos_in_set(photoset, s) + #create the gallery thumbnail image: + #photo = Photo.objects.get(flickr_id__exact=str(photoset['primary'])) + #make_gallery_thumb(photo, s) + + + + def get_photos_in_set(self, flickr_id, photoset): + photos = self.flickr.photosets.getPhotos(photoset_id=flickr_id) + for photo in photos['photoset']['photo']: + try: + p = Photo.objects.get(flickr_id__exact=str(photo['id'])) + except ObjectDoesNotExist: + p = self.get_photo(photo['id']) + if p.is_public: + pass #photoset.photos.add(p) + #slideshow_image(p, 1000, 800, 95) + print(p) + + def get_photo(self, photo_id): + photo = self.flickr.photos.getInfo(photo_id=photo_id) + info = photo['photo'] + try: + geo = self.flickr.photos.geo.getLocation(photo_id=photo_id) + location, region = self.get_geo(float(geo['photo']['location']['latitude']), float(geo['photo']['location']['longitude'])) + except KeyError: + print("no effing geodata asshat") + exif = self.exif_handler(self.flickr.photos.getExif(photo_id=photo_id)['photo']['exif']) + p, created = Photo.objects.get_or_create( + title=info['title']['_content'], + flickr_id=info['id'], + flickr_owner=info['owner']['nsid'], + flickr_server=info['server'], + flickr_secret=info['secret'], + flickr_originalsecret=info['originalsecret'], + flickr_farm=info['farm'], + pub_date=self.flickr_datetime_to_datetime(exif["DateTimeOriginal"].replace(':', '-', 2)), + description=info['description']['_content'], + exif_aperture=exif['FNumber'], + exif_make=exif['Make'], + exif_model=exif['Model'], + exif_exposure=exif['ExposureTime'], + exif_iso=exif['ISO'], + exif_lens=exif['LensModel'], + exif_focal_length=exif['FocalLength'], + exif_date=self.flickr_datetime_to_datetime(exif["DateTimeOriginal"].replace(':', '-', 2)), + lat=float(geo['photo']['location']['latitude']), + lon=float(geo['photo']['location']['longitude']), + region=region, + location=location, + ) + if created: + for tag in info['tags']['tag']: + p.tags.add(tag['raw']) + p.save() + + local = FlickrImage() + local.make_local_copies(p) + #retina image: + #slideshow_image(p, 2000, 1600, 75) + #normal image + print("grabbing... "+p.title) + return p + + + def sync_flickr_photos(self, *args, **kwargs): + photos = self.flickr.people.getPhotos(user_id="85322932@N00", extras="date_upload,date_taken,geo") + for photo in photos['photos']['photo']: + try: + row = Photo.objects.get(flickr_id=photo['id'], flickr_secret=photo['secret']) + print('already have ' + photo['id'] + ' moving on') + except ObjectDoesNotExist: + p = self.get_photo(photo['id']) + + + + """ + ################################################ + ## Various meta data and geo helper functions ## + ################################################ + """ + + def exif_handler(self, data): + converted = {} + try: + for t in data: + converted[t['tag']] = t['raw']['_content'] + except: + pass + for k, v in list(EXIF_PARAMS.items()): + if k not in converted: + converted[k] = v + return converted + + + def flickr_datetime_to_datetime(self, fdt): + from datetime import datetime + from time import strptime + date_parts = strptime(fdt, '%Y-%m-%d %H:%M:%S') + return datetime(*date_parts[0:6]) + + + def get_geo(self, lat, lon): + from locations.models import Location, Region + from django.contrib.gis.geos import Point + pnt_wkt = Point(lon, lat) + try: + location = Location.objects.get(geometry__contains=pnt_wkt) + except Location.DoesNotExist: + location = None + try: + region = Region.objects.get(geometry__contains=pnt_wkt) + except Region.DoesNotExist: + region = None + return location, region + + + + + + +class FlickrImage(): + """ + ## Photo retrieval functions to pull down images from Flickr servers ## + """ + + def slideshow_image(self, photo, max_width, max_height, quality): + slide_dir = settings.IMAGES_ROOT + '/slideshow/' + photo.pub_date.strftime("%Y") + if not os.path.isdir(slide_dir): + os.makedirs(slide_dir) + + # Is it a retina image or not? + if max_width >= 1001 or max_height >= 801: + filename = '%s/%sx2.jpg' % (slide_dir, photo.flickr_id) + else: + filename = '%s/%s.jpg' % (slide_dir, photo.flickr_id) + + flickr_photo = photo.get_original_url() + fname = urllib.request.urlopen(flickr_photo) + im = io.StringIO(fname.read().decode('UTF-8')) # constructs a StringIO holding the image + img = Image.open(im) + cur_width, cur_height = img.size + #if image landscape + if cur_width > cur_height: + new_width = max_width + #check to make sure we aren't upsizing + if cur_width > new_width: + ratio = float(new_width) / cur_width + x = (cur_width * ratio) + y = (cur_height * ratio) + resized = img.resize((int(x), int(y)), Image.ANTIALIAS) + resized.save(filename, 'JPEG', quality=quality, optimize=True) + else: + img.save(filename) + else: + #image portrait + new_height = max_height + #check to make sure we aren't upsizing + if cur_height > new_height: + ratio = float(new_height) / cur_height + x = (cur_width * ratio) + y = (cur_height * ratio) + resized = img.resize((int(x), int(y)), Image.ANTIALIAS) + resized.save(filename, 'JPEG', quality=quality, optimize=True) + else: + img.save(filename) + photo.slideshowimage_width = photo.get_width + photo.slideshowimage_height = photo.get_height + photo.slideshowimage_margintop = photo.get_margin_top + photo.slideshowimage_marginleft = photo.get_margin_left + photo.save() + #now resize the local copy + + + def make_local_copies(self,photo): + orig_dir = settings.IMAGES_ROOT + '/flickr/full/' + photo.pub_date.strftime("%Y") + if not os.path.isdir(orig_dir): + os.makedirs(orig_dir) + full = photo.get_original_url() + fname = urllib.request.urlopen(full) + im = io.StringIO(fname.read().decode('UTF-8')) # constructs a StringIO holding the image + img = Image.open(im) + local_full = '%s/%s.jpg' % (orig_dir, photo.flickr_id) + img.save(local_full) + #save large size + large_dir = settings.IMAGES_ROOT + '/flickr/large/' + photo.pub_date.strftime("%Y") + if not os.path.isdir(large_dir): + os.makedirs(large_dir) + large = photo.get_large_url() + fname = urllib.request.urlopen(large) + im = io.StringIO(fname.read().decode('UTF-8')) # constructs a StringIO holding the image + img = Image.open(im) + local_large = '%s/%s.jpg' % (large_dir, photo.flickr_id) + if img.format == 'JPEG': + img.save(local_large) + #save medium size + med_dir = settings.IMAGES_ROOT + '/flickr/med/' + photo.pub_date.strftime("%Y") + if not os.path.isdir(med_dir): + os.makedirs(med_dir) + med = photo.get_medium_url() + fname = urllib.request.urlopen(med) + im = io.StringIO(fname.read().decode('UTF-8')) # constructs a StringIO holding the image + img = Image.open(im) + local_med = '%s/%s.jpg' % (med_dir, photo.flickr_id) + img.save(local_med) + + + def make_gallery_thumb(self, photo, set): + crop_dir = settings.IMAGES_ROOT + '/gallery_thumbs/' + if not os.path.isdir(crop_dir): + os.makedirs(crop_dir) + remote = photo.get_original_url() + print(remote) + fname = urllib.request.urlopen(remote) + im = io.StringIO(fname.read().decode('UTF-8')) # constructs a StringIO holding the image + img = Image.open(im) + #calculate crop: + cur_width, cur_height = img.size + new_width, new_height = 291, 350 + ratio = max(float(new_width) / cur_width, float(new_height) / cur_height) + x = (cur_width * ratio) + y = (cur_height * ratio) + xd = abs(new_width - x) + yd = abs(new_height - y) + x_diff = int(xd / 2) + y_diff = int(yd / 2) + box = (int(x_diff), int(y_diff), int(x_diff + new_width), int(y_diff + new_height)) + + # create resized file + resized = img.resize((int(x), int(y)), Image.ANTIALIAS).crop(box) + # save resized file + resized_filename = '%s/%s.jpg' % (crop_dir, set.id) + try: + if img.format == 'JPEG': + resized.save(resized_filename, 'JPEG', quality=95, optimize=True) + else: + resized.save(resized_filename) + except IOError as e: + if os.path.isfile(resized_filename): + os.unlink(resized_filename) + raise e + os.unlink(img) |