3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,8 +3,9 @@
|
||||
*.pyc
|
||||
*_flymake
|
||||
.coverage
|
||||
.sass-cache/
|
||||
.ropeproject/
|
||||
.sass-cache/
|
||||
.tox/
|
||||
nose.cfg
|
||||
MANIFEST
|
||||
_build/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "2.6"
|
||||
- "3.3"
|
||||
before_install:
|
||||
# Dependencies to build PIL
|
||||
- sudo apt-get update -qq
|
||||
|
||||
@@ -18,7 +18,7 @@ The idea behind Sigal is to ease the use of the javascript librairies like
|
||||
`galleria`_. These librairies do a great job to display the images, Sigal does
|
||||
what is missing: resize images, create thumbnails, generate html pages.
|
||||
|
||||
Sigal is currently compatible only with Python 2.
|
||||
Sigal is compatible with Python 2.7 and 3.3.
|
||||
|
||||
Links :
|
||||
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
Changelog
|
||||
===========
|
||||
|
||||
Version 0.6.dev
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Released on 2013-xx-xx.
|
||||
|
||||
- Add support for Python 3.3
|
||||
|
||||
Version 0.5.1
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
10
setup.py
10
setup.py
@@ -22,8 +22,10 @@ with open('docs/changelog.rst') as f:
|
||||
|
||||
# Load package meta from the pkgmeta module without loading the package.
|
||||
pkgmeta = {}
|
||||
execfile(os.path.join(os.path.dirname(__file__), 'sigal', 'pkgmeta.py'),
|
||||
pkgmeta)
|
||||
pkgmeta_file = os.path.join(os.path.dirname(__file__), 'sigal', 'pkgmeta.py')
|
||||
with open(pkgmeta_file) as f:
|
||||
code = compile(f.read(), 'pkgmeta.py', 'exec')
|
||||
exec(code, pkgmeta)
|
||||
|
||||
setup(
|
||||
name='sigal',
|
||||
@@ -46,8 +48,10 @@ setup(
|
||||
'Environment :: Console',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Multimedia :: Graphics :: Viewers',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
|
||||
@@ -30,9 +30,9 @@ sigal is yet another python script to prepare a static gallery of images:
|
||||
* generate html pages.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import codecs
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
@@ -72,9 +72,9 @@ def init():
|
||||
from pkg_resources import resource_string
|
||||
conf = resource_string(__name__, 'templates/sigal.conf.py')
|
||||
|
||||
with codecs.open('sigal.conf.py', 'w', 'utf-8') as f:
|
||||
with io.open('sigal.conf.py', 'w', 'utf-8') as f:
|
||||
f.write(conf)
|
||||
print "Sample config file created: sigal.conf.py"
|
||||
print("Sample config file created: sigal.conf.py")
|
||||
|
||||
|
||||
@arg('source', nargs='?', help='Input directory')
|
||||
@@ -97,7 +97,7 @@ def build(source, destination, debug=False, verbose=False, force=False,
|
||||
|
||||
settings_file = config or _DEFAULT_CONFIG_FILE
|
||||
if not os.path.isfile(settings_file):
|
||||
logger.error("Settings file not found (%s)", settings_file)
|
||||
logger.error("Settings file not found: %s", settings_file)
|
||||
sys.exit(1)
|
||||
settings = read_settings(settings_file)
|
||||
|
||||
@@ -108,8 +108,7 @@ def build(source, destination, debug=False, verbose=False, force=False,
|
||||
|
||||
logger.info("Input : %s", settings['source'])
|
||||
if not settings['source'] or not os.path.isdir(settings['source']):
|
||||
logger.error("Input directory '%s' does not exist.",
|
||||
settings['source'])
|
||||
logger.error("Input directory not found: %s", settings['source'])
|
||||
sys.exit(1)
|
||||
|
||||
logger.info("Output : %s", settings['destination'])
|
||||
@@ -138,7 +137,7 @@ def serve(path):
|
||||
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
|
||||
httpd = SocketServer.TCPServer(("", PORT), Handler, False)
|
||||
|
||||
print " * Running on http://127.0.0.1:%i/" % PORT
|
||||
print(" * Running on http://127.0.0.1:{}/".format(PORT))
|
||||
|
||||
try:
|
||||
httpd.allow_reuse_address = True
|
||||
@@ -146,13 +145,14 @@ def serve(path):
|
||||
httpd.server_activate()
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print '\nAll done!'
|
||||
print('\nAll done!')
|
||||
else:
|
||||
sys.stderr.write("The '%s' directory doesn't exist.\n" % path)
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArghParser(description='Simple static gallery generator.',
|
||||
version=__version__)
|
||||
parser = ArghParser(description='Simple static gallery generator.')
|
||||
parser.add_commands([init, build, serve])
|
||||
parser.add_argument('--version', action='version',
|
||||
version='%(prog)s {}'.format(__version__))
|
||||
parser.dispatch()
|
||||
|
||||
14
sigal/compat.py
Normal file
14
sigal/compat.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
|
||||
if not PY2:
|
||||
text_type = str
|
||||
string_types = (str,)
|
||||
unichr = chr
|
||||
else:
|
||||
text_type = unicode # NOQA
|
||||
string_types = (str, unicode) # NOQA
|
||||
unichr = unichr
|
||||
@@ -38,9 +38,13 @@ from PIL import Image as PILImage
|
||||
|
||||
import sigal.image
|
||||
import sigal.video
|
||||
from . import compat
|
||||
from .settings import get_thumb
|
||||
from .writer import Writer
|
||||
|
||||
if not compat.PY2:
|
||||
from functools import reduce
|
||||
|
||||
DESCRIPTION_FILE = "index.md"
|
||||
|
||||
# Label with for the progress bar. The max value is 48 character = 80 - 32 for
|
||||
@@ -69,7 +73,7 @@ class PathsDb(object):
|
||||
# basepath must to be a unicode string so that os.walk will return
|
||||
# unicode dirnames and filenames. If basepath is a str, we must
|
||||
# convert it to unicode.
|
||||
if isinstance(path, str):
|
||||
if compat.PY2 and isinstance(path, str):
|
||||
enc = locale.getpreferredencoding()
|
||||
self.basepath = path.decode(enc)
|
||||
else:
|
||||
@@ -96,12 +100,18 @@ class PathsDb(object):
|
||||
}
|
||||
|
||||
# get information for each directory
|
||||
for path, dirnames, filenames in os.walk(self.basepath, followlinks=True):
|
||||
for path, dirnames, filenames in os.walk(self.basepath,
|
||||
followlinks=True):
|
||||
relpath = os.path.relpath(path, self.basepath)
|
||||
|
||||
# sort images and sub-albums by name
|
||||
filenames.sort(cmp=locale.strcoll)
|
||||
dirnames.sort(cmp=locale.strcoll)
|
||||
if compat.PY2:
|
||||
filenames.sort(cmp=locale.strcoll)
|
||||
dirnames.sort(cmp=locale.strcoll)
|
||||
else:
|
||||
from functools import cmp_to_key
|
||||
filenames.sort(key=cmp_to_key(locale.strcoll))
|
||||
dirnames.sort(key=cmp_to_key(locale.strcoll))
|
||||
|
||||
self.db['paths_list'].append(relpath)
|
||||
self.db[relpath] = {
|
||||
|
||||
@@ -40,6 +40,8 @@ from pilkit.processors import Transpose, Adjust
|
||||
from pilkit.utils import save_image
|
||||
from datetime import datetime
|
||||
|
||||
from . import compat
|
||||
|
||||
|
||||
def _has_exif_tags(img):
|
||||
return hasattr(img, 'info') and 'exif' in img.info
|
||||
@@ -91,8 +93,7 @@ def generate_image(source, outname, settings, options=None):
|
||||
|
||||
outformat = img.format or original_format or 'JPEG'
|
||||
logger.debug(u'Save resized image to {0} ({1})'.format(outname, outformat))
|
||||
with open(outname, 'w') as fp:
|
||||
save_image(img, fp, outformat, options=options, autoconvert=True)
|
||||
save_image(img, outname, outformat, options=options, autoconvert=True)
|
||||
|
||||
|
||||
def generate_thumbnail(source, outname, box, fit=True, options=None):
|
||||
@@ -109,8 +110,7 @@ def generate_thumbnail(source, outname, box, fit=True, options=None):
|
||||
|
||||
outformat = img.format or original_format or 'JPEG'
|
||||
logger.debug(u'Save thumnail image: {0} ({1})'.format(outname, outformat))
|
||||
with open(outname, 'w') as fp:
|
||||
save_image(img, fp, outformat, options=options, autoconvert=True)
|
||||
save_image(img, outname, outformat, options=options, autoconvert=True)
|
||||
|
||||
|
||||
def add_copyright(img, text):
|
||||
@@ -185,7 +185,12 @@ def get_exif_tags(source):
|
||||
# Remove null bytes at the end if necessary
|
||||
date = data['DateTimeOriginal'].rsplit('\x00')[0]
|
||||
dt = datetime.strptime(date, '%Y:%m:%d %H:%M:%S')
|
||||
simple['datetime'] = dt
|
||||
dt = dt.strftime('%A, %d. %B %Y')
|
||||
|
||||
if compat.PY2:
|
||||
simple['datetime'] = dt.decode('utf8')
|
||||
else:
|
||||
simple['datetime'] = dt
|
||||
except (ValueError, TypeError) as e:
|
||||
msg = u'Could not parse DateTimeOriginal of %s: %s' % (source, e)
|
||||
logger.warning(msg)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
__title__ = 'sigal'
|
||||
__author__ = u"Simon Conseil"
|
||||
__version__ = "0.5.1"
|
||||
__license__ = "MIT"
|
||||
__author__ = 'Simon Conseil'
|
||||
__version__ = '0.6.0-dev'
|
||||
__license__ = 'MIT'
|
||||
__url__ = 'https://github.com/saimn/sigal'
|
||||
__all__ = ['__title__', '__author__', '__version__', '__license__', '__url__']
|
||||
|
||||
@@ -60,6 +60,7 @@ def get_thumb(settings, filename):
|
||||
"""Return the path to the thumb.
|
||||
|
||||
examples:
|
||||
>>> default_settings = create_settings()
|
||||
>>> get_thumb(default_settings, "bar/foo.jpg")
|
||||
"bar/thumbnails/foo.jpg"
|
||||
>>> get_thumb(default_settings, "bar/foo.png")
|
||||
@@ -96,8 +97,12 @@ def read_settings(filename=None):
|
||||
if filename:
|
||||
logger.debug("Settings file: %s", filename)
|
||||
tempdict = {}
|
||||
execfile(filename, tempdict)
|
||||
settings.update((k, v) for k, v in tempdict.iteritems()
|
||||
|
||||
with open(filename) as f:
|
||||
code = compile(f.read(), filename, 'exec')
|
||||
exec(code, tempdict)
|
||||
|
||||
settings.update((k, v) for k, v in tempdict.items()
|
||||
if k not in ['__builtins__'])
|
||||
|
||||
# Make the paths relative to the settings file
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
{% if media.big %} data-big="{{ media.big }}"{% endif %}
|
||||
{% if media.exif %}
|
||||
{% if media.exif.datetime %}
|
||||
data-date=", {{ media.exif.datetime.strftime('%d %B %Y') }}"
|
||||
data-date=", {{ media.exif.datetime }}"
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
{% if media.exif.exposure %}Exposure: {{ media.exif.exposure }}, {% endif %}
|
||||
{% if media.exif.fstop %}Fstop: {{ media.exif.fstop }}{% endif %}
|
||||
{% if media.exif.datetime %}
|
||||
<br>Date: {{ media.exif.datetime.strftime('%A, %d. %B %Y') }}
|
||||
<br>Date: {{ media.exif.datetime }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
@@ -27,6 +27,8 @@ import re
|
||||
import shutil
|
||||
import sigal.image
|
||||
|
||||
from . import compat
|
||||
|
||||
|
||||
def vid_size(source):
|
||||
"""Returns the dimensions of the video"""
|
||||
@@ -35,6 +37,10 @@ def vid_size(source):
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if not compat.PY2:
|
||||
stderr = stderr.decode('utf8')
|
||||
|
||||
match = pattern.search(stderr)
|
||||
if match:
|
||||
x, y = int(match.groups()[0]), int(match.groups()[1])
|
||||
|
||||
Reference in New Issue
Block a user