New settings to define the sort order for albums and medias (closes #2).
This commit is contained in:
@@ -18,6 +18,9 @@ Released on 2014-xx-xx.
|
||||
``album.title``, ``media.file`` => ``media.filename``, ``media.thumb`` =>
|
||||
``media.thumbnail``, ``zip_gallery`` => ``album.zip``
|
||||
|
||||
- New settings to define the sort order for albums and medias:
|
||||
``albums_sort_reverse``, ``medias_sort_attr``, ``medias_sort_reverse``.
|
||||
|
||||
Version 0.6.0
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ if not PY2:
|
||||
text_type = str
|
||||
string_types = (str,)
|
||||
unichr = chr
|
||||
|
||||
from functools import cmp_to_key
|
||||
alpha_sort = {'key': cmp_to_key(locale.strcoll)}
|
||||
strxfrm = locale.strxfrm
|
||||
|
||||
from http import server
|
||||
import socketserver
|
||||
@@ -19,7 +17,9 @@ else:
|
||||
text_type = unicode # NOQA
|
||||
string_types = (str, unicode) # NOQA
|
||||
unichr = unichr
|
||||
alpha_sort = {'cmp': locale.strcoll}
|
||||
|
||||
def strxfrm(s):
|
||||
return locale.strxfrm(s.encode('utf-8'))
|
||||
|
||||
import SimpleHTTPServer as server
|
||||
import SocketServer as socketserver
|
||||
|
||||
@@ -32,11 +32,12 @@ import sys
|
||||
import zipfile
|
||||
|
||||
from collections import defaultdict
|
||||
from os.path import isfile, join
|
||||
from datetime import datetime
|
||||
from os.path import isfile, join, splitext
|
||||
from PIL import Image as PILImage
|
||||
|
||||
from . import image, video
|
||||
from .compat import UnicodeMixin, alpha_sort
|
||||
from .compat import UnicodeMixin, strxfrm
|
||||
from .image import process_image, get_exif_tags
|
||||
from .log import colored, BLUE
|
||||
from .settings import get_thumb, get_orig
|
||||
@@ -76,6 +77,7 @@ class Media(UnicodeMixin):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.raw_exif = None
|
||||
self.exif = None
|
||||
self.date = None
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s>(%r)" % (self.__class__.__name__, self.file_path)
|
||||
@@ -120,6 +122,8 @@ class Image(Media):
|
||||
def __init__(self, filename, path, settings):
|
||||
super(Image, self).__init__(filename, path, settings)
|
||||
self.raw_exif, self.exif = get_exif_tags(self.src_path)
|
||||
if self.exif is not None and 'dateobj' in self.exif:
|
||||
self.date = self.exif['dateobj']
|
||||
|
||||
|
||||
class Video(Media):
|
||||
@@ -130,7 +134,7 @@ class Video(Media):
|
||||
|
||||
def __init__(self, filename, path, settings):
|
||||
super(Video, self).__init__(filename, path, settings)
|
||||
base = os.path.splitext(filename)[0]
|
||||
base = splitext(filename)[0]
|
||||
self.file_path = join(path, base + '.webm')
|
||||
self.dst_path = join(settings['destination'], path, base + '.webm')
|
||||
|
||||
@@ -188,19 +192,17 @@ class Album(UnicodeMixin):
|
||||
self.index_url = os.path.relpath(settings['destination'],
|
||||
self.dst_path) + '/' + self.url_ext
|
||||
|
||||
# sort images and sub-albums by name
|
||||
filenames.sort(**alpha_sort)
|
||||
dirnames.sort(**alpha_sort)
|
||||
|
||||
# sort sub-albums
|
||||
dirnames.sort(key=strxfrm, reverse=settings['albums_sort_reverse'])
|
||||
self.subdirs = dirnames
|
||||
|
||||
#: List of all medias in the album (:class:`~sigal.gallery.Image` and
|
||||
#: :class:`~sigal.gallery.Video`).
|
||||
self.medias = []
|
||||
self.medias = medias = []
|
||||
self.medias_count = defaultdict(int)
|
||||
|
||||
for f in filenames:
|
||||
ext = os.path.splitext(f)[1]
|
||||
ext = splitext(f)[1]
|
||||
if ext in Image.extensions:
|
||||
media = Image(f, self.path, settings)
|
||||
elif ext in Video.extensions:
|
||||
@@ -209,7 +211,16 @@ class Album(UnicodeMixin):
|
||||
continue
|
||||
|
||||
self.medias_count[media.type] += 1
|
||||
self.medias.append(media)
|
||||
medias.append(media)
|
||||
|
||||
# sort images
|
||||
medias_sort_attr = settings['medias_sort_attr']
|
||||
if medias_sort_attr == 'date':
|
||||
key = lambda s: s.date or datetime.now()
|
||||
else:
|
||||
key = lambda s: strxfrm(getattr(s, medias_sort_attr))
|
||||
|
||||
medias.sort(key=key, reverse=settings['medias_sort_reverse'])
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s>(%r)" % (self.__class__.__name__, self.path)
|
||||
@@ -292,7 +303,7 @@ class Album(UnicodeMixin):
|
||||
else:
|
||||
# find and return the first landscape image
|
||||
for f in self.medias:
|
||||
ext = os.path.splitext(f.filename)[1]
|
||||
ext = splitext(f.filename)[1]
|
||||
if ext in Image.extensions:
|
||||
im = PILImage.open(f.src_path)
|
||||
if im.size[0] > im.size[1]:
|
||||
|
||||
@@ -218,8 +218,8 @@ def get_exif_tags(source):
|
||||
try:
|
||||
# Remove null bytes at the end if necessary
|
||||
date = data['DateTimeOriginal'].rsplit('\x00')[0]
|
||||
dt = datetime.strptime(date, '%Y:%m:%d %H:%M:%S')
|
||||
dt = dt.strftime('%A, %d. %B %Y')
|
||||
simple['dateobj'] = datetime.strptime(date, '%Y:%m:%d %H:%M:%S')
|
||||
dt = simple['dateobj'].strftime('%A, %d. %B %Y')
|
||||
|
||||
if compat.PY2:
|
||||
simple['datetime'] = dt.decode('utf8')
|
||||
|
||||
@@ -31,6 +31,7 @@ from .compat import PY2
|
||||
_DEFAULT_CONFIG = {
|
||||
'adjust_options': {'color': 1.0, 'brightness': 1.0,
|
||||
'contrast': 1.0, 'sharpness': 1.0},
|
||||
'albums_sort_reverse': False,
|
||||
'copy_exif_data': True,
|
||||
'copyright': '',
|
||||
'destination': '_build',
|
||||
@@ -44,6 +45,8 @@ _DEFAULT_CONFIG = {
|
||||
'keep_orig': False,
|
||||
'links': '',
|
||||
'locale': '',
|
||||
'medias_sort_attr': 'filename',
|
||||
'medias_sort_reverse': False,
|
||||
'make_thumbs': True,
|
||||
'orig_dir': 'original',
|
||||
'orig_link': False,
|
||||
|
||||
@@ -61,6 +61,16 @@ thumb_size = (280, 210)
|
||||
# Use symbolic links instead of copying the original images
|
||||
# orig_link = False
|
||||
|
||||
# Reverse sort for albums
|
||||
albums_sort_reverse = False
|
||||
|
||||
# Attribute of Media objects which is used to sort medias. 'date' can be used
|
||||
# to sort with EXIF dates.
|
||||
medias_sort_attr = 'filename'
|
||||
|
||||
# Reverse sort for medias
|
||||
medias_sort_reverse = False
|
||||
|
||||
# Jpeg options
|
||||
# jpg_options = {'quality': 85,
|
||||
# 'optimize': True,
|
||||
|
||||
BIN
tests/sample/pictures/dir1/test2/archlinux-kiss-1024x640.png
Normal file
BIN
tests/sample/pictures/dir1/test2/archlinux-kiss-1024x640.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 KiB |
@@ -1,5 +1,6 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import locale
|
||||
import os
|
||||
import pytest
|
||||
|
||||
@@ -31,7 +32,7 @@ REF = {
|
||||
'name': 'test2',
|
||||
'thumbnail': 'test2/thumbnails/21.tn.jpg',
|
||||
'subdirs': [],
|
||||
'medias': ['21.jpg', '22.jpg'],
|
||||
'medias': ['21.jpg', '22.jpg', 'archlinux-kiss-1024x640.png'],
|
||||
},
|
||||
'dir2': {
|
||||
'title': 'Another example gallery with a very long name',
|
||||
@@ -39,9 +40,9 @@ REF = {
|
||||
'thumbnail': 'dir2/thumbnails/m57_the_ring_nebula-587px.tn.jpg',
|
||||
'subdirs': [],
|
||||
'medias': ['exo20101028-b-full.jpg',
|
||||
'm57_the_ring_nebula-587px.jpg',
|
||||
'Hubble Interacting Galaxy NGC 5257.jpg',
|
||||
'Hubble ultra deep field.jpg',
|
||||
'Hubble Interacting Galaxy NGC 5257.jpg'],
|
||||
'm57_the_ring_nebula-587px.jpg'],
|
||||
},
|
||||
u'accentué': {
|
||||
'title': u'Accentué',
|
||||
@@ -118,6 +119,7 @@ def test_video(settings, tmpdir):
|
||||
|
||||
@pytest.mark.parametrize("path,album", REF.items())
|
||||
def test_album(path, album, settings, tmpdir):
|
||||
locale.setlocale(locale.LC_ALL, 'fr_FR')
|
||||
gal = Gallery(settings, ncpu=1)
|
||||
a = Album(path, settings, album['subdirs'], album['medias'], gal)
|
||||
|
||||
@@ -129,7 +131,7 @@ def test_album(path, album, settings, tmpdir):
|
||||
assert len(a) == len(album['medias'])
|
||||
|
||||
|
||||
def test_album_medias(settings, tmpdir):
|
||||
def test_album_medias(settings):
|
||||
gal = Gallery(settings, ncpu=1)
|
||||
|
||||
album = REF['dir1/test1']
|
||||
@@ -143,6 +145,30 @@ def test_album_medias(settings, tmpdir):
|
||||
assert list(a.images) == []
|
||||
|
||||
|
||||
def test_albums_sort(settings):
|
||||
gal = Gallery(settings, ncpu=1)
|
||||
album = REF['dir1']
|
||||
|
||||
settings['albums_sort_reverse'] = True
|
||||
a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
|
||||
assert [im.filename for im in a.images] == list(reversed(album['medias']))
|
||||
|
||||
|
||||
def test_medias_sort(settings):
|
||||
gal = Gallery(settings, ncpu=1)
|
||||
album = REF['dir1/test2']
|
||||
|
||||
settings['medias_sort_reverse'] = True
|
||||
a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal)
|
||||
assert [im.filename for im in a.images] == list(reversed(album['medias']))
|
||||
|
||||
settings['medias_sort_attr'] = 'date'
|
||||
settings['medias_sort_reverse'] = False
|
||||
a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal)
|
||||
assert [im.filename for im in a.images] == ['22.jpg', '21.jpg',
|
||||
'archlinux-kiss-1024x640.png']
|
||||
|
||||
|
||||
def test_gallery(settings, tmpdir):
|
||||
"Test the Gallery class."
|
||||
|
||||
|
||||
Reference in New Issue
Block a user