summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2024-12-27 09:47:42 -0600
committerluxagraf <sng@luxagraf.net>2024-12-27 09:47:42 -0600
commit8c7b0e1abe1983fac38322c3bc01165c4c693d7e (patch)
tree2f91e32f0dae419fe46f773fe9a11817b809fcf0
parent05b386315c09c735201566cf8945fc8ff78d2741 (diff)
jrnl: added a photo essay post type and new url/template/views. also cleared out some old unneeded files
-rw-r--r--.gitignore2
-rw-r--r--app/media/0002_auto_20201201_2054.py46
-rw-r--r--app/media/0003_auto_20201201_2055.py118
-rw-r--r--app/media/admin.py16
-rw-r--r--app/media/migrations/0009_remove_luximage_exif_aperture_and_more.py49
-rw-r--r--app/media/migrations/0010_luximage_image_type.py18
-rw-r--r--app/media/models.py25
-rw-r--r--app/media/retriever.py323
-rw-r--r--app/media/retriever.py.bak314
-rw-r--r--app/media/static/image-preview.js42
-rw-r--r--app/media/static/my_styles.css40
-rw-r--r--app/media/views.py10
-rw-r--r--app/posts/models.py1
-rw-r--r--app/posts/templates/photo_essay_detail.html34
-rw-r--r--app/posts/urls/photo_essay_urls.py (renamed from app/posts/urls/film_urls.py)10
-rw-r--r--app/posts/views/photo_essay_views.py (renamed from app/posts/views/film_views.py)27
-rw-r--r--config/base_urls.py1
-rw-r--r--templates/archives/photo_daily_list.html6
18 files changed, 158 insertions, 924 deletions
diff --git a/.gitignore b/.gitignore
index 7d6425c..bbfe13f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,4 +31,4 @@ screenv11.min.css
.ipython/
.python_history
.viminfo
-
+bak/
diff --git a/app/media/0002_auto_20201201_2054.py b/app/media/0002_auto_20201201_2054.py
deleted file mode 100644
index 843f48b..0000000
--- a/app/media/0002_auto_20201201_2054.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Generated by Django 3.1 on 2020-12-01 19:26
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('media', '0001_initial'),
- ]
-
- operations = [
- migrations.RunSQL("""
- INSERT INTO media_luximagesize (
- id,
- name,
- width,
- height,
- quality
- )
- SELECT
- id,
- name,
- width,
- height,
- quality
- FROM
- photos_luximagesize;
- """, reverse_sql="""
- INSERT INTO photos_luximagesize (
- id,
- name,
- width,
- height,
- quality
- )
- SELECT
- id,
- name,
- width,
- height,
- quality
- FROM
- media_luximagesize;
- """)
- ]
diff --git a/app/media/0003_auto_20201201_2055.py b/app/media/0003_auto_20201201_2055.py
deleted file mode 100644
index 4aeec12..0000000
--- a/app/media/0003_auto_20201201_2055.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Generated by Django 3.1 on 2020-12-01 20:49
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('media', '0002_auto_20201201_2054'),
- ]
-
- operations = [
- migrations.RunSQL("""
- INSERT INTO media_luximage (
- id,
- image,
- title,
- alt,
- photo_credit_source,
- photo_credit_url,
- caption,
- pub_date,
- height,
- width,
- is_public,
- exif_raw,
- exif_aperture,
- exif_make,
- exif_model,
- exif_exposure,
- exif_iso,
- exif_focal_length,
- exif_lens,
- exif_date,
- point,
- location,
- sizes
- )
- SELECT
- id,
- image,
- title,
- alt,
- photo_credit_source,
- photo_credit_url,
- caption,
- pub_date,
- height,
- width,
- is_public,
- exif_raw,
- exif_aperture,
- exif_make,
- exif_model,
- exif_exposure,
- exif_iso,
- exif_focal_length,
- exif_lens,
- exif_date,
- point,
- location,
- sizes
- FROM
- photos_luximage;
- """, reverse_sql="""
- INSERT INTO photos_luximage (
- id,
- image,
- title,
- alt,
- photo_credit_source,
- photo_credit_url,
- caption,
- pub_date,
- height,
- width,
- is_public,
- sizes,
- exif_raw,
- exif_aperture,
- exif_make,
- exif_model,
- exif_exposure,
- exif_iso,
- exif_focal_length,
- exif_lens,
- exif_date,
- point,
- location
- )
- SELECT
- id,
- image,
- title,
- alt,
- photo_credit_source,
- photo_credit_url,
- caption,
- pub_date,
- height,
- width,
- is_public,
- sizes,
- exif_raw,
- exif_aperture,
- exif_make,
- exif_model,
- exif_exposure,
- exif_iso,
- exif_focal_length,
- exif_lens,
- exif_date,
- point,
- location
- FROM
- media_luximage;
- """)
- ]
diff --git a/app/media/admin.py b/app/media/admin.py
index 2ccce29..f46475c 100644
--- a/app/media/admin.py
+++ b/app/media/admin.py
@@ -6,7 +6,7 @@ from django.shortcuts import render
from django.contrib.admin import helpers
from django.http import HttpResponseRedirect
-from utils.widgets import OLAdminBase
+from utils.widgets import OLAdminBase, LGEntryForm, ImageRadioSelect
@admin.register(LuxImageSize)
class LuxImageSizeAdmin(admin.ModelAdmin):
@@ -41,7 +41,7 @@ class LuxImageAdmin(OLAdminBase):
'fields': (
('is_public'),
('photo_credit_source', 'photo_credit_url'),
- 'exif_raw', 'exif_aperture', 'exif_make', 'exif_model', 'exif_exposure', 'exif_iso', 'exif_focal_length', 'exif_lens', 'exif_date', 'height', 'width'),
+ 'height', 'width'),
}),
)
@@ -53,3 +53,15 @@ class LuxImageAdmin(OLAdminBase):
class Media:
js = ('image-preview.js', 'next-prev-links.js')
+
+
+@admin.register(LuxGallery)
+class LuxGalleryAdmin(admin.ModelAdmin):
+ form = LGEntryForm
+ class Meta:
+ widgets = {
+ 'images': ImageRadioSelect,
+ }
+ autocomplete_fields = ['images']
+ list_display = ('title','pub_date', 'thumb')
+
diff --git a/app/media/migrations/0009_remove_luximage_exif_aperture_and_more.py b/app/media/migrations/0009_remove_luximage_exif_aperture_and_more.py
new file mode 100644
index 0000000..631c12c
--- /dev/null
+++ b/app/media/migrations/0009_remove_luximage_exif_aperture_and_more.py
@@ -0,0 +1,49 @@
+# Generated by Django 5.0.4 on 2024-12-25 11:50
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('media', '0008_auto_20201202_1155'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_aperture',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_date',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_exposure',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_focal_length',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_iso',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_lens',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_make',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_model',
+ ),
+ migrations.RemoveField(
+ model_name='luximage',
+ name='exif_raw',
+ ),
+ ]
diff --git a/app/media/migrations/0010_luximage_image_type.py b/app/media/migrations/0010_luximage_image_type.py
new file mode 100644
index 0000000..ed8cad9
--- /dev/null
+++ b/app/media/migrations/0010_luximage_image_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.0.4 on 2024-12-25 11:54
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('media', '0009_remove_luximage_exif_aperture_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='luximage',
+ name='image_type',
+ field=models.IntegerField(choices=[(0, 'Photo'), (1, 'Sketch')], default=0),
+ ),
+ ]
diff --git a/app/media/models.py b/app/media/models.py
index d1ef32a..f8ce3b5 100644
--- a/app/media/models.py
+++ b/app/media/models.py
@@ -22,7 +22,6 @@ from resizeimage.imageexceptions import ImageSizeError
from taggit.managers import TaggableManager
-from .readexif import readexif
from .utils import resize_image
from locations.models import Location, CheckIn
@@ -78,19 +77,10 @@ class LuxImage(models.Model):
image = models.FileField(blank=True, null=True, upload_to=get_upload_path)
title = models.CharField(null=True, blank=True, max_length=300)
alt = models.CharField(null=True, blank=True, max_length=300)
- photo_credit_source = models.CharField(null=True, blank=True, max_length=300)
- photo_credit_url = models.CharField(null=True, blank=True, max_length=300)
caption = models.TextField(blank=True, null=True)
pub_date = models.DateTimeField(default=datetime.datetime.now)
- exif_raw = models.TextField(blank=True, null=True)
- exif_aperture = models.CharField(max_length=50, blank=True, null=True)
- exif_make = models.CharField(max_length=50, blank=True, null=True)
- exif_model = models.CharField(max_length=50, blank=True, null=True)
- exif_exposure = models.CharField(max_length=50, blank=True, null=True)
- exif_iso = models.CharField(max_length=50, blank=True, null=True)
- exif_focal_length = models.CharField(max_length=50, blank=True, null=True)
- exif_lens = models.CharField(max_length=50, blank=True, null=True)
- exif_date = models.DateTimeField(blank=True, null=True)
+ photo_credit_source = models.CharField(null=True, blank=True, max_length=300)
+ photo_credit_url = models.CharField(null=True, blank=True, max_length=300)
height = models.CharField(max_length=6, blank=True, null=True)
width = models.CharField(max_length=6, blank=True, null=True)
point = models.PointField(null=True, blank=True)
@@ -98,6 +88,11 @@ class LuxImage(models.Model):
is_public = models.BooleanField(default=True)
sizes = models.ManyToManyField(LuxImageSize, blank=True, related_name='sizes')
sizes_cache = models.CharField(null=True, blank=True, max_length=300)
+ IMAGE_TYPE = (
+ (0, 'Photo'),
+ (1, 'Sketch'),
+ )
+ image_type = models.IntegerField(choices=IMAGE_TYPE, default=0)
class Meta:
ordering = ('-pub_date', 'id')
@@ -255,9 +250,9 @@ class LuxGallery(models.Model):
def get_absolute_url(self):
if self.is_public:
- return "/photos/galleries/%s" % (self.slug)
+ return "/image//%s" % (self.slug)
else:
- return "/photos/galleries/private/%s" % (self.slug)
+ return None
def thumbs(self):
lst = [x.image.name for x in self.images.all()]
@@ -368,8 +363,6 @@ class LuxAudio(models.Model):
@receiver(post_save, sender=LuxImage)
def post_save_events(sender, update_fields, created, instance, **kwargs):
if created:
- if instance.exif_raw == '':
- instance = readexif(instance)
instance.sizes.add(LuxImageSize.objects.get(slug="tn"))
img = Image.open(instance.image.path)
instance.height = img.height
diff --git a/app/media/retriever.py b/app/media/retriever.py
deleted file mode 100644
index f5cae68..0000000
--- a/app/media/retriever.py
+++ /dev/null
@@ -1,323 +0,0 @@
-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)
diff --git a/app/media/retriever.py.bak b/app/media/retriever.py.bak
deleted file mode 100644
index d3c572a..0000000
--- a/app/media/retriever.py.bak
+++ /dev/null
@@ -1,314 +0,0 @@
-from __future__ import division
-import datetime
-import os
-import cStringIO
-import urllib
-
-from django.template.defaultfilters import slugify
-from django.core.exceptions import ObjectDoesNotExist
-from django.utils.encoding import force_unicode
-from django.conf import settings
-
-# 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
-
-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
-
-EXIF_PARAMS = {
- "FNumber": 'f/2.8',
- "Make": 'Apple',
- "Model": 'iPhone',
- "ExposureTime": '',
- "ISO": '',
- "FocalLength": '',
- "LensModel": '',
- 'DateTimeOriginal': '2013:09:03 22:44:25'
-}
-
-
-def sync_flickr_photos(*args, **kwargs):
- flickr_api.set_keys(api_key=settings.FLICKR_API_KEY, api_secret=settings.FLICKR_API_SECRET)
- flickr_api.set_auth_handler("app/photos/flickrauth")
- user = flickr_api.test.login()
- photos = user.getPhotos(extras="date_upload,date_taken,geo")
- # reverse! reverse!
- photos.reverse()
- for photo in photos:
- info = photo.getInfo()
- try:
- row = Photo.objects.get(flickr_id=info['id'], flickr_secret=info['secret'])
- print('already have ' + info['id'] + ' moving on')
- except ObjectDoesNotExist:
- get_photo(photo)
-
-
-def get_photo(photo):
- info = photo.getInfo()
- geo = photo.getLocation()
- location, region = get_geo(float(geo['latitude']), float(geo['longitude']))
- exif = exif_handler(photo.getExif())
- p, created = Photo.objects.get_or_create(
- title=info['title'],
- flickr_id=info['id'],
- flickr_owner=info['owner']['id'],
- flickr_server=info['server'],
- flickr_secret=info['secret'],
- flickr_originalsecret=info['originalsecret'],
- flickr_farm=info['farm'],
- pub_date=flickr_datetime_to_datetime(info['taken']),
- description=info['description'],
- 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=flickr_datetime_to_datetime(exif["DateTimeOriginal"].replace(':', '-', 2)),
- lat=float(geo['latitude']),
- lon=float(geo['longitude']),
- region=region,
- location=location,
- )
- if created:
- for tag in info['tags']:
- p.tags.add(tag['raw'])
- p.save()
- make_local_copies(p)
- #retina image:
- #slideshow_image(p, 2000, 1600, 75)
- #normal image
- print(p.title)
- return p
-
-
-def sync_sets(*args, **kwargs):
- flickr_api.set_keys(api_key=settings.FLICKR_API_KEY, api_secret=settings.FLICKR_API_SECRET)
- flickr_api.set_auth_handler("app/photos/flickrauth")
- user = flickr_api.test.login()
- photosets = user.getPhotosets()
- # reverse! reverse!
- photosets.reverse()
- disregard = [
- 'POTD 2008',
- 'Snow Day',
- 'Wedding',
- 'Some random stuff',
- 'Lilah & Olivia',
- '6 months+',
- '6-9 months',
- '9-18 months',
- ]
- for photoset in photosets:
- if photoset['title'] 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?
- #get_photos_in_set(row,set.id)
- except ObjectDoesNotExist:
- s = PhotoGallery.objects.create(
- set_id=force_unicode(photoset['id']),
- set_title=force_unicode(photoset['title']),
- set_desc=force_unicode(photoset['description']),
- set_slug=slugify(force_unicode(photoset['title'])),
- primary=force_unicode(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(flickr_photoset, photoset):
- for photo in flickr_photoset.getPhotos():
- try:
- p = Photo.objects.get(flickr_id__exact=str(photo['id']))
- except ObjectDoesNotExist:
- p = get_photo(photo)
- if p.is_public:
- photoset.photos.add(p)
- slideshow_image(p, 1000, 800, 95)
-
-
-################################################
-## Various meta data and geo helper functions ##
-################################################
-
-
-def exif_handler(data):
- converted = {}
- try:
- for t in data:
- converted[t['tag']] = t['raw']
- except:
- pass
- for k, v in EXIF_PARAMS.items():
- if not converted.has_key(k):
- converted[k] = v
- return converted
-
-
-def flickr_datetime_to_datetime(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(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
-
-#######################################################################
-## Photo retrieval functions to pull down images from Flickr servers ##
-#######################################################################
-
-def slideshow_image(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.urlopen(flickr_photo)
- im = cStringIO.StringIO(fname.read()) # 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(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.urlopen(full)
- im = cStringIO.StringIO(fname.read()) # 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.urlopen(large)
- im = cStringIO.StringIO(fname.read()) # 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.urlopen(med)
- im = cStringIO.StringIO(fname.read()) # 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(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.urlopen(remote)
- im = cStringIO.StringIO(fname.read()) # 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, e:
- if os.path.isfile(resized_filename):
- os.unlink(resized_filename)
- raise e
- #os.unlink(img)
-
-
-
diff --git a/app/media/static/image-preview.js b/app/media/static/image-preview.js
deleted file mode 100644
index c829084..0000000
--- a/app/media/static/image-preview.js
+++ /dev/null
@@ -1,42 +0,0 @@
-function build_image_preview () {
- var url = window.location.href
- var cur = url.split('/')[6];
- if (cur) {
- var container = document.createElement("div");
- container.className = "form-row field-image";
- var wrapper = document.createElement("div");
- var label = document.createElement("label");
- label.textContent = "Image:";
- var pwrap = document.createElement("p");
- var img = document.createElement("img");
-
- var request = new XMLHttpRequest();
- request.open('GET', '/photos/data/admin/preview/'+cur+'/', true);
- request.onload = function() {
- if (request.status >= 200 && request.status < 400) {
- var data = JSON.parse(request.responseText);
- //console.log(data);
- img.src = data['url'];
- } else {
- console.log("server error");
- }
- };
- request.onerror = function() {
- console.log("error on request");
- };
- request.send();
- pwrap.appendChild(img);
- wrapper.appendChild(label);
- wrapper.appendChild(pwrap);
- container.appendChild(wrapper);
- parent = document.getElementById("luximage_form");
- node = parent.children[1].children[0];
- node.parentNode.insertBefore(container, node.previousSibling);
- } else {
- return;
- }
-}
-
-document.addEventListener("DOMContentLoaded", function(event) {
- build_image_preview();
-});
diff --git a/app/media/static/my_styles.css b/app/media/static/my_styles.css
deleted file mode 100644
index d13c8e4..0000000
--- a/app/media/static/my_styles.css
+++ /dev/null
@@ -1,40 +0,0 @@
-
-/*o.v.*/
-
-#id_featured_image {
- /*style the "box" in its minimzed state*/
- border:1px solid black; width:230px; overflow:hidden;
- height:300px; overflow-y:scroll;
- /*animate collapsing the dropdown from open to closed state (v. fast)*/
-}
-#id_featured_image input {
- /*hide the nasty default radio buttons. like, completely!*/
- position:absolute;top:0;left:0;opacity:0;
-}
-
-
-#id_featured_image label {
- /*style the labels to look like dropdown options, kinda*/
- color: #000;
- display:block;
- margin: 2px 2px 2px 10px;
- height:102px;
- opacity:.6;
- background-repeat: no-repeat;
-}
-#id_featured_image:hover label{
- /*this is how labels render in the "expanded" state. we want to see only the selected radio button in the collapsed menu, and all of them when expanded*/
-}
-#id_featured_image label:hover {
- opacity:.8;
-}
-#id_featured_image input:checked + label {
- /*tricky! labels immediately following a checked radio button (with our markup they are semantically related) should be fully opaque regardless of hover, and they should always be visible (i.e. even in the collapsed menu*/
- opacity:1 !important;
- display:block;
- background: #333;
-}
-
-/*pfft, nothing as cool here, just the value trace*/
-#trace {margin:0 0 20px;}
-#id_featured_image li:first-child { display: none;}
diff --git a/app/media/views.py b/app/media/views.py
index 04ac11c..82c68ba 100644
--- a/app/media/views.py
+++ b/app/media/views.py
@@ -38,14 +38,20 @@ class Gallery(DetailView):
class GalleryList(PaginatedListView):
- template_name = 'archives/gallery_list.html'
+ #template_name = 'luxgallery_list.html'
+ template_name = 'luxgallery_detail.html'
def get_queryset(self):
- return LuxGallery.objects.filter(is_public=True)
+ self.gallery = LuxGallery.objects.get(slug="placeholder")
+ return self.gallery
+ #actual return statement for when I have some galleries:
+ #return LuxGallery.objects.filter(is_public=True)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(GalleryList, self).get_context_data(**kwargs)
+ context['breadcrumbs'] = ('Images',)
+ context['crumb_url'] = '/media/'
context['is_private'] = False
return context
diff --git a/app/posts/models.py b/app/posts/models.py
index 377225f..6179fbe 100644
--- a/app/posts/models.py
+++ b/app/posts/models.py
@@ -73,6 +73,7 @@ class PostType(models.IntegerChoices):
SRC = 3, ('src')
JRNL = 4, ('jrnl')
FIELD_NOTE = 5, ('field note')
+ PHOTO_ESSAY = 6, ('photo essay')
class PostTopic(models.IntegerChoices):
diff --git a/app/posts/templates/photo_essay_detail.html b/app/posts/templates/photo_essay_detail.html
new file mode 100644
index 0000000..8195ae7
--- /dev/null
+++ b/app/posts/templates/photo_essay_detail.html
@@ -0,0 +1,34 @@
+{% extends 'base.html' %}
+{%block htmlclass%}class="detail single"{% endblock %}
+{% load typogrify_tags %}
+{% load html5_datetime %}
+{% load pagination_tags %}
+{% block pagetitle %} Photos | luxagraf {% endblock %}
+{% block metadescription %} Recent Images {% endblock %}
+{%block bodyid%}class="photos" id="notes-archive"{%endblock%}
+{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %}
+{% block primary %}
+ <main role="main">
+ <figure class="large-top-image">{%with object=object_list%}
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">{%with image=object.featured_image%}
+ <img style="margin:0;" sizes="(max-width: 960px) 100vw"
+ srcset="{{image.get_srcset}}"
+ src="{{image.get_src}}"
+ alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}">
+ </a>
+ </figure>{%endwith%}
+ <div class="folio-wrapper">
+ <article class="h-entry hentry content" itemscope itemType="http://schema.org/BlogPosting">
+ <header id="header" class="post-header">
+ <h1 class="p-name post-title" itemprop="headline">{{object.title|smartypants|safe}}</h1>
+ <div class="post-dateline">
+ <time class="hide dt-published published dt-updated post-date lttr-box" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished"><span>{{object.pub_date|date:"F j, Y"}}</span></time>
+ <span class="hide" itemprop="author" itemscope itemtype="http://schema.org/Person">by <a class="p-author h-card" href="/about"><span itemprop="name">Scott Gilbertson</span></a></span>
+ </div>
+ </header>
+ <div id="article" class="e-content entry-content post-body" itemprop="articleBody">
+ {{object.body_html|safe|smartypants}}
+ </div>
+ </div>
+ </main>{%endwith%}
+{% endblock%}
diff --git a/app/posts/urls/film_urls.py b/app/posts/urls/photo_essay_urls.py
index 872d3f4..e69f07c 100644
--- a/app/posts/urls/film_urls.py
+++ b/app/posts/urls/photo_essay_urls.py
@@ -1,23 +1,23 @@
from django.urls import path, re_path
-from ..views import film_views as views
+from ..views import photo_essay_views as views
-app_name = "film"
+app_name = "photo_essay"
urlpatterns = [
path(
r'<str:slug>',
- views.FilmDetailView.as_view(),
+ views.PhotoEssayDetailView.as_view(),
name="detail"
),
path(
r'<int:page>/',
- views.FilmListView.as_view(),
+ views.PhotoEssayListView.as_view(),
name="list"
),
path(
r'',
- views.FilmListView.as_view(),
+ views.PhotoEssayListView.as_view(),
{'page':1},
name="list"
),
diff --git a/app/posts/views/film_views.py b/app/posts/views/photo_essay_views.py
index 48bdaa4..4f08910 100644
--- a/app/posts/views/film_views.py
+++ b/app/posts/views/photo_essay_views.py
@@ -11,44 +11,47 @@ from ..models import Post, PostType
from taxonomy.models import Category
-class FilmListView(PaginatedListView):
+class PhotoEssayListView(PaginatedListView):
model = Post
- template_name = "posts/film_list.html"
+ # TODO: change this when I have an actual archive to show
+ template_name = "photo_essay_detail.html"
def get_queryset(self):
- queryset = super(FilmListView, self).get_queryset()
- return queryset.filter(site__domain='luxagraf.net').filter(post_type__in=[PostType.FILM]).filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image')
+ queryset = super(PhotoEssayListView, self).get_queryset()
+ return queryset.get(slug="dawn")
+ # real queryset
+ #return queryset.filter(site__domain='luxagraf.net').filter(post_type__in=[PostType.PHOTO_ESSAY]).filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image')
def get_context_data(self, **kwargs):
'''
override for custom breadcrumb path
'''
# Call the base implementation first to get a context
- context = super(FilmListView, self).get_context_data(**kwargs)
- context['breadcrumbs'] = ('Film',)
+ context = super(PhotoEssayListView, self).get_context_data(**kwargs)
+ context['breadcrumbs'] = ('Photos',)
return context
-class FilmDetailView(LuxDetailView):
+class PhotoEssayDetailView(LuxDetailView):
model = Post
slug_field = "slug"
def get_queryset(self):
- queryset = super(FilmDetailView, self).get_queryset()
+ queryset = super(PhotoEssayDetailView, self).get_queryset()
return queryset.select_related('location').prefetch_related('field_notes')
def get_context_data(self, **kwargs):
- context = super(FilmDetailView, self).get_context_data(**kwargs)
+ context = super(PhotoEssayDetailView, self).get_context_data(**kwargs)
related = []
for obj in self.object.related.all():
model = apps.get_model(obj.model_name.app_label, obj.model_name.model)
related.append(model.objects.get(slug=obj.slug, pub_date=obj.pub_date))
context['related'] = related
- context['breadcrumbs'] = ('Range',)
- context['crumb_url'] = reverse('range:range-list')
+ context['breadcrumbs'] = ('Photos',)
+ context['crumb_url'] = reverse('posts:photo-essay-list')
return context
def get_template_names(self):
obj = self.get_object()
- return ["posts/film_detail.html"]
+ return ["film_detail.html"]
diff --git a/config/base_urls.py b/config/base_urls.py
index 9d0a507..0677a15 100644
--- a/config/base_urls.py
+++ b/config/base_urls.py
@@ -48,6 +48,7 @@ urlpatterns = [
#path(r'expenses/', include('expenses.urls', namespace='expenses')),
path(r'newsletter/', include('lttr.urls')),
path(r'photos/', include('media.urls')),
+ path(r'images/', include('posts.urls.photo_essay_urls', namespace='photo-essay-list')),
#path(r'film/', include('posts.urls.film_urls')),
#re_path(r'^film/$', RedirectView.as_view(url='/films/')),
#path(r'films/', include('posts.urls.film_urls', namespace='films')),
diff --git a/templates/archives/photo_daily_list.html b/templates/archives/photo_daily_list.html
index 04254ff..28659c9 100644
--- a/templates/archives/photo_daily_list.html
+++ b/templates/archives/photo_daily_list.html
@@ -3,8 +3,8 @@
{% load typogrify_tags %}
{% load html5_datetime %}
{% load pagination_tags %}
-{% block pagetitle %} Photos | luxagraf {% endblock %}
-{% block metadescription %} Recent Images {% endblock %}
+{% block pagetitle %}Luxagraf: Images{% endblock %}
+{% block metadescription %}{% endblock %}
{%block bodyid%}class="photos" id="notes-archive"{%endblock%}
{% block primary %}
@@ -13,7 +13,7 @@
<li>Photos</li>
</ul>
<main role="main">
- {% autopaginate object_list 8 %}{% for object in object_list %}
+ {% for object in object_list.photos %}
<article class="h-entry hentry " itemscope="" itemtype="http://schema.org/Article">
<figure class="daily-figure">
{% include 'lib/img_picwide.html' with image=object caption=False exif=False is_cluster=False cluster_class='' extra='' %}